PDA

View Full Version : [TrinityCore] Written How to setup Crossfaction Battlegrounds



Wise
29-11-14, 08:45 PM
I want you to read this very carefully, as it is a nice long process. I will be as specific as I can be with this, so bare with me here. Don't blame me if I miss something. :P

This includes all error fixes.

#1. Configuration Option


Go into World.h and add: CONFIG_CROSSFACTIONBG inside of:



enum WorldBoolConfigs


Now head into your World.cpp and add:



m_bool_configs[CONFIG_CROSSFACTIONBG] = sConfigMgr->GetBoolDefault("MixedBGs", true);


Around line #1191 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/World/World.cpp#L1191) where all the other options are loading.



#2. Player source & header file

We will be doing the Player files. To start, open up Player.h and Player.cpp. Once you have those opened;

Go on line #1061 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Entities/Player/Player.h#L1061) and above line #1066 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Entities/Player/Player.h#L1066) add:



//CROSSFACION BG START
private:
bool m_ForgetBGPlayers;
bool m_ForgetInListPlayers;
public:
typedef std::vector<uint64> FakePlayers;
void FitPlayerInTeam(bool action);
void DoForgetPlayersInList();
void DoForgetPlayersInBG(Battleground* pBattleGround);
uint8 GetFakeRaceOrRace();
void SetForgetBGPlayers(bool tralse) { m_ForgetBGPlayers = tralse; }
bool ShouldForgetBGPlayers() { return m_ForgetBGPlayers; }
void SetForgetInListPlayers(bool tralse) { m_ForgetInListPlayers = tralse; }
bool ShouldForgetInListPlayers() { return m_ForgetInListPlayers; }
bool SendBattleGroundChat(uint32 msgtype, std::string message);
void MorphFit(bool value);
bool TeamIsBGTeam() { return GetBGTeam() == GetTeam(); }
FakePlayers m_FakePlayers;
//CROSSFACION BG END


Now go to line #1887 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Entities/Player/Player.h#L1887) and above that add:



TeamId GetBGTeamId() const { return GetBGTeam() == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; }


That should be all of Player.h. Go to Player.cpp..

I guess on any line under a function of your choice add: (In Player.cpp)



/*################################################# ###################################
###############################CROSSFACTION BATTLEGROUNDS#############################
################################################## ##################################*/

void Player::FitPlayerInTeam(bool action)
{
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(GetFakeRaceOrRace());
if(rEntry && !TeamIsBGTeam() && action)
setFaction(rEntry->FactionID);
else
setFactionForRace(getRace());

if (action)
SetForgetBGPlayers(true);
else
SetForgetInListPlayers(true);

MorphFit(action);

if (GetBattleground() && action)
ChatHandler(GetSession()).PSendSysMessage("You are playing for the %s%s in %s!", GetBGTeam() == ALLIANCE ? "|cff0000FFalliance|r" : "|cffFF0000horde|r", GetBattleground()->GetName());
}

uint8 Player::GetFakeRaceOrRace()
{
if(!TeamIsBGTeam())
return GetBGTeam() == ALLIANCE ? RACE_HUMAN : RACE_BLOODELF;
else
return getRace();
}

void Player::DoForgetPlayersInList()
{
// m_FakePlayers is filled from a vector within the battleground
// they were in previously so all players that have been in that BG will be invalidated.
for (FakePlayers::const_iterator itr = m_FakePlayers.begin(); itr != m_FakePlayers.end(); ++itr)
{
WorldPacket data(SMSG_INVALIDATE_PLAYER, 8);
data << *itr;
GetSession()->SendPacket(&data);
if (Player* pPlayer = ObjectAccessor::FindPlayer(*itr))
GetSession()->SendNameQueryOpcode(*itr);
}
m_FakePlayers.clear();
}

void Player::DoForgetPlayersInBG(Battleground* pBattleGround)
{
if (!pBattleGround || pBattleGround->isArena())
return;

for (Battleground::BattlegroundPlayerMap::const_iterat or itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr)
{
// Here we invalidate players in the bg to the added player
WorldPacket data1(SMSG_INVALIDATE_PLAYER, 8);
data1 << itr->first;
GetSession()->SendPacket(&data1);
GetSession()->SendNameQueryOpcode(itr->first);

if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first))
{
// Here we invalidate the player added to players in the bg
WorldPacket data2(SMSG_INVALIDATE_PLAYER, 8);
data2 << GetGUID();
pPlayer->GetSession()->SendPacket(&data2);
pPlayer->GetSession()->SendNameQueryOpcode(GetGUID());
}
}
}

