/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "BattlefieldMgr.h"
#include "DatabaseEnv.h"
#include "Log.h"
#include "Map.h"
#include "MapUtils.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
namespace
{
constexpr std::array BattlefieldIdToMapId = { 0, 571, 732 };
constexpr std::array BattlefieldIdToZoneId = { 0, 4197, 5095 }; // imitate World_PVP_Area.db2
std::array BattlefieldIdToScriptId = { 0, 0, 0 };
}
BattlefieldMgr::BattlefieldMgr()
{
_updateTimer = 0;
}
BattlefieldMgr::~BattlefieldMgr() = default;
BattlefieldMgr* BattlefieldMgr::instance()
{
static BattlefieldMgr instance;
return &instance;
}
void BattlefieldMgr::InitBattlefield()
{
uint32 oldMSTime = getMSTime();
uint32 count = 0;
if (QueryResult result = WorldDatabase.Query("SELECT TypeId, ScriptName FROM battlefield_template"))
{
do
{
Field* fields = result->Fetch();
uint32 typeId = fields[0].GetUInt8();
if (typeId >= BATTLEFIELD_MAX)
{
TC_LOG_ERROR("sql.sql", "BattlefieldMgr::InitBattlefield: Invalid TypeId value {} in battlefield_template, skipped.", typeId);
continue;
}
BattlefieldIdToScriptId[typeId] = sObjectMgr->GetScriptId(fields[1].GetStringView());
++count;
} while (result->NextRow());
}
TC_LOG_INFO("server.loading", ">> Loaded {} battlefields in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void BattlefieldMgr::CreateBattlefieldsForMap(Map* map)
{
for (uint32 i = 0; i < BATTLEFIELD_MAX; ++i)
{
if (!BattlefieldIdToScriptId[i])
continue;
if (BattlefieldIdToMapId[i] != map->GetId())
continue;
Battlefield* bf = sScriptMgr->CreateBattlefield(BattlefieldIdToScriptId[i], map);
if (!bf)
continue;
if (!bf->SetupBattlefield())
{
TC_LOG_INFO("bg.battlefield", "Setting up battlefield with TypeId {} on map {} instance id {} failed.", i, map->GetId(), map->GetInstanceId());
delete bf;
}
_battlefieldsByMap[map].emplace_back(bf);
TC_LOG_INFO("bg.battlefield", "Setting up battlefield with TypeId {} on map {} instance id {} succeeded.", i, map->GetId(), map->GetInstanceId());
}
}
void BattlefieldMgr::DestroyBattlefieldsForMap(Map const* map)
{
_battlefieldsByMap.erase(map);
}
void BattlefieldMgr::AddZone(uint32 zoneId, Battlefield* bf)
{
_battlefieldsByZone[{ bf->GetMap(), zoneId }] = bf;
}
void BattlefieldMgr::HandlePlayerEnterZone(Player* player, uint32 zoneId)
{
auto itr = _battlefieldsByZone.find({ player->GetMap(), zoneId });
if (itr == _battlefieldsByZone.end())
return;
Battlefield* bf = itr->second;
if (!bf->IsEnabled() || bf->HasPlayer(player))
return;
bf->HandlePlayerEnterZone(player, zoneId);
TC_LOG_DEBUG("bg.battlefield", "Player {} entered battlefield id {}", player->GetGUID().ToString(), bf->GetTypeId());
}
void BattlefieldMgr::HandlePlayerLeaveZone(Player* player, uint32 zoneId)
{
auto itr = _battlefieldsByZone.find({ player->GetMap(), zoneId });
if (itr == _battlefieldsByZone.end())
return;
// teleport: remove once in removefromworld, once in updatezone
if (!itr->second->HasPlayer(player))
return;
itr->second->HandlePlayerLeaveZone(player, zoneId);
TC_LOG_DEBUG("bg.battlefield", "Player {} left battlefield id {}", player->GetGUID().ToString(), itr->second->GetTypeId());
}
bool BattlefieldMgr::IsWorldPvpArea(uint32 zoneId) const
{
return std::find(BattlefieldIdToZoneId.begin(), BattlefieldIdToZoneId.end(), zoneId) != BattlefieldIdToZoneId.end();
}
Battlefield* BattlefieldMgr::GetBattlefieldToZoneId(Map const* map, uint32 zoneId)
{
auto itr = _battlefieldsByZone.find({ map, zoneId });
if (itr == _battlefieldsByZone.end())
{
// no handle for this zone, return
return nullptr;
}
if (!itr->second->IsEnabled())
return nullptr;
return itr->second;
}
Battlefield* BattlefieldMgr::GetBattlefieldByBattleId(Map const* map, uint32 battleId)
{
if (BattlefieldsMapByMap::mapped_type const* battlefields = Trinity::Containers::MapGetValuePtr(_battlefieldsByMap, map))
for (std::unique_ptr const& battlefield : *battlefields)
if (battlefield->GetBattleId() == battleId)
return battlefield.get();
return nullptr;
}
void BattlefieldMgr::Update(uint32 diff)
{
_updateTimer += diff;
if (_updateTimer > BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL)
{
for (auto const& [map, battlefields] : _battlefieldsByMap)
for (std::unique_ptr const& bfItr : battlefields)
if (bfItr->IsEnabled())
bfItr->Update(_updateTimer);
_updateTimer = 0;
}
}