Wise
29-11-14, 09: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
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