bool BattlegroundQueue::CheckCrossFactionMatch(Battlegr oundBracketId bracket_id, Battleground* bg)
{
TC_LOG_DEBUG("misc", "BattleGroundQueue::CheckCrossFactionMatch");
if (bg->isArena())
return false; // Only do this if crossbg's are enabled.

// Here we will add all players to selectionpool, later we check if there are enough and launch a bg.
FillXPlayersToBG(bracket_id, bg, true);

uint8 MPT = bg->GetMinPlayersPerTeam();
if (m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() < MPT || m_SelectionPools[TEAM_HORDE].GetPlayerCount() < MPT)
{
TC_LOG_DEBUG("misc", "Not enough players. Has: %u Need: %u", m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() + m_SelectionPools[TEAM_HORDE].GetPlayerCount(), MPT * 2);
return false;
}
return true;
}

// This function will invite players in the least populated faction, which makes battleground queues much faster.
// This function will return true if cross faction battlegrounds are enabled, otherwise return false,
// which is useful in FillPlayersToBG. Because then we can interrupt the regular invitation if cross faction bg's are enabled.
bool BattlegroundQueue::FillXPlayersToBG(BattlegroundBr acketId bracket_id, Battleground* bg, bool start)
{
if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
{
int32 aliFree = start ? bg->GetMinPlayersPerTeam() : bg->GetFreeSlotsForTeam(ALLIANCE);
int32 hordeFree = start ? bg->GetMinPlayersPerTeam() : bg->GetFreeSlotsForTeam(HORDE);
// Empty selection pools. They will be refilled from queued groups.
m_SelectionPools[TEAM_ALLIANCE].Init();
m_SelectionPools[TEAM_HORDE].Init();
int32 valiFree = aliFree;
int32 vhordeFree = hordeFree;
int32 diff = 0;

TC_LOG_DEBUG("misc", "valiFree: %u vhordeFree: %u", valiFree, vhordeFree);

for (GroupsQueueType::iterator itr = m_QueuedGroups[BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].end(); ++itr)
{
if ((*itr)->IsInvitedToBGInstanceGUID)
continue;

diff = abs(valiFree - vhordeFree);
bool moreAli = valiFree < vhordeFree;

if (diff > 0)
(*itr)->Team = moreAli ? HORDE : ALLIANCE;

bool alliance = (*itr)->Team == ALLIANCE;

if (m_SelectionPools[alliance ? TEAM_ALLIANCE : TEAM_HORDE].AddGroup((*itr), alliance ? aliFree : hordeFree))
{
uint8 GSize = (*itr)->Players.size();
alliance ? valiFree -= GSize : vhordeFree -= GSize;
}
}
return true;
}
return false;
}

bool Player::SendBattleGroundChat(uint32 msgtype, std::string message)
{
float distance = msgtype == CHAT_MSG_SAY ? sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY) : sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL);

if (Battleground* pBattleGround = GetBattleground())
{
for (Battleground::BattlegroundPlayerMap::const_iterat or itr = pBattleGround->GetPlayers().begin(); itr != pBattleGround->GetPlayers().end(); ++itr)
{
if (Player* pPlayer = ObjectAccessor::FindPlayer(itr->first))
{
if (GetDistance2d(pPlayer->GetPositionX(), pPlayer->GetPositionY()) <= distance)
{
if (GetBGTeam() == pPlayer->GetBGTeam())
{
WorldPacket data;
ChatHandler::BuildChatPacket(data, ChatMsg(msgtype), LANG_UNIVERSAL, pPlayer, NULL, message);
pPlayer->GetSession()->SendPacket(&data);
}
else if (msgtype != CHAT_MSG_EMOTE)
{
WorldPacket data;
ChatHandler::BuildChatPacket(data, ChatMsg(msgtype), pPlayer->GetTeam() == ALLIANCE ? LANG_ORCISH : LANG_COMMON, pPlayer, NULL, message);
pPlayer->GetSession()->SendPacket(&data);
}
}
}
}
return true;
}
else
return false;
}

void Player::MorphFit(bool value)
{
if (!TeamIsBGTeam() && value)
{
if (GetBGTeam() == ALLIANCE)
{
if (getGender() == GENDER_MALE)
{
SetDisplayId(19723);
SetNativeDisplayId(19723);
}
else
{
SetDisplayId(19724);
SetNativeDisplayId(19724);
}
}
else
{
if (getGender() == GENDER_MALE)
{
SetDisplayId(20578);
SetNativeDisplayId(20578);
}
else
{
SetDisplayId(20579);
SetNativeDisplayId(20579);
}
}
}
else
InitDisplayIds();
}




