/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "OutdoorPvPNA.h"
#include "AreaDefines.h"
#include "CreatureScript.h"
#include "GameGraveyard.h"
#include "GridNotifiers.h"
#include "Language.h"
#include "MapMgr.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
#include "OutdoorPvPScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "World.h"
#include "WorldPacket.h"
#include "WorldSessionMgr.h"
#include "WorldStateDefines.h"
#include "WorldStatePackets.h"
OutdoorPvPNA::OutdoorPvPNA()
{
_typeId = OUTDOOR_PVP_NA;
m_obj = nullptr;
}
// SpawnIds from creatures
HalaaNPCS halaaNPCHorde;
HalaaNPCS halaaNPCAlly;
void OutdoorPvPNA::HandleKill(Player* killer, Unit* killed)
{
if (Group* group = killer->GetGroup())
{
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{
Player* groupGuy = itr->GetSource();
if (!groupGuy)
continue;
// skip if too far away
if (!groupGuy->IsAtGroupRewardDistance(killed) && killer != groupGuy)
continue;
// creature kills must be notified, even if not inside objective / not outdoor pvp active
// player kills only count if active and inside objective
if ((groupGuy->IsOutdoorPvPActive() && groupGuy->GetAreaId() == AREA_HALAA) || killed->IsCreature())
{
HandleKillImpl(groupGuy, killed);
}
}
}
else
{
// creature kills must be notified, even if not inside objective / not outdoor pvp active
if (killer && ((killer->IsOutdoorPvPActive() && killer->ToPlayer()->GetAreaId() == AREA_HALAA) || killed->IsCreature()))
{
HandleKillImpl(killer, killed);
}
}
}
void OutdoorPvPNA::HandleKillImpl(Player* player, Unit* killed)
{
if (killed->IsPlayer() && player->GetTeamId() != killed->ToPlayer()->GetTeamId())
{
player->KilledMonsterCredit(NA_CREDIT_MARKER);
player->CastSpell(player, player->GetTeamId() == TEAM_ALLIANCE ? NA_KILL_TOKEN_ALLIANCE : NA_KILL_TOKEN_HORDE, true);
}
}
void UpdateCreatureHalaa(ObjectGuid::LowType spawnId, Map* map, float x, float y)
{
CreatureData& data = sObjectMgr->NewOrExistCreatureData(spawnId);
sObjectMgr->AddCreatureToGrid(spawnId, &data);
// Spawn if necessary (loaded grids only)
if (!map->Instanceable() && map->IsGridLoaded(x, y))
{
Creature* creature = new Creature();
if (!creature->LoadCreatureFromDB(spawnId, map, true, true))
{
LOG_ERROR("sql.sql", "AddCreature: Cannot add creature spawnId {} to map", spawnId);
delete creature;
return;
}
}
}
uint32 OPvPCapturePointNA::GetAliveGuardsCount()
{
uint32 count = 0;
for (auto itr = _creatures.begin(); itr != _creatures.end(); ++itr)
{
auto bounds = _pvp->GetMap()->GetCreatureBySpawnIdStore().equal_range(itr->second);
for (auto itr2 = bounds.first; itr2 != bounds.second; ++itr2)
if (itr2->second->IsAlive() && (itr2->second->GetEntry() == NA_HALAANI_GUARD_A || itr2->second->GetEntry() == NA_HALAANI_GUARD_H))
++count;
}
return count;
}
TeamId OPvPCapturePointNA::GetControllingFaction() const
{
return m_ControllingFaction;
}
void OPvPCapturePointNA::DespawnCreatures(HalaaNPCS teamNPC)
{
for (int i = 0; i < NA_HALAA_CREATURE_TEAM_SPAWN; i++)
{
ObjectGuid::LowType spawnId = teamNPC[i];
auto bounds = _pvp->GetMap()->GetCreatureBySpawnIdStore().equal_range(spawnId);
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
for (auto itr = bounds.first; itr != bounds.second;)
{
// can happen when closing the core
Creature* c = itr->second;
if (c)
{
++itr;
c->AddObjectToRemoveList();
sObjectMgr->RemoveCreatureFromGrid(spawnId, data);
_creatures[i] = 0;
_creatureTypes[_creatures[i]] = 0;
}
}
}
}
void OPvPCapturePointNA::SpawnNPCsForTeam(HalaaNPCS teamNPC)
{
for (int i = 0; i < NA_HALAA_CREATURE_TEAM_SPAWN; i++)
{
ObjectGuid::LowType spawnId = teamNPC[i];
const CreatureData* data = sObjectMgr->GetCreatureData(spawnId);
if (data)
{
UpdateCreatureHalaa(spawnId, _pvp->GetMap(), data->posX, data->posY);
_creatures[i] = spawnId;
_creatureTypes[_creatures[i]] = i;
}
}
}
void OPvPCapturePointNA::SpawnGOsForTeam(TeamId teamId)
{
const go_type* gos = nullptr;
if (teamId == TEAM_ALLIANCE)
gos = AllianceControlGOs;
else if (teamId == TEAM_HORDE)
gos = HordeControlGOs;
else
return;
for (int i = 0; i < NA_CONTROL_GO_NUM; ++i)
{
if (i == NA_ROOST_S ||
i == NA_ROOST_W ||
i == NA_ROOST_N ||
i == NA_ROOST_E ||
i == NA_BOMB_WAGON_S ||
i == NA_BOMB_WAGON_W ||
i == NA_BOMB_WAGON_N ||
i == NA_BOMB_WAGON_E)
continue; // roosts and bomb wagons are spawned when someone uses the matching destroyed roost
AddObject(i, gos[i].entry, gos[i].map, gos[i].x, gos[i].y, gos[i].z, gos[i].o, gos[i].rot0, gos[i].rot1, gos[i].rot2, gos[i].rot3);
}
}
void OPvPCapturePointNA::DespawnGOs()
{
for (int i = 0; i < NA_CONTROL_GO_NUM; ++i)
{
DelObject(i);
}
}
void OPvPCapturePointNA::FactionTakeOver(TeamId teamId)
{
if (m_ControllingFaction != TEAM_NEUTRAL)
sGraveyard->RemoveGraveyardLink(NA_HALAA_GRAVEYARD, NA_HALAA_GRAVEYARD_ZONE, m_ControllingFaction, false);
if (m_ControllingFaction == TEAM_ALLIANCE)
_pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_A).c_str());
else if (m_ControllingFaction == TEAM_HORDE)
_pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_H).c_str());
DespawnCreatures(GetControllingFaction() == TEAM_HORDE ? halaaNPCHorde : halaaNPCAlly);
m_ControllingFaction = teamId;
if (m_ControllingFaction != TEAM_NEUTRAL)
sGraveyard->AddGraveyardLink(NA_HALAA_GRAVEYARD, NA_HALAA_GRAVEYARD_ZONE, m_ControllingFaction, false);
DespawnGOs();
SpawnGOsForTeam(teamId);
SpawnNPCsForTeam(GetControllingFaction() == TEAM_HORDE ? halaaNPCHorde : halaaNPCAlly);
m_GuardsAlive = NA_GUARDS_MAX;
m_capturable = false;
m_canRecap = false;
this->UpdateHalaaWorldState();
if (teamId == TEAM_ALLIANCE)
{
m_WyvernStateSouth = WYVERN_NEU_HORDE;
m_WyvernStateNorth = WYVERN_NEU_HORDE;
m_WyvernStateEast = WYVERN_NEU_HORDE;
m_WyvernStateWest = WYVERN_NEU_HORDE;
_pvp->TeamApplyBuff(TEAM_ALLIANCE, NA_CAPTURE_BUFF);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 0);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 1);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive);
_pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_A).c_str());
}
else
{
m_WyvernStateSouth = WYVERN_NEU_ALLIANCE;
m_WyvernStateNorth = WYVERN_NEU_ALLIANCE;
m_WyvernStateEast = WYVERN_NEU_ALLIANCE;
m_WyvernStateWest = WYVERN_NEU_ALLIANCE;
_pvp->TeamApplyBuff(TEAM_HORDE, NA_CAPTURE_BUFF);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 1);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 0);
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive);
_pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_H).c_str());
}
UpdateWyvernRoostWorldState(NA_ROOST_S);
UpdateWyvernRoostWorldState(NA_ROOST_N);
UpdateWyvernRoostWorldState(NA_ROOST_W);
UpdateWyvernRoostWorldState(NA_ROOST_E);
}
bool OPvPCapturePointNA::HandlePlayerEnter(Player* player)
{
if (OPvPCapturePoint::HandlePlayerEnter(player))
{
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_DISPLAY, 1);
uint32 phase = (uint32)ceil((_value + _maxValue) / (2 * _maxValue) * 100.0f);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_POS, phase);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_SLIDER_N, _neutralValuePct);
return true;
}
return false;
}
void OPvPCapturePointNA::HandlePlayerLeave(Player* player)
{
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_DISPLAY, 0);
OPvPCapturePoint::HandlePlayerLeave(player);
}
OPvPCapturePointNA::OPvPCapturePointNA(OutdoorPvP* pvp) :
OPvPCapturePoint(pvp), m_capturable(true), m_GuardsAlive(0), m_ControllingFaction(TEAM_NEUTRAL),
m_WyvernStateNorth(0), m_WyvernStateSouth(0), m_WyvernStateEast(0), m_WyvernStateWest(0),
m_HalaaState(HALAA_N), m_RespawnTimer(NA_RESPAWN_TIME), m_GuardCheckTimer(NA_GUARD_CHECK_TIME), m_canRecap(true)
{
SetCapturePointData(182210, MAP_OUTLAND, -1572.57f, 7945.3f, -22.475f, 2.05949f, 0.0f, 0.0f, 0.857167f, 0.515038f);
}
bool OutdoorPvPNA::SetupOutdoorPvP()
{
// _typeId = OUTDOOR_PVP_NA; _MUST_ be set in ctor, because of spawns cleanup
// add the zones affected by the pvp buff
RegisterZone(NA_BUFF_ZONE);
SetMapFromZone(NA_BUFF_ZONE);
// halaa
m_obj = new OPvPCapturePointNA(this);
if (!m_obj)
return false;
AddCapturePoint(m_obj);
//Remove linked graveyard at the server start to avoid players spawning in halaa
sGraveyard->RemoveGraveyardLink(NA_HALAA_GRAVEYARD, NA_HALAA_GRAVEYARD_ZONE, TEAM_ALLIANCE, false);
sGraveyard->RemoveGraveyardLink(NA_HALAA_GRAVEYARD, NA_HALAA_GRAVEYARD_ZONE, TEAM_HORDE, false);
return true;
}
void OutdoorPvPNA::HandlePlayerEnterZone(Player* player, uint32 zone)
{
// add buffs
if (player->GetTeamId() == m_obj->GetControllingFaction())
player->CastSpell(player, NA_CAPTURE_BUFF, true);
OutdoorPvP::HandlePlayerEnterZone(player, zone);
}
void OutdoorPvPNA::HandlePlayerLeaveZone(Player* player, uint32 zone)
{
// remove buffs
player->RemoveAurasDueToSpell(NA_CAPTURE_BUFF);
OutdoorPvP::HandlePlayerLeaveZone(player, zone);
}
void OutdoorPvPNA::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
{
m_obj->FillInitialWorldStates(packet);
}
void OPvPCapturePointNA::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
{
packet.Worldstates.reserve(25);
if (m_ControllingFaction == TEAM_ALLIANCE)
{
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 1);
}
else if (m_ControllingFaction == TEAM_HORDE)
{
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 1);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 0);
}
else
{
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 0);
}
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_GUARDS_MAX, NA_GUARDS_MAX);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_H, (m_WyvernStateNorth & WYVERN_NEU_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_A, (m_WyvernStateNorth & WYVERN_NEU_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_H, (m_WyvernStateNorth & WYVERN_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_A, (m_WyvernStateNorth & WYVERN_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_H, (m_WyvernStateSouth & WYVERN_NEU_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_A, (m_WyvernStateSouth & WYVERN_NEU_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_H, (m_WyvernStateSouth & WYVERN_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_A, (m_WyvernStateSouth & WYVERN_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_H, (m_WyvernStateWest & WYVERN_NEU_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_A, (m_WyvernStateWest & WYVERN_NEU_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_H, (m_WyvernStateWest & WYVERN_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_A, (m_WyvernStateWest & WYVERN_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_H, (m_WyvernStateEast & WYVERN_NEU_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_A, (m_WyvernStateEast & WYVERN_NEU_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_H, (m_WyvernStateEast & WYVERN_HORDE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_A, (m_WyvernStateEast & WYVERN_ALLIANCE) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_HALAA_NEUTRAL, (m_HalaaState & HALAA_N) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_A, (m_HalaaState & HALAA_N_A) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_H, (m_HalaaState & HALAA_N_H) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_HALAA_HORDE, (m_HalaaState & HALAA_H) != 0 ? 1 : 0);
packet.Worldstates.emplace_back(WORLD_STATE_OPVP_NA_MAP_HALAA_ALLIANCE, (m_HalaaState & HALAA_A) != 0 ? 1 : 0);
}
void OutdoorPvPNA::SendRemoveWorldStates(Player* player)
{
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_MAX, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_DISPLAY, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_POS, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_SLIDER_N, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEUTRAL, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_A, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_H, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_HORDE, 0);
player->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_ALLIANCE, 0);
}
bool OutdoorPvPNA::Update(uint32 diff)
{
return m_obj->Update(diff);
}
void FlagPlayerPvP(Player* player)
{
player->SetPlayerFlag(PLAYER_FLAGS_IN_PVP);
player->UpdatePvP(true, true);
}
bool OPvPCapturePointNA::HandleCustomSpell(Player* player, uint32 spellId, GameObject* /*go*/)
{
std::vector nodes;
nodes.resize(2);
bool retval = false;
switch (spellId)
{
case NA_SPELL_FLY_NORTH:
nodes[0] = FlightPathStartNodes[NA_ROOST_N];
nodes[1] = FlightPathEndNodes[NA_ROOST_N];
player->ActivateTaxiPathTo(nodes);
FlagPlayerPvP(player);
retval = true;
break;
case NA_SPELL_FLY_SOUTH:
nodes[0] = FlightPathStartNodes[NA_ROOST_S];
nodes[1] = FlightPathEndNodes[NA_ROOST_S];
player->ActivateTaxiPathTo(nodes);
FlagPlayerPvP(player);
retval = true;
break;
case NA_SPELL_FLY_WEST:
nodes[0] = FlightPathStartNodes[NA_ROOST_W];
nodes[1] = FlightPathEndNodes[NA_ROOST_W];
player->ActivateTaxiPathTo(nodes);
FlagPlayerPvP(player);
retval = true;
break;
case NA_SPELL_FLY_EAST:
nodes[0] = FlightPathStartNodes[NA_ROOST_E];
nodes[1] = FlightPathEndNodes[NA_ROOST_E];
player->ActivateTaxiPathTo(nodes);
FlagPlayerPvP(player);
retval = true;
break;
default:
break;
}
if (retval)
{
//Adding items
uint32 noSpaceForCount = 0;
// check space and find places
ItemPosCountVec dest;
int32 count = 10;
// bomb id count
InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, NA_HALAA_BOMB, count, &noSpaceForCount);
if (msg != EQUIP_ERR_OK) // convert to possible store amount
count -= noSpaceForCount;
if (count == 0 || dest.empty()) // can't add any
{
return true;
}
Item* item = player->StoreNewItem(dest, NA_HALAA_BOMB, true);
if (count > 0 && item)
{
player->SendNewItem(item, count, true, false);
}
return true;
}
return false;
}
int32 OPvPCapturePointNA::HandleOpenGo(Player* player, GameObject* go)
{
int32 retval = OPvPCapturePoint::HandleOpenGo(player, go);
if (retval >= 0)
{
const go_type* gos = nullptr;
if (m_ControllingFaction == TEAM_ALLIANCE)
gos = AllianceControlGOs;
else if (m_ControllingFaction == TEAM_HORDE)
gos = HordeControlGOs;
else
return -1;
int32 del = -1;
int32 del2 = -1;
int32 add = -1;
int32 add2 = -1;
switch (retval)
{
case NA_DESTROYED_ROOST_S:
del = NA_DESTROYED_ROOST_S;
add = NA_ROOST_S;
add2 = NA_BOMB_WAGON_S;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateSouth = WYVERN_ALLIANCE;
else
m_WyvernStateSouth = WYVERN_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_S);
FlagPlayerPvP(player);
break;
case NA_DESTROYED_ROOST_N:
del = NA_DESTROYED_ROOST_N;
add = NA_ROOST_N;
add2 = NA_BOMB_WAGON_N;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateNorth = WYVERN_ALLIANCE;
else
m_WyvernStateNorth = WYVERN_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_N);
FlagPlayerPvP(player);
break;
case NA_DESTROYED_ROOST_W:
del = NA_DESTROYED_ROOST_W;
add = NA_ROOST_W;
add2 = NA_BOMB_WAGON_W;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateWest = WYVERN_ALLIANCE;
else
m_WyvernStateWest = WYVERN_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_W);
FlagPlayerPvP(player);
break;
case NA_DESTROYED_ROOST_E:
del = NA_DESTROYED_ROOST_E;
add = NA_ROOST_E;
add2 = NA_BOMB_WAGON_E;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateEast = WYVERN_ALLIANCE;
else
m_WyvernStateEast = WYVERN_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_E);
FlagPlayerPvP(player);
break;
case NA_BOMB_WAGON_S:
del = NA_BOMB_WAGON_S;
del2 = NA_ROOST_S;
add = NA_DESTROYED_ROOST_S;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateSouth = WYVERN_NEU_ALLIANCE;
else
m_WyvernStateSouth = WYVERN_NEU_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_S);
FlagPlayerPvP(player);
break;
case NA_BOMB_WAGON_N:
del = NA_BOMB_WAGON_N;
del2 = NA_ROOST_N;
add = NA_DESTROYED_ROOST_N;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateNorth = WYVERN_NEU_ALLIANCE;
else
m_WyvernStateNorth = WYVERN_NEU_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_N);
FlagPlayerPvP(player);
break;
case NA_BOMB_WAGON_W:
del = NA_BOMB_WAGON_W;
del2 = NA_ROOST_W;
add = NA_DESTROYED_ROOST_W;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateWest = WYVERN_NEU_ALLIANCE;
else
m_WyvernStateWest = WYVERN_NEU_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_W);
FlagPlayerPvP(player);
break;
case NA_BOMB_WAGON_E:
del = NA_BOMB_WAGON_E;
del2 = NA_ROOST_E;
add = NA_DESTROYED_ROOST_E;
if (m_ControllingFaction == TEAM_HORDE)
m_WyvernStateEast = WYVERN_NEU_ALLIANCE;
else
m_WyvernStateEast = WYVERN_NEU_HORDE;
UpdateWyvernRoostWorldState(NA_ROOST_E);
FlagPlayerPvP(player);
break;
default:
return -1;
break;
}
if (del > -1)
DelObject(del);
if (del2 > -1)
DelObject(del2);
if (add > -1)
AddObject(add, gos[add].entry, gos[add].map, gos[add].x, gos[add].y, gos[add].z, gos[add].o, gos[add].rot0, gos[add].rot1, gos[add].rot2, gos[add].rot3);
if (add2 > -1)
AddObject(add2, gos[add2].entry, gos[add2].map, gos[add2].x, gos[add2].y, gos[add2].z, gos[add2].o, gos[add2].rot0, gos[add2].rot1, gos[add2].rot2, gos[add2].rot3);
return retval;
}
return -1;
}
bool OPvPCapturePointNA::Update(uint32 diff)
{
if (!_capturePoint)
return false;
float radius = ((float)_capturePoint->GetGOInfo()->capturePoint.radius);
for (PlayerSet playerSet : _activePlayers)
{
for (ObjectGuid playerGuid : playerSet)
{
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
if (!_capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
HandlePlayerLeave(player);
}
}
std::list players;
Acore::AnyPlayerInObjectRangeCheck checker(_capturePoint, radius);
Acore::PlayerListSearcher searcher(_capturePoint, players, checker);
Cell::VisitObjects(_capturePoint, searcher, radius);
for (Player* player : players)
{
if (player->IsOutdoorPvPActive())
{
if (_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second)
HandlePlayerEnter(player);
}
}
if (m_GuardCheckTimer < diff)
{
m_GuardCheckTimer = NA_GUARD_CHECK_TIME;
uint32 cnt = GetAliveGuardsCount();
if (cnt != m_GuardsAlive)
{
m_GuardsAlive = cnt;
if (m_GuardsAlive == 0)
{
m_capturable = true;
m_RespawnTimer = NA_RESPAWN_TIME;
_pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_DEFENSELESS).c_str());
}
else
m_capturable = false;
// update the guard count for the players in zone
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive);
}
}
else m_GuardCheckTimer -= diff;
if (m_capturable)
{
if (m_RespawnTimer < diff)
{
// if the guards have been killed, then the challenger has one hour to take over halaa.
// in case they fail to do it, the guards are respawned, and they have to start again.
if (GetControllingFaction() == TEAM_ALLIANCE)
{
_state = OBJECTIVESTATE_ALLIANCE;
_value = _maxValue;
}
else
{
_state = OBJECTIVESTATE_HORDE;
_value = -_maxValue;
}
// we reset again the artkit, map icons, sliders and respawn Halaa for controller team
SendChangePhase();
ChangeState();
FactionTakeOver(GetControllingFaction());
return true;
}
else if (GetControllingFaction() != TEAM_NEUTRAL) // Don't decrease the respawn timer if the team is not HORDE or ALLIANCE
m_RespawnTimer -= diff;
// get the difference of numbers
float factDiff = ((float)_activePlayers[0].size() - (float)_activePlayers[1].size()) * diff / OUTDOORPVP_OBJECTIVE_UPDATE_INTERVAL;
if (!factDiff)
return false;
float maxDiff = _maxSpeed * diff;
if (factDiff < 0)
{
// horde is in majority, but it's already horde-controlled -> no change
if (_state == OBJECTIVESTATE_HORDE && _value <= -_maxValue)
return false;
if (factDiff < -maxDiff)
factDiff = -maxDiff;
}
else
{
// ally is in majority, but it's already ally-controlled -> no change
if (_state == OBJECTIVESTATE_ALLIANCE && _value >= _maxValue)
return false;
if (factDiff > maxDiff)
factDiff = maxDiff;
}
float oldValue = _value;
TeamId oldTeam = _team;
_oldState = _state;
_value += factDiff;
if (_value < -_minValue) // red
{
if (_value < -_maxValue) //check if the m_value is lower than max, that means horde capped point
{
_value = -_maxValue;
_state = OBJECTIVESTATE_HORDE;
_team = TEAM_HORDE;
}
else //then point is still in battle between teams
{
if (_oldState == OBJECTIVESTATE_NEUTRAL || _oldState == OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE || _oldState == OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE)
{
_state = OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE;
}
else
{
_state = OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE;
}
}
if (GetControllingFaction() == TEAM_ALLIANCE && !m_canRecap)
{
//When the point goes through neutral, the same faction can recapture again to respawn the guards, still need check blizzlike
m_canRecap = true;
DespawnGOs();
DespawnCreatures(GetControllingFaction() == TEAM_HORDE ? halaaNPCHorde : halaaNPCAlly);
}
}
else //blue
{
if (_value > _maxValue) //check if the m_value is bigger than max, that means alliance capped point
{
_value = _maxValue;
_state = OBJECTIVESTATE_ALLIANCE;
_team = TEAM_ALLIANCE;
}
else //then point is still in battle between teams
{
if (_oldState == OBJECTIVESTATE_NEUTRAL || _oldState == OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE || _oldState == OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE)
{
_state = OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE;
}
else
{
_state = OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE;
}
}
if (GetControllingFaction() == TEAM_HORDE && !m_canRecap)
{
//When the point goes through neutral, the same faction can recapture again to respawn the guards, still need check blizzlike
m_canRecap = true;
DespawnGOs();
DespawnCreatures(GetControllingFaction() == TEAM_HORDE ? halaaNPCHorde : halaaNPCAlly);
}
}
if (_value != oldValue)
{
SendChangePhase();
}
if (_oldState != _state)
{
if (oldTeam != _team)
{
ChangeTeam(oldTeam);
}
ChangeState();
return true;
}
}
else
SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_DISPLAY, 0); //Point is not capturable so we hide the slider
return false;
}
void OPvPCapturePointNA::ChangeState()
{
uint32 artkit = 21;
switch (_state)
{
case OBJECTIVESTATE_NEUTRAL:
m_HalaaState = HALAA_N;
break;
case OBJECTIVESTATE_ALLIANCE:
m_HalaaState = HALAA_A;
if (m_canRecap)
FactionTakeOver(TEAM_ALLIANCE);
artkit = 2;
break;
case OBJECTIVESTATE_HORDE:
m_HalaaState = HALAA_H;
if (m_canRecap)
FactionTakeOver(TEAM_HORDE);
artkit = 1;
break;
case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
m_HalaaState = HALAA_N_A;
break;
case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
m_HalaaState = HALAA_N_H;
break;
case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
m_HalaaState = HALAA_N_A;
artkit = 2;
break;
case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
m_HalaaState = HALAA_N_H;
artkit = 1;
break;
}
auto bounds = sMapMgr->FindMap(MAP_OUTLAND, 0)->GetGameObjectBySpawnIdStore().equal_range(m_capturePointSpawnId);
for (auto itr = bounds.first; itr != bounds.second; ++itr)
itr->second->SetGoArtKit(artkit);
UpdateHalaaWorldState();
}
void OPvPCapturePointNA::SendChangePhase()
{
// send this too, sometimes the slider disappears, dunno why :(
SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_DISPLAY, 1);
// send these updates to only the ones in this objective
uint32 phase = (uint32)ceil((_value + _maxValue) / (2 * _maxValue) * 100.0f);
SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_TOWER_SLIDER_POS, phase);
SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_SLIDER_N, _neutralValuePct);
}
void OPvPCapturePointNA::UpdateHalaaWorldState()
{
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEUTRAL, uint32(bool(m_HalaaState & HALAA_N)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_A, uint32(bool(m_HalaaState & HALAA_N_A)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_NEU_H, uint32(bool(m_HalaaState & HALAA_N_H)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_HORDE, uint32(bool(m_HalaaState & HALAA_H)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_HALAA_ALLIANCE, uint32(bool(m_HalaaState & HALAA_A)));
}
void OPvPCapturePointNA::UpdateWyvernRoostWorldState(uint32 roost)
{
switch (roost)
{
case NA_ROOST_S:
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_H, uint32(bool(m_WyvernStateSouth & WYVERN_NEU_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_NEU_A, uint32(bool(m_WyvernStateSouth & WYVERN_NEU_ALLIANCE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_H, uint32(bool(m_WyvernStateSouth & WYVERN_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_SOUTH_A, uint32(bool(m_WyvernStateSouth & WYVERN_ALLIANCE)));
break;
case NA_ROOST_N:
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_H, uint32(bool(m_WyvernStateNorth & WYVERN_NEU_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_NEU_A, uint32(bool(m_WyvernStateNorth & WYVERN_NEU_ALLIANCE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_H, uint32(bool(m_WyvernStateNorth & WYVERN_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_NORTH_A, uint32(bool(m_WyvernStateNorth & WYVERN_ALLIANCE)));
break;
case NA_ROOST_W:
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_H, uint32(bool(m_WyvernStateWest & WYVERN_NEU_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_NEU_A, uint32(bool(m_WyvernStateWest & WYVERN_NEU_ALLIANCE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_H, uint32(bool(m_WyvernStateWest & WYVERN_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_WEST_A, uint32(bool(m_WyvernStateWest & WYVERN_ALLIANCE)));
break;
case NA_ROOST_E:
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_H, uint32(bool(m_WyvernStateEast & WYVERN_NEU_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_NEU_A, uint32(bool(m_WyvernStateEast & WYVERN_NEU_ALLIANCE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_H, uint32(bool(m_WyvernStateEast & WYVERN_HORDE)));
_pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_MAP_WYVERN_EAST_A, uint32(bool(m_WyvernStateEast & WYVERN_ALLIANCE)));
break;
}
}
class OutdoorPvP_nagrand : public OutdoorPvPScript
{
public:
OutdoorPvP_nagrand() : OutdoorPvPScript("outdoorpvp_na") { }
OutdoorPvP* GetOutdoorPvP() const override
{
return new OutdoorPvPNA();
}
};
struct outdoorpvp_na_halaa_creatures : public ScriptedAI
{
outdoorpvp_na_halaa_creatures(Creature* creature) : ScriptedAI(creature) { }
void UpdateAI(uint32 /*diff*/) override
{
if (halaaNPCHorde.size() != NA_HALAA_CREATURE_TEAM_SPAWN && halaaNPCAlly.size() != NA_HALAA_CREATURE_TEAM_SPAWN)
{
std::list creatures;
uint32 entry = 0;
for (int i = 0; i < NA_HALAA_CREATURES; i++)
{
me->GetCreatureListWithEntryInGrid(creatures, PatrolCreatureEntry[i].idPatrol, 250);
}
if (creatures.size() == NA_HALAA_MAX_CREATURE_SPAWN)
{
for (std::list::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
{
Creature* const c = *itr;
if (entry < NA_HALAA_CREATURE_TEAM_SPAWN)
{
halaaNPCHorde[entry] = c->GetSpawnId();
}
else
{
halaaNPCAlly[entry - NA_HALAA_CREATURE_TEAM_SPAWN] = c->GetSpawnId();
}
c->AddObjectToRemoveList();
entry++;
sObjectMgr->RemoveCreatureFromGrid(c->GetSpawnId(), c->GetCreatureData());
}
}
}
DoMeleeAttackIfReady();
}
};
void AddSC_outdoorpvp_na()
{
new OutdoorPvP_nagrand();
RegisterCreatureAI(outdoorpvp_na_halaa_creatures);
}