Files
TrinityCore/src/server/game/Battlegrounds/BattlegroundMgr.cpp
T
jackpoz 1c0903e286 Core/Misc: Fix some static analysis issues
Fix some static analysis issues about uninitialized values. Most of them are false positives, always initialized before being accessed, while some of them are real issues spotted by valgrind too.
2013-12-14 18:41:26 +01:00

1213 lines
47 KiB
C++

/*
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Common.h"
#include "ObjectMgr.h"
#include "ArenaTeamMgr.h"
#include "World.h"
#include "WorldPacket.h"
#include "ArenaTeam.h"
#include "BattlegroundMgr.h"
#include "BattlegroundAV.h"
#include "BattlegroundAB.h"
#include "BattlegroundEY.h"
#include "BattlegroundWS.h"
#include "BattlegroundNA.h"
#include "BattlegroundBE.h"
#include "BattlegroundRL.h"
#include "BattlegroundSA.h"
#include "BattlegroundDS.h"
#include "BattlegroundRV.h"
#include "BattlegroundIC.h"
#include "Chat.h"
#include "Map.h"
#include "MapInstanced.h"
#include "MapManager.h"
#include "Player.h"
#include "GameEventMgr.h"
#include "SharedDefines.h"
#include "Formulas.h"
#include "DisableMgr.h"
#include "Opcodes.h"
/*********************************************************/
/*** BATTLEGROUND MANAGER ***/
/*********************************************************/
BattlegroundMgr::BattlegroundMgr() :
m_NextRatedArenaUpdate(sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER)),
m_NextAutoDistributionTime(0),
m_AutoDistributionTimeChecker(0), m_ArenaTesting(false), m_Testing(false)
{ }
BattlegroundMgr::~BattlegroundMgr()
{
DeleteAllBattlegrounds();
}
void BattlegroundMgr::DeleteAllBattlegrounds()
{
for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1)
{
BattlegroundData& data = itr1->second;
while (!data.m_Battlegrounds.empty())
delete data.m_Battlegrounds.begin()->second;
data.m_Battlegrounds.clear();
while (!data.BGFreeSlotQueue.empty())
delete data.BGFreeSlotQueue.front();
}
bgDataStore.clear();
}
// used to update running battlegrounds, and delete finished ones
void BattlegroundMgr::Update(uint32 diff)
{
for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1)
{
BattlegroundContainer& bgs = itr1->second.m_Battlegrounds;
BattlegroundContainer::iterator itrDelete = bgs.begin();
// first one is template and should not be deleted
for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgs.end();)
{
itrDelete = itr++;
Battleground* bg = itrDelete->second;
bg->Update(diff);
if (bg->ToBeDeleted())
{
itrDelete->second = NULL;
bgs.erase(itrDelete);
BattlegroundClientIdsContainer& clients = itr1->second.m_ClientBattlegroundIds[bg->GetBracketId()];
if (!clients.empty())
clients.erase(bg->GetClientInstanceID());
delete bg;
}
}
}
// update events timer
for (int qtype = BATTLEGROUND_QUEUE_NONE; qtype < MAX_BATTLEGROUND_QUEUE_TYPES; ++qtype)
m_BattlegroundQueues[qtype].UpdateEvents(diff);
// update scheduled queues
if (!m_QueueUpdateScheduler.empty())
{
std::vector<uint64> scheduled;
std::swap(scheduled, m_QueueUpdateScheduler);
for (uint8 i = 0; i < scheduled.size(); i++)
{
uint32 arenaMMRating = scheduled[i] >> 32;
uint8 arenaType = scheduled[i] >> 24 & 255;
BattlegroundQueueTypeId bgQueueTypeId = BattlegroundQueueTypeId(scheduled[i] >> 16 & 255);
BattlegroundTypeId bgTypeId = BattlegroundTypeId((scheduled[i] >> 8) & 255);
BattlegroundBracketId bracket_id = BattlegroundBracketId(scheduled[i] & 255);
m_BattlegroundQueues[bgQueueTypeId].BattlegroundQueueUpdate(diff, bgTypeId, bracket_id, arenaType, arenaMMRating > 0, arenaMMRating);
}
}
// if rating difference counts, maybe force-update queues
if (sWorld->getIntConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER))
{
// it's time to force update
if (m_NextRatedArenaUpdate < diff)
{
// forced update for rated arenas (scan all, but skipped non rated)
TC_LOG_TRACE("bg.arena", "BattlegroundMgr: UPDATING ARENA QUEUES");
for (int qtype = BATTLEGROUND_QUEUE_2v2; qtype <= BATTLEGROUND_QUEUE_5v5; ++qtype)
for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
m_BattlegroundQueues[qtype].BattlegroundQueueUpdate(diff,
BATTLEGROUND_AA, BattlegroundBracketId(bracket),
BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId(qtype)), true, 0);
m_NextRatedArenaUpdate = sWorld->getIntConfig(CONFIG_ARENA_RATED_UPDATE_TIMER);
}
else
m_NextRatedArenaUpdate -= diff;
}
if (sWorld->getBoolConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
{
if (m_AutoDistributionTimeChecker < diff)
{
if (time(NULL) > m_NextAutoDistributionTime)
{
sArenaTeamMgr->DistributeArenaPoints();
m_NextAutoDistributionTime = m_NextAutoDistributionTime + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld->getIntConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
sWorld->setWorldState(WS_ARENA_DISTRIBUTION_TIME, uint64(m_NextAutoDistributionTime));
}
m_AutoDistributionTimeChecker = 600000; // check 10 minutes
}
else
m_AutoDistributionTimeChecker -= diff;
}
}
void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype, uint32 arenaFaction)
{
// we can be in 2 queues in same time...
if (StatusID == 0 || !bg)
{
data->Initialize(SMSG_BATTLEFIELD_STATUS, 4+8);
*data << uint32(QueueSlot); // queue id (0...1)
*data << uint64(0);
return;
}
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+8+1+1+4+1+4+4+4));
*data << uint32(QueueSlot); // queue id (0...1) - player can be in 2 queues in time
// The following segment is read as uint64 in client but can be appended as their original type.
*data << uint8(arenatype);
TC_LOG_DEBUG("network", "BattlegroundMgr::BuildBattlegroundStatusPacket: arenatype = %u for bg instanceID %u, TypeID %u.", arenatype, bg->GetClientInstanceID(), bg->GetTypeID());
*data << uint8(bg->isArena() ? 0xE : 0x0);
*data << uint32(bg->GetTypeID());
*data << uint16(0x1F90);
// End of uint64 segment, decomposed this way for simplicity
*data << uint8(bg->GetMinLevel());
*data << uint8(bg->GetMaxLevel());
*data << uint32(bg->GetClientInstanceID());
// alliance/horde for BG and skirmish/rated for Arenas
// following displays the minimap-icon 0 = faction icon 1 = arenaicon
*data << uint8(bg->isRated()); // 1 for rated match, 0 for bg or non rated match
*data << uint32(StatusID); // status
switch (StatusID)
{
case STATUS_WAIT_QUEUE: // status_in_queue
*data << uint32(Time1); // average wait time, milliseconds
*data << uint32(Time2); // time in queue, updated every minute!, milliseconds
break;
case STATUS_WAIT_JOIN: // status_invite
*data << uint32(bg->GetMapId()); // map id
*data << uint64(0); // 3.3.5, unknown
*data << uint32(Time1); // time to remove from queue, milliseconds
break;
case STATUS_IN_PROGRESS: // status_in_progress
*data << uint32(bg->GetMapId()); // map id
*data << uint64(0); // 3.3.5, unknown
*data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
*data << uint32(Time2); // time from bg start, milliseconds
*data << uint8(arenaFaction == ALLIANCE ? 1 : 0); // arenafaction (0 for horde, 1 for alliance)
break;
default:
TC_LOG_ERROR("bg.battleground", "Unknown BG status!");
break;
}
}
void BattlegroundMgr::BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg)
{
uint8 type = (bg->isArena() ? 1 : 0);
data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
*data << uint8(type); // type (battleground=0/arena=1)
if (type) // arena
{
// it seems this must be according to BG_WINNER_A/H and _NOT_ TEAM_A/H
for (int8 i = 1; i >= 0; --i)
{
int32 rating_change = bg->GetArenaTeamRatingChangeByIndex(i);
uint32 pointsLost = rating_change < 0 ? -rating_change : 0;
uint32 pointsGained = rating_change > 0 ? rating_change : 0;
uint32 MatchmakerRating = bg->GetArenaMatchmakerRatingByIndex(i);
*data << uint32(pointsLost); // Rating Lost
*data << uint32(pointsGained); // Rating gained
*data << uint32(MatchmakerRating); // Matchmaking Value
TC_LOG_DEBUG("bg.battleground", "rating change: %d", rating_change);
}
for (int8 i = 1; i >= 0; --i)
{
if (ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(bg->GetArenaTeamIdByIndex(i)))
*data << at->GetName();
else
*data << uint8(0);
}
}
if (bg->GetStatus() != STATUS_WAIT_LEAVE)
*data << uint8(0); // bg not ended
else
{
*data << uint8(1); // bg ended
*data << uint8(bg->GetWinner()); // who win
}
size_t wpos = data->wpos();
uint32 scoreCount = 0;
*data << uint32(scoreCount); // placeholder
Battleground::BattlegroundScoreMap::const_iterator itr2 = bg->GetPlayerScoresBegin();
for (Battleground::BattlegroundScoreMap::const_iterator itr = itr2; itr != bg->GetPlayerScoresEnd();)
{
itr2 = itr++;
BattlegroundScore* score = itr2->second;
if (!bg->IsPlayerInBattleground(itr2->first))
{
TC_LOG_ERROR("bg.battleground", "Player " UI64FMTD " has scoreboard entry for battleground %u but is not in battleground!", itr->first, bg->GetTypeID(true));
continue;
}
*data << uint64(itr2->first);
*data << uint32(score->KillingBlows);
if (type == 0)
{
*data << uint32(score->HonorableKills);
*data << uint32(score->Deaths);
*data << uint32(score->BonusHonor);
}
else
{
Player* player = ObjectAccessor::FindPlayer(itr2->first);
uint32 team = bg->GetPlayerTeam(itr2->first);
if (!team && player)
team = player->GetBGTeam();
*data << uint8(team == ALLIANCE ? 1 : 0); // green or yellow
}
*data << uint32(score->DamageDone); // damage done
*data << uint32(score->HealingDone); // healing done
switch (bg->GetTypeID(true)) // battleground specific things
{
case BATTLEGROUND_RB:
switch (bg->GetMapId())
{
case 489:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures
*data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns
break;
case 566:
*data << uint32(0x00000001); // count of next fields
*data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures
break;
case 529:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases asssulted
*data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended
break;
case 30:
*data << uint32(0x00000005); // count of next fields
*data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted
*data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended
*data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted
*data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended
*data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured
break;
case 607:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed);
*data << uint32(((BattlegroundSAScore*)score)->gates_destroyed);
break;
case 628: // IC
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases asssulted
*data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended
default:
*data << uint32(0);
break;
}
break;
case BATTLEGROUND_AV:
*data << uint32(0x00000005); // count of next fields
*data << uint32(((BattlegroundAVScore*)score)->GraveyardsAssaulted); // GraveyardsAssaulted
*data << uint32(((BattlegroundAVScore*)score)->GraveyardsDefended); // GraveyardsDefended
*data << uint32(((BattlegroundAVScore*)score)->TowersAssaulted); // TowersAssaulted
*data << uint32(((BattlegroundAVScore*)score)->TowersDefended); // TowersDefended
*data << uint32(((BattlegroundAVScore*)score)->MinesCaptured); // MinesCaptured
break;
case BATTLEGROUND_WS:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundWGScore*)score)->FlagCaptures); // flag captures
*data << uint32(((BattlegroundWGScore*)score)->FlagReturns); // flag returns
break;
case BATTLEGROUND_AB:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundABScore*)score)->BasesAssaulted); // bases assaulted
*data << uint32(((BattlegroundABScore*)score)->BasesDefended); // bases defended
break;
case BATTLEGROUND_EY:
*data << uint32(0x00000001); // count of next fields
*data << uint32(((BattlegroundEYScore*)score)->FlagCaptures); // flag captures
break;
case BATTLEGROUND_SA:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundSAScore*)score)->demolishers_destroyed);
*data << uint32(((BattlegroundSAScore*)score)->gates_destroyed);
break;
case BATTLEGROUND_IC:
*data << uint32(0x00000002); // count of next fields
*data << uint32(((BattlegroundICScore*)score)->BasesAssaulted); // bases assaulted
*data << uint32(((BattlegroundICScore*)score)->BasesDefended); // bases defended
break;
case BATTLEGROUND_NA:
case BATTLEGROUND_BE:
case BATTLEGROUND_AA:
case BATTLEGROUND_RL:
case BATTLEGROUND_DS:
case BATTLEGROUND_RV:
*data << uint32(0);
break;
default:
TC_LOG_DEBUG("network", "Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
*data << uint32(0);
break;
}
// should never happen
if (++scoreCount >= bg->GetMaxPlayers() && itr != bg->GetPlayerScoresEnd())
{
TC_LOG_ERROR("bg.battleground", "Battleground %u scoreboard has more entries (%u) than allowed players in this bg (%u)", bg->GetTypeID(true), bg->GetPlayerScoresSize(), bg->GetMaxPlayers());
break;
}
}
data->put(wpos, scoreCount);
}
void BattlegroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result)
{
data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
*data << int32(result);
if (result == ERR_BATTLEGROUND_JOIN_TIMED_OUT || result == ERR_BATTLEGROUND_JOIN_FAILED)
*data << uint64(0); // player guid
}
void BattlegroundMgr::BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value)
{
data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
*data << uint32(field);
*data << uint32(value);
}
void BattlegroundMgr::BuildPlaySoundPacket(WorldPacket* data, uint32 soundid)
{
data->Initialize(SMSG_PLAY_SOUND, 4);
*data << uint32(soundid);
}
void BattlegroundMgr::BuildPlayerLeftBattlegroundPacket(WorldPacket* data, uint64 guid)
{
data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
*data << uint64(guid);
}
void BattlegroundMgr::BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player)
{
data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
*data << uint64(player->GetGUID());
}
Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
//cause at HandleBattlegroundJoinOpcode the clients sends the instanceid he gets from
//SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
Battleground* bg = GetBattlegroundTemplate(bgTypeId);
if (!bg)
return NULL;
if (bg->isArena())
return GetBattleground(instanceId, bgTypeId);
BattlegroundDataContainer::const_iterator it = bgDataStore.find(bgTypeId);
if (it == bgDataStore.end())
return NULL;
for (BattlegroundContainer::const_iterator itr = it->second.m_Battlegrounds.begin(); itr != it->second.m_Battlegrounds.end(); ++itr)
{
if (itr->second->GetClientInstanceID() == instanceId)
return itr->second;
}
return NULL;
}
Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (!instanceId)
return NULL;
BattlegroundDataContainer::const_iterator begin, end;
if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
begin = bgDataStore.begin();
end = bgDataStore.end();
}
else
{
end = bgDataStore.find(bgTypeId);
if (end == bgDataStore.end())
return NULL;
begin = end++;
}
for (BattlegroundDataContainer::const_iterator it = begin; it != end; ++it)
{
BattlegroundContainer const& bgs = it->second.m_Battlegrounds;
BattlegroundContainer::const_iterator itr = bgs.find(instanceId);
if (itr != bgs.end())
return itr->second;
}
return NULL;
}
Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgTypeId)
{
BattlegroundDataContainer::const_iterator itr = bgDataStore.find(bgTypeId);
if (itr == bgDataStore.end())
return NULL;
BattlegroundContainer const& bgs = itr->second.m_Battlegrounds;
//map is sorted and we can be sure that lowest instance id has only BG template
return bgs.empty() ? NULL : bgs.begin()->second;
}
uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
if (IsArenaType(bgTypeId))
return 0; //arenas don't have client-instanceids
// we create here an instanceid, which is just for
// displaying this to the client and without any other use..
// the client-instanceIds are unique for each battleground-type
// the instance-id just needs to be as low as possible, beginning with 1
// the following works, because std::set is default ordered with "<"
// the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
BattlegroundClientIdsContainer& clientIds = bgDataStore[bgTypeId].m_ClientBattlegroundIds[bracket_id];
uint32 lastId = 0;
for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end();)
{
if ((++lastId) != *itr) //if there is a gap between the ids, we will break..
break;
lastId = *itr;
}
clientIds.insert(++lastId);
return lastId;
}
// create a new battleground that will really be used to play
Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId originalBgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated)
{
BattlegroundTypeId bgTypeId = originalBgTypeId;
bool isRandom = false;
switch (originalBgTypeId)
{
case BATTLEGROUND_RB:
isRandom = true;
/// Intentional fallback, "All Arenas" is random too
case BATTLEGROUND_AA:
bgTypeId = GetRandomBG(originalBgTypeId);
break;
default:
break;
}
// get the template BG
Battleground* bg_template = GetBattlegroundTemplate(bgTypeId);
if (!bg_template)
{
TC_LOG_ERROR("bg.battleground", "Battleground: CreateNewBattleground - bg template not found for %u", bgTypeId);
return NULL;
}
Battleground* bg = NULL;
// create a copy of the BG template
switch (bgTypeId)
{
case BATTLEGROUND_AV:
bg = new BattlegroundAV(*(BattlegroundAV*)bg_template);
break;
case BATTLEGROUND_WS:
bg = new BattlegroundWS(*(BattlegroundWS*)bg_template);
break;
case BATTLEGROUND_AB:
bg = new BattlegroundAB(*(BattlegroundAB*)bg_template);
break;
case BATTLEGROUND_NA:
bg = new BattlegroundNA(*(BattlegroundNA*)bg_template);
break;
case BATTLEGROUND_BE:
bg = new BattlegroundBE(*(BattlegroundBE*)bg_template);
break;
case BATTLEGROUND_EY:
bg = new BattlegroundEY(*(BattlegroundEY*)bg_template);
break;
case BATTLEGROUND_RL:
bg = new BattlegroundRL(*(BattlegroundRL*)bg_template);
break;
case BATTLEGROUND_SA:
bg = new BattlegroundSA(*(BattlegroundSA*)bg_template);
break;
case BATTLEGROUND_DS:
bg = new BattlegroundDS(*(BattlegroundDS*)bg_template);
break;
case BATTLEGROUND_RV:
bg = new BattlegroundRV(*(BattlegroundRV*)bg_template);
break;
case BATTLEGROUND_IC:
bg = new BattlegroundIC(*(BattlegroundIC*)bg_template);
break;
case BATTLEGROUND_RB:
case BATTLEGROUND_AA:
bg = new Battleground(*bg_template);
break;
default:
return NULL;
}
bg->SetBracket(bracketEntry);
bg->SetInstanceID(sMapMgr->GenerateInstanceId());
bg->SetClientInstanceID(CreateClientVisibleInstanceId(isRandom ? BATTLEGROUND_RB : bgTypeId, bracketEntry->GetBracketId()));
bg->Reset(); // reset the new bg (set status to status_wait_queue from status_none)
bg->SetStatus(STATUS_WAIT_JOIN); // start the joining of the bg
bg->SetArenaType(arenaType);
bg->SetTypeID(originalBgTypeId);
bg->SetRandomTypeID(bgTypeId);
bg->SetRated(isRated);
bg->SetRandom(isRandom);
// Set up correct min/max player counts for scoreboards
if (bg->isArena())
{
uint32 maxPlayersPerTeam = 0;
switch (arenaType)
{
case ARENA_TYPE_2v2:
maxPlayersPerTeam = 2;
break;
case ARENA_TYPE_3v3:
maxPlayersPerTeam = 3;
break;
case ARENA_TYPE_5v5:
maxPlayersPerTeam = 5;
break;
}
bg->SetMaxPlayersPerTeam(maxPlayersPerTeam);
bg->SetMaxPlayers(maxPlayersPerTeam * 2);
}
return bg;
}
// used to create the BG templates
bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
{
// Create the BG
Battleground* bg = NULL;
switch (data.bgTypeId)
{
case BATTLEGROUND_AV:
bg = new BattlegroundAV;
break;
case BATTLEGROUND_WS:
bg = new BattlegroundWS;
break;
case BATTLEGROUND_AB:
bg = new BattlegroundAB;
break;
case BATTLEGROUND_NA:
bg = new BattlegroundNA;
break;
case BATTLEGROUND_BE:
bg = new BattlegroundBE;
break;
case BATTLEGROUND_EY:
bg = new BattlegroundEY;
break;
case BATTLEGROUND_RL:
bg = new BattlegroundRL;
break;
case BATTLEGROUND_SA:
bg = new BattlegroundSA;
break;
case BATTLEGROUND_DS:
bg = new BattlegroundDS;
break;
case BATTLEGROUND_RV:
bg = new BattlegroundRV;
break;
case BATTLEGROUND_IC:
bg = new BattlegroundIC;
break;
case BATTLEGROUND_AA:
bg = new Battleground;
break;
case BATTLEGROUND_RB:
bg = new Battleground;
bg->SetRandom(true);
break;
default:
return false;
}
bg->SetMapId(data.MapID);
bg->SetTypeID(data.bgTypeId);
bg->SetInstanceID(0);
bg->SetArenaorBGType(data.IsArena);
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
bg->SetMinPlayers(data.MinPlayersPerTeam * 2);
bg->SetMaxPlayers(data.MaxPlayersPerTeam * 2);
bg->SetName(data.BattlegroundName);
bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO);
bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO);
bg->SetStartMaxDist(data.StartMaxDist);
bg->SetLevelRange(data.LevelMin, data.LevelMax);
bg->SetScriptId(data.scriptId);
AddBattleground(bg);
return true;
}
void BattlegroundMgr::CreateInitialBattlegrounds()
{
uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 5 6 7 8 9 10 11
QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, StartMaxDist, Weight, ScriptName FROM battleground_template");
if (!result)
{
TC_LOG_ERROR("server.loading", ">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 bgTypeId = fields[0].GetUInt32();
if (DisableMgr::IsDisabledFor(DISABLE_TYPE_BATTLEGROUND, bgTypeId, NULL))
continue;
// can be overwrite by values from DB
BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
if (!bl)
{
TC_LOG_ERROR("bg.battleground", "Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeId);
continue;
}
CreateBattlegroundData data;
data.bgTypeId = BattlegroundTypeId(bgTypeId);
data.IsArena = (bl->type == TYPE_ARENA);
data.MinPlayersPerTeam = fields[1].GetUInt16();
data.MaxPlayersPerTeam = fields[2].GetUInt16();
data.LevelMin = fields[3].GetUInt8();
data.LevelMax = fields[4].GetUInt8();
float dist = fields[9].GetFloat();
data.StartMaxDist = dist * dist;
data.scriptId = sObjectMgr->GetScriptId(fields[11].GetCString());
data.BattlegroundName = bl->name[sWorld->GetDefaultDbcLocale()];
data.MapID = bl->mapid[0];
if (data.MaxPlayersPerTeam == 0 || data.MinPlayersPerTeam > data.MaxPlayersPerTeam)
{
TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)",
data.bgTypeId, data.MinPlayersPerTeam, data.MaxPlayersPerTeam);
continue;
}
if (data.LevelMin == 0 || data.LevelMax == 0 || data.LevelMin > data.LevelMax)
{
TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for LevelMin (%u) and LevelMax(%u)",
data.bgTypeId, data.LevelMin, data.LevelMax);
continue;
}
if (data.bgTypeId == BATTLEGROUND_AA || data.bgTypeId == BATTLEGROUND_RB)
{
data.Team1StartLocX = 0;
data.Team1StartLocY = 0;
data.Team1StartLocZ = 0;
data.Team1StartLocO = fields[6].GetFloat();
data.Team2StartLocX = 0;
data.Team2StartLocY = 0;
data.Team2StartLocZ = 0;
data.Team2StartLocO = fields[8].GetFloat();
}
else
{
uint32 startId = fields[5].GetUInt32();
if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId))
{
data.Team1StartLocX = start->x;
data.Team1StartLocY = start->y;
data.Team1StartLocZ = start->z;
data.Team1StartLocO = fields[6].GetFloat();
}
else
{
TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", data.bgTypeId, startId);
continue;
}
startId = fields[7].GetUInt32();
if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId))
{
data.Team2StartLocX = start->x;
data.Team2StartLocY = start->y;
data.Team2StartLocZ = start->z;
data.Team2StartLocO = fields[8].GetFloat();
}
else
{
TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", data.bgTypeId, startId);
continue;
}
}
if (!CreateBattleground(data))
continue;
if (data.IsArena)
{
if (data.bgTypeId != BATTLEGROUND_AA)
m_ArenaSelectionWeights[data.bgTypeId] = fields[10].GetUInt8();
}
else if (data.bgTypeId != BATTLEGROUND_RB)
m_BGSelectionWeights[data.bgTypeId] = fields[10].GetUInt8();
++count;
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u battlegrounds in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void BattlegroundMgr::InitAutomaticArenaPointDistribution()
{
if (!sWorld->getBoolConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
return;
time_t wstime = time_t(sWorld->getWorldState(WS_ARENA_DISTRIBUTION_TIME));
time_t curtime = time(NULL);
TC_LOG_DEBUG("bg.battleground", "Initializing Automatic Arena Point Distribution");
if (wstime < curtime)
{
m_NextAutoDistributionTime = curtime; // reset will be called in the next update
TC_LOG_DEBUG("bg.battleground", "Battleground: Next arena point distribution time in the past, reseting it now.");
}
else
m_NextAutoDistributionTime = wstime;
TC_LOG_DEBUG("bg.battleground", "Automatic Arena Point Distribution initialized.");
}
void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere)
{
if (!player)
return;
uint32 winner_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_HONOR_FIRST);
uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST);
uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST);
winner_kills = Trinity::Honor::hk_honor_at_level(player->getLevel(), float(winner_kills));
loser_kills = Trinity::Honor::hk_honor_at_level(player->getLevel(), float(loser_kills));
data->Initialize(SMSG_BATTLEFIELD_LIST);
*data << uint64(guid); // battlemaster guid
*data << uint8(fromWhere); // from where you joined
*data << uint32(bgTypeId); // battleground id
*data << uint8(0); // unk
*data << uint8(0); // unk
// Rewards
*data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin
*data << uint32(winner_kills); // 3.3.3 winHonor
*data << uint32(winner_arena); // 3.3.3 winArena
*data << uint32(loser_kills); // 3.3.3 lossHonor
uint8 isRandom = bgTypeId == BATTLEGROUND_RB;
*data << uint8(isRandom); // 3.3.3 isRandom
if (isRandom)
{
// Rewards (random)
*data << uint8(player->GetRandomWinner()); // 3.3.3 hasWin_Random
*data << uint32(winner_kills); // 3.3.3 winHonor_Random
*data << uint32(winner_arena); // 3.3.3 winArena_Random
*data << uint32(loser_kills); // 3.3.3 lossHonor_Random
}
if (bgTypeId == BATTLEGROUND_AA) // arena
*data << uint32(0); // unk (count?)
else // battleground
{
size_t count_pos = data->wpos();
*data << uint32(0); // number of bg instances
BattlegroundDataContainer::iterator it = bgDataStore.find(bgTypeId);
if (it != bgDataStore.end())
{
// expected bracket entry
if (PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(it->second.m_Battlegrounds.begin()->second->GetMapId(), player->getLevel()))
{
uint32 count = 0;
BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
BattlegroundClientIdsContainer& clientIds = it->second.m_ClientBattlegroundIds[bracketId];
for (BattlegroundClientIdsContainer::const_iterator itr = clientIds.begin(); itr != clientIds.end(); ++itr)
{
*data << uint32(*itr);
++count;
}
data->put<uint32>(count_pos, count);
}
}
}
}
void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (Battleground* bg = GetBattleground(instanceId, bgTypeId))
{
float x, y, z, O;
uint32 mapid = bg->GetMapId();
uint32 team = player->GetBGTeam();
if (team == 0)
team = player->GetTeam();
bg->GetTeamStartLoc(team, x, y, z, O);
TC_LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending %s to map %u, X %f, Y %f, Z %f, O %f (bgType %u)", player->GetName().c_str(), mapid, x, y, z, O, bgTypeId);
player->TeleportTo(mapid, x, y, z, O);
}
else
TC_LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance %u (bgType %u) not found while trying to teleport player %s", instanceId, bgTypeId, player->GetName().c_str());
}
void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid)
{
WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
if (time_ == uint32(-1))
time_ = 0;
data << guid << time_;
player->GetSession()->SendPacket(&data);
}
bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId)
{
return bgTypeId == BATTLEGROUND_AA
|| bgTypeId == BATTLEGROUND_BE
|| bgTypeId == BATTLEGROUND_NA
|| bgTypeId == BATTLEGROUND_DS
|| bgTypeId == BATTLEGROUND_RV
|| bgTypeId == BATTLEGROUND_RL;
}
BattlegroundQueueTypeId BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 arenaType)
{
switch (bgTypeId)
{
case BATTLEGROUND_AB:
return BATTLEGROUND_QUEUE_AB;
case BATTLEGROUND_AV:
return BATTLEGROUND_QUEUE_AV;
case BATTLEGROUND_EY:
return BATTLEGROUND_QUEUE_EY;
case BATTLEGROUND_IC:
return BATTLEGROUND_QUEUE_IC;
case BATTLEGROUND_RB:
return BATTLEGROUND_QUEUE_RB;
case BATTLEGROUND_SA:
return BATTLEGROUND_QUEUE_SA;
case BATTLEGROUND_WS:
return BATTLEGROUND_QUEUE_WS;
case BATTLEGROUND_AA:
case BATTLEGROUND_BE:
case BATTLEGROUND_DS:
case BATTLEGROUND_NA:
case BATTLEGROUND_RL:
case BATTLEGROUND_RV:
switch (arenaType)
{
case ARENA_TYPE_2v2:
return BATTLEGROUND_QUEUE_2v2;
case ARENA_TYPE_3v3:
return BATTLEGROUND_QUEUE_3v3;
case ARENA_TYPE_5v5:
return BATTLEGROUND_QUEUE_5v5;
default:
return BATTLEGROUND_QUEUE_NONE;
}
default:
return BATTLEGROUND_QUEUE_NONE;
}
}
BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId)
{
switch (bgQueueTypeId)
{
case BATTLEGROUND_QUEUE_WS:
return BATTLEGROUND_WS;
case BATTLEGROUND_QUEUE_AB:
return BATTLEGROUND_AB;
case BATTLEGROUND_QUEUE_AV:
return BATTLEGROUND_AV;
case BATTLEGROUND_QUEUE_EY:
return BATTLEGROUND_EY;
case BATTLEGROUND_QUEUE_SA:
return BATTLEGROUND_SA;
case BATTLEGROUND_QUEUE_IC:
return BATTLEGROUND_IC;
case BATTLEGROUND_QUEUE_RB:
return BATTLEGROUND_RB;
case BATTLEGROUND_QUEUE_2v2:
case BATTLEGROUND_QUEUE_3v3:
case BATTLEGROUND_QUEUE_5v5:
return BATTLEGROUND_AA;
default:
return BattlegroundTypeId(0); // used for unknown template (it existed and do nothing)
}
}
uint8 BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId bgQueueTypeId)
{
switch (bgQueueTypeId)
{
case BATTLEGROUND_QUEUE_2v2:
return ARENA_TYPE_2v2;
case BATTLEGROUND_QUEUE_3v3:
return ARENA_TYPE_3v3;
case BATTLEGROUND_QUEUE_5v5:
return ARENA_TYPE_5v5;
default:
return 0;
}
}
void BattlegroundMgr::ToggleTesting()
{
m_Testing = !m_Testing;
sWorld->SendWorldText(m_Testing ? LANG_DEBUG_BG_ON : LANG_DEBUG_BG_OFF);
}
void BattlegroundMgr::ToggleArenaTesting()
{
m_ArenaTesting = !m_ArenaTesting;
sWorld->SendWorldText(m_ArenaTesting ? LANG_DEBUG_ARENA_ON : LANG_DEBUG_ARENA_OFF);
}
void BattlegroundMgr::SetHolidayWeekends(uint32 mask)
{
for (uint32 bgtype = 1; bgtype < MAX_BATTLEGROUND_TYPE_ID; ++bgtype)
{
if (Battleground* bg = GetBattlegroundTemplate(BattlegroundTypeId(bgtype)))
{
bg->SetHoliday(mask & (1 << bgtype));
}
}
}
void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
//This method must be atomic, @todo add mutex
//we will use only 1 number created of bgTypeId and bracket_id
uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | (uint32(arenaType) << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id;
if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end())
m_QueueUpdateScheduler.push_back(scheduleId);
}
uint32 BattlegroundMgr::GetMaxRatingDifference() const
{
// this is for stupid people who can't use brain and set max rating difference to 0
uint32 diff = sWorld->getIntConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
if (diff == 0)
diff = 5000;
return diff;
}
uint32 BattlegroundMgr::GetRatingDiscardTimer() const
{
return sWorld->getIntConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
}
uint32 BattlegroundMgr::GetPrematureFinishTime() const
{
return sWorld->getIntConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
}
void BattlegroundMgr::LoadBattleMastersEntry()
{
uint32 oldMSTime = getMSTime();
mBattleMastersMap.clear(); // need for reload case
QueryResult result = WorldDatabase.Query("SELECT entry, bg_template FROM battlemaster_entry");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 battlemaster entries. DB table `battlemaster_entry` is empty!");
return;
}
uint32 count = 0;
do
{
++count;
Field* fields = result->Fetch();
uint32 entry = fields[0].GetUInt32();
uint32 bgTypeId = fields[1].GetUInt32();
if (!sBattlemasterListStore.LookupEntry(bgTypeId))
{
TC_LOG_ERROR("sql.sql", "Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.", entry, bgTypeId);
continue;
}
mBattleMastersMap[entry] = BattlegroundTypeId(bgTypeId);
}
while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u battlemaster entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
HolidayIds BattlegroundMgr::BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId)
{
switch (bgTypeId)
{
case BATTLEGROUND_AV: return HOLIDAY_CALL_TO_ARMS_AV;
case BATTLEGROUND_EY: return HOLIDAY_CALL_TO_ARMS_EY;
case BATTLEGROUND_WS: return HOLIDAY_CALL_TO_ARMS_WS;
case BATTLEGROUND_SA: return HOLIDAY_CALL_TO_ARMS_SA;
case BATTLEGROUND_AB: return HOLIDAY_CALL_TO_ARMS_AB;
case BATTLEGROUND_IC: return HOLIDAY_CALL_TO_ARMS_IC;
default: return HOLIDAY_NONE;
}
}
BattlegroundTypeId BattlegroundMgr::WeekendHolidayIdToBGType(HolidayIds holiday)
{
switch (holiday)
{
case HOLIDAY_CALL_TO_ARMS_AV: return BATTLEGROUND_AV;
case HOLIDAY_CALL_TO_ARMS_EY: return BATTLEGROUND_EY;
case HOLIDAY_CALL_TO_ARMS_WS: return BATTLEGROUND_WS;
case HOLIDAY_CALL_TO_ARMS_SA: return BATTLEGROUND_SA;
case HOLIDAY_CALL_TO_ARMS_AB: return BATTLEGROUND_AB;
case HOLIDAY_CALL_TO_ARMS_IC: return BATTLEGROUND_IC;
default: return BATTLEGROUND_TYPE_NONE;
}
}
bool BattlegroundMgr::IsBGWeekend(BattlegroundTypeId bgTypeId)
{
return IsHolidayActive(BGTypeToWeekendHolidayId(bgTypeId));
}
BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId)
{
uint32 weight = 0;
BattlegroundTypeId returnBgTypeId = BATTLEGROUND_TYPE_NONE;
BattlegroundSelectionWeightMap selectionWeights;
if (bgTypeId == BATTLEGROUND_AA)
{
for (BattlegroundSelectionWeightMap::const_iterator it = m_ArenaSelectionWeights.begin(); it != m_ArenaSelectionWeights.end(); ++it)
{
if (it->second)
{
weight += it->second;
selectionWeights[it->first] = it->second;
}
}
}
else if (bgTypeId == BATTLEGROUND_RB)
{
for (BattlegroundSelectionWeightMap::const_iterator it = m_BGSelectionWeights.begin(); it != m_BGSelectionWeights.end(); ++it)
{
if (it->second)
{
weight += it->second;
selectionWeights[it->first] = it->second;
}
}
}
if (weight)
{
// Select a random value
uint32 selectedWeight = urand(0, weight - 1);
// Select the correct bg (if we have in DB A(10), B(20), C(10), D(15) --> [0---A---9|10---B---29|30---C---39|40---D---54])
weight = 0;
for (BattlegroundSelectionWeightMap::const_iterator it = selectionWeights.begin(); it != selectionWeights.end(); ++it)
{
weight += it->second;
if (selectedWeight < weight)
{
returnBgTypeId = it->first;
break;
}
}
}
return returnBgTypeId;
}
BGFreeSlotQueueContainer& BattlegroundMgr::GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId)
{
return bgDataStore[bgTypeId].BGFreeSlotQueue;
}
void BattlegroundMgr::AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg)
{
bgDataStore[bgTypeId].BGFreeSlotQueue.push_front(bg);
}
void BattlegroundMgr::RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
BGFreeSlotQueueContainer& queues = bgDataStore[bgTypeId].BGFreeSlotQueue;
for (BGFreeSlotQueueContainer::iterator itr = queues.begin(); itr != queues.end(); ++itr)
if ((*itr)->GetInstanceID() == instanceId)
{
queues.erase(itr);
return;
}
}
void BattlegroundMgr::AddBattleground(Battleground* bg)
{
if (bg)
bgDataStore[bg->GetTypeID()].m_Battlegrounds[bg->GetInstanceID()] = bg;
}
void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId)
{
bgDataStore[bgTypeId].m_Battlegrounds.erase(instanceId);
}