#3. Unit.cpp & Handlers (https://github.com/TrinityCore/TrinityCore/tree/master/src/server/game/Handlers)



[B]QueryHandler.cpp

In QueryHandler.cpp under SendNameQueryOpcode(uint64 guid) (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/QueryHandler.cpp#L34), change:

(On line #51 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/QueryHandler.cpp#L51))


data << uint8(nameData->m_race);

to:


data << uint8(player ? player->GetFakeRaceOrRace() : nameData->m_race);

MiscHandler.cpp

Under void WorldSession::HandleTimeSyncResp(WorldPacket& recvData) (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/MiscHandler.cpp#L1416) add:



Battleground* bg = _player->GetBattleground();
if (bg)
{
if (_player->ShouldForgetBGPlayers())
{
_player->DoForgetPlayersInBG(bg);
_player->SetForgetBGPlayers(false);
}
}
else if (_player->ShouldForgetInListPlayers())
{
_player->DoForgetPlayersInList();
_player->SetForgetInListPlayers(false);
}


Above or below line: #1418 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/MiscHandler.cpp#L1418)

ChatHandler.cpp

Inside of void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/ChatHandler.cpp#L43) add:



if (!GetPlayer()->IsGameMaster())
if (GetPlayer()->SendBattleGroundChat(type, msg))
return;


Above line #251 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/ChatHandler.cpp#L251)

CharacterHandler.cpp

Inside of void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/CharacterHandler.cpp#L798)

Under line #1031 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Handlers/CharacterHandler.cpp#L1031) add:



if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
{
float x = pCurrChar->GetPositionX();
float y = pCurrChar->GetPositionY();
float z = pCurrChar->GetPositionZ();
uint32 hm = pCurrChar->m_homebindMapId;
float hx = pCurrChar->m_homebindX;
float hy = pCurrChar->m_homebindX;
float hz = pCurrChar->m_homebindX;
if (z+1 < pCurrChar->GetMap()->GetHeight(x, y, MAX_HEIGHT) && pCurrChar->GetMap()->IsOutdoors(x, y, z))
pCurrChar->TeleportTo(hm, hx, hy, hz, 0);
}

if (pCurrChar->GetBattleground() && !pCurrChar->GetBattleground()->isArena())
pCurrChar->FitPlayerInTeam(true);
else
pCurrChar->FitPlayerInTeam(false);


Unit.cpp

Inside of void Unit::RestoreFaction() (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Entities/Unit/Unit.cpp#L15918)

On line #15921 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Entities/Unit/Unit.cpp#L15921), replace:


ToPlayer()->setFactionForRace(getRace());

with


ToPlayer()->setFactionForRace(ToPlayer()->GetFakeRaceOrRace());



#4. BattlegroundQueue.cpp & BattlegroundQueue.h



Open BattlegroundQueue.h..

Inside of enum BattlegroundQueueGroupTypes (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.h#L58) under BG_QUEUE_NORMAL_HORDE = 3 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.h#L63), add:


BG_QUEUE_MIXED = 4

It should look like this now:



enum BattlegroundQueueGroupTypes
{
BG_QUEUE_PREMADE_ALLIANCE = 0,
BG_QUEUE_PREMADE_HORDE = 1,
BG_QUEUE_NORMAL_ALLIANCE = 2,
BG_QUEUE_NORMAL_HORDE = 3,
BG_QUEUE_MIXED = 4
};


On line #65 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.h#L65) replace #define BG_QUEUE_GROUP_TYPES_COUNT 4 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.h#L65) with:

(Just change the 4 to a 5)



#define BG_QUEUE_GROUP_TYPES_COUNT 5


Now, under line #75 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.h#L75) add:



bool FillXPlayersToBG(BattlegroundBracketId bracket_id, Battleground* bg, bool start = false);
bool CheckCrossFactionMatch(BattlegroundBracketId bracket_id, Battleground* bg);


You're done with BattlegroundQueue.h. Open up and go to BattlegroundQueue.cpp..

On line #840 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L840), replace:



if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
|| (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam)))


with:



if (CheckNormalMatch(bg_template, bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam)
|| (bg_template->isArena() && CheckSkirmishForSameFaction(bracket_id, MinPlayersPerTeam))
|| CheckCrossFactionMatch(bracket_id, bg_template))



On line #747 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L747), replace:



if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty())
return;


with:



if (m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_PREMADE_HORDE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].empty() &&
m_QueuedGroups[bracket_id][BG_QUEUE_MIXED].empty())
return;


On line #501 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L501) add:



if (!bg->isArena())
if (FillXPlayersToBG(bracket_id, bg, false))
return;


On line #313 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L313), replace:



for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_TEAMS_COUNT)


with:



for (uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j)


On line #298 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L298), replace:



TC_LOG_ERROR("bg.battleground", "BattlegroundQueue: couldn't find player %s (GUID: %u)", playerName.c_str(), GUID_LOPART(guid));


with:



TC_LOG_DEBUG("bg.battleground", "BattlegroundQueue: couldn't find player %s (GUID: %u)", playerName.c_str(), GUID_LOPART(guid));


READ CAREFULLY:

Inside of GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, BattlegroundTypeId BgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 arenateamid) (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L130)

On line #143 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L143) replace:


ginfo->Team = leader->GetTeam();

with:


ginfo->Team = leader->GetBGTeam();

Above line #157 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L157) add:



if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG) && ArenaType == 0)
index = BG_QUEUE_MIXED;


ON LINE #200 (https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Battlegrounds/BattlegroundQueue.cpp#L200) replace:



if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId))
{
char const* bgName = bg->GetName();
uint32 MinPlayers = bg->GetMinPlayersPerTeam();
uint32 qHorde = 0;
uint32 qAlliance = 0;
uint32 q_min_level = bracketEntry->minLevel;
uint32 q_max_level = bracketEntry->maxLevel;
GroupsQueueType::const_iterator itr;
for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
if (!(*itr)->IsInvitedToBGInstanceGUID)
qAlliance += (*itr)->Players.size();
for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
if (!(*itr)->IsInvitedToBGInstanceGUID)
qHorde += (*itr)->Players.size();

// Show queue status to player only (when joining queue)
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ PLAYERONLY))
{
ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUN CE_SELF, bgName, q_min_level, q_max_level,
qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
}
// System message
else
{
sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
}
}


with:



if (Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(ginfo->BgTypeId))
{
if (sWorld->getBoolConfig(CONFIG_CROSSFACTIONBG))
{
char const* bgName = bg->GetName();
uint32 MinPlayers = bg->GetMinPlayersPerTeam()*2;
uint32 qPlayers = 0;
uint32 q_min_level = bracketEntry->minLevel;
uint32 q_max_level = bracketEntry->maxLevel;
for (GroupsQueueType::const_iterator itr = m_QueuedGroups[bracketId][BG_QUEUE_MIXED].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_MIXED].end(); ++itr)
if (!(*itr)->IsInvitedToBGInstanceGUID)
qPlayers += (*itr)->Players.size();

if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ PLAYERONLY))
ChatHandler(leader->GetSession()).PSendSysMessage("Queue status for %s (Lvl: %u to %u) Queued players: %u (Need at least %u more)", bgName, q_min_level, q_max_level, qPlayers, MinPlayers - qPlayers);
else
{
std::ostringstream ss;
ss << "|cffff0000[BG Queue Announcer]:|r " << bgName << " -- [" << q_min_level << "-" << q_max_level << "]" << qPlayers << "/" << MinPlayers;
sWorld->SendGlobalText(ss.str().c_str(), NULL);
}
}
else
{
char const* bgName = bg->GetName();
uint32 MinPlayers = bg->GetMinPlayersPerTeam();
uint32 qHorde = 0;
uint32 qAlliance = 0;
uint32 q_min_level = bracketEntry->minLevel;
uint32 q_max_level = bracketEntry->maxLevel;
GroupsQueueType::const_iterator itr;
for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
if (!(*itr)->IsInvitedToBGInstanceGUID)
qAlliance += (*itr)->Players.size();
for (itr = m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[bracketId][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
if (!(*itr)->IsInvitedToBGInstanceGUID)
qHorde += (*itr)->Players.size();

// Show queue status to player only (when joining queue)
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ PLAYERONLY))
{
ChatHandler(leader->GetSession()).PSendSysMessage(LANG_BG_QUEUE_ANNOUN CE_SELF, bgName, q_min_level, q_max_level,
qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
}
// System message
else
{
sWorld->SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD, bgName, q_min_level, q_max_level,
qAlliance, (MinPlayers > qAlliance) ? MinPlayers - qAlliance : (uint32)0, qHorde, (MinPlayers > qHorde) ? MinPlayers - qHorde : (uint32)0);
}
}
}





And that should be it! Enjoy. :)


Credits : Tommy