aboutsummaryrefslogtreecommitdiff
path: root/src/game/BattleGroundMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/BattleGroundMgr.cpp')
-rw-r--r--src/game/BattleGroundMgr.cpp2018
1 files changed, 1147 insertions, 871 deletions
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index 54d2538068d..1a761895b0f 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ * Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
*
* 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
@@ -19,7 +19,12 @@
*/
#include "Common.h"
-#include "Player.h"
+#include "ObjectMgr.h"
+#include "World.h"
+#include "WorldPacket.h"
+#include "Policies/SingletonImp.h"
+
+#include "ArenaTeam.h"
#include "BattleGroundMgr.h"
#include "BattleGroundAV.h"
#include "BattleGroundAB.h"
@@ -29,16 +34,16 @@
#include "BattleGroundBE.h"
#include "BattleGroundAA.h"
#include "BattleGroundRL.h"
-#include "SharedDefines.h"
-#include "Policies/SingletonImp.h"
-#include "MapManager.h"
+#include "BattleGroundSA.h"
+#include "BattleGroundDS.h"
+#include "BattleGroundRV.h"
+#include "Chat.h"
#include "Map.h"
#include "MapInstanced.h"
-#include "ObjectMgr.h"
+#include "MapManager.h"
+#include "Player.h"
#include "ProgressBar.h"
-#include "World.h"
-#include "Chat.h"
-#include "ArenaTeam.h"
+#include "SharedDefines.h"
INSTANTIATE_SINGLETON_1( BattleGroundMgr );
@@ -48,96 +53,103 @@ INSTANTIATE_SINGLETON_1( BattleGroundMgr );
BattleGroundQueue::BattleGroundQueue()
{
- //queues are empty, we don't have to call clear()
-/* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
- {
- //m_QueuedPlayers[i].Horde = 0;
- //m_QueuedPlayers[i].Alliance = 0;
- //m_QueuedPlayers[i].AverageTime = 0;
- }*/
-}
-
-BattleGroundQueue::~BattleGroundQueue()
-{
- for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
{
- m_QueuedPlayers[i].clear();
- for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
+ for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++)
{
- delete (*itr);
+ m_SumOfWaitTimes[i][j] = 0;
+ m_WaitTimeLastPlayer[i][j] = 0;
+ for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++)
+ m_WaitTimes[i][j][k] = 0;
}
- m_QueuedGroups[i].clear();
}
}
-// initialize eligible groups from the given source matching the given specifications
-void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
+BattleGroundQueue::~BattleGroundQueue()
{
- // clear from prev initialization
- clear();
- BattleGroundQueue::QueuedGroupsList::iterator itr, next;
- // iterate through the source
- for(itr = source->begin(); itr!= source->end(); itr = next)
+ m_QueuedPlayers.clear();
+ for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
- next = itr;
- ++next;
- if( (*itr)->BgTypeId == BgTypeId && // bg type must match
- (*itr)->ArenaType == ArenaType && // arena type must match
- (*itr)->IsRated == IsRated && // israted must match
- (*itr)->IsInvitedToBGInstanceGUID == 0 && // leave out already invited groups
- (*itr)->Team == side && // match side
- (*itr)->Players.size() <= MaxPlayers && // the group must fit in the bg
- ( !excludeTeam || (*itr)->ArenaTeamId != excludeTeam ) && // if excludeTeam is specified, leave out those arena team ids
- ( !IsRated || (*itr)->Players.size() == MaxPlayers ) && // if rated, then pass only if the player count is exact NEEDS TESTING! (but now this should never happen)
- ( !DisregardTime || (*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time
- || (*itr)->ArenaTeamRating == 0 // pass if no rating info
- || ( (*itr)->ArenaTeamRating >= MinRating // pass if matches the rating range
- && (*itr)->ArenaTeamRating <= MaxRating ) ) )
+ for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++)
{
- // the group matches the conditions
- // using push_back for proper selecting when inviting
- push_back((*itr));
+ for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr)
+ delete (*itr);
+ m_QueuedGroups[i][j].clear();
}
}
}
+/*********************************************************/
+/*** BATTLEGROUND QUEUE SELECTION POOLS ***/
+/*********************************************************/
+
// selection pool initialization, used to clean up from prev selection
-void BattleGroundQueue::SelectionPool::Init(EligibleGroups * curr)
+void BattleGroundQueue::SelectionPool::Init()
{
- m_CurrEligGroups = curr;
SelectedGroups.clear();
PlayerCount = 0;
}
// remove group info from selection pool
-void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
+// returns true when we need to try to add new group to selection pool
+// returns false when selection pool is ok or when we kicked smaller group than we need to kick
+// sometimes it can be called on empty selection pool
+bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
{
- // find what to remove
- for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
+ //find maxgroup or LAST group with size == size and kick it
+ bool found = false;
+ GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
+ for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
{
- if((*itr)==ginfo)
+ if (abs((int32)((*itr)->Players.size() - size)) <= 1)
{
- SelectedGroups.erase(itr);
- // decrease selected players count
- PlayerCount -= ginfo->Players.size();
- return;
+ groupToKick = itr;
+ found = true;
}
+ else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
+ groupToKick = itr;
}
+ //if pool is empty, do nothing
+ if (GetPlayerCount())
+ {
+ //update player count
+ GroupQueueInfo* ginfo = (*groupToKick);
+ SelectedGroups.erase(groupToKick);
+ PlayerCount -= ginfo->Players.size();
+ //return false if we kicked smaller group or there are enough players in selection pool
+ if (ginfo->Players.size() <= size + 1)
+ return false;
+ }
+ return true;
}
-// add group to selection
+// add group to selection pool
// used when building selection pools
-void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
+// returns true if we can invite more players, or when we added group to selection pool
+// returns false when selection pool is full
+bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
{
- SelectedGroups.push_back(ginfo);
- // increase selected players count
- PlayerCount+=ginfo->Players.size();
+ //if group is larger than desired count - don't allow to add it to pool
+ if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
+ {
+ SelectedGroups.push_back(ginfo);
+ // increase selected players count
+ PlayerCount += ginfo->Players.size();
+ return true;
+ }
+ if (PlayerCount < desiredCount)
+ return true;
+ return false;
}
+/*********************************************************/
+/*** BATTLEGROUND QUEUES ***/
+/*********************************************************/
+
// add group to bg queue with the given leader and bg specifications
-GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating, uint32 arenateamid)
+GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
{
- uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
+ BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId);
// create new ginfo
// cannot use the method like in addplayer, because that could modify an in-queue group's stats
@@ -147,28 +159,34 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, ui
ginfo->ArenaType = ArenaType;
ginfo->ArenaTeamId = arenateamid;
ginfo->IsRated = isRated;
- ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?
+ ginfo->IsInvitedToBGInstanceGUID = 0;
ginfo->JoinTime = getMSTime();
+ ginfo->RemoveInviteTime = 0;
ginfo->Team = leader->GetTeam();
ginfo->ArenaTeamRating = arenaRating;
- ginfo->OpponentsTeamRating = 0; //initialize it to 0
+ ginfo->OpponentsTeamRating = 0;
ginfo->Players.clear();
- m_QueuedGroups[queue_id].push_back(ginfo);
+ //compute index (if group is premade or joined a rated match) to queues
+ uint32 index = 0;
+ if (!isRated && !isPremade)
+ index += BG_TEAMS_COUNT;
+ if (ginfo->Team == HORDE)
+ index++;
+ sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
+
+ m_QueuedGroups[queue_id][index].push_back(ginfo);
// return ginfo, because it is needed to add players to this group info
return ginfo;
}
+//add player to playermap
void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
{
- uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
-
//if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
- PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()];
- info.InviteTime = 0;
- info.LastInviteTime = 0;
+ PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
info.LastOnlineTime = getMSTime();
info.GroupInfo = ginfo;
@@ -176,113 +194,228 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
ginfo->Players[plr->GetGUID()] = &info;
}
-void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
+void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
{
- Player *plr = objmgr.GetPlayer(guid);
+ uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
+ uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
+ if (!ginfo->ArenaType)
+ {
+ if (ginfo->Team == HORDE)
+ team_index = BG_TEAM_HORDE;
+ }
+ else
+ {
+ if (ginfo->IsRated)
+ team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
+ }
- uint32 queue_id = 0;
- QueuedPlayersMap::iterator itr;
- GroupQueueInfo * group;
- QueuedGroupsList::iterator group_itr;
- bool IsSet = false;
- if(plr)
+ //store pointer to arrayindex of player that was added first
+ uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
+ //remove his time from sum
+ m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
+ //set average time to new
+ m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
+ //add new time to sum
+ m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
+ //set index of last player added to next one
+ (*lastPlayerAddedPointer)++;
+ (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
+}
+
+uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
+{
+ uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
+ if (!ginfo->ArenaType)
{
- queue_id = plr->GetBattleGroundQueueIdFromLevel();
+ if (ginfo->Team == HORDE)
+ team_index = BG_TEAM_HORDE;
+ }
+ else
+ {
+ if (ginfo->IsRated)
+ team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
+ }
+ //check if there is enought values(we always add values > 0)
+ if (m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
+ return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
+ else
+ //if there aren't enough values return 0 - not available
+ return 0;
+}
- itr = m_QueuedPlayers[queue_id].find(guid);
- if(itr != m_QueuedPlayers[queue_id].end())
- IsSet = true;
+//remove player from queue and from group info, if group info is empty then remove it too
+void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
+{
+ //Player *plr = objmgr.GetPlayer(guid);
+
+ int32 queue_id = -1; // signed for proper for-loop finish
+ QueuedPlayersMap::iterator itr;
+
+ //remove player from map, if he's there
+ itr = m_QueuedPlayers.find(guid);
+ if (itr == m_QueuedPlayers.end())
+ {
+ sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
+ return;
}
- if(!IsSet)
+ GroupQueueInfo* group = itr->second.GroupInfo;
+ GroupsQueueType::iterator group_itr, group_itr_tmp;
+ // mostly people with the highest levels are in battlegrounds, thats why
+ // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
+ // variable index removes useless searching in other team's queue
+ uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
+
+ for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
{
- // either player is offline, or he levelled up to another queue category
- // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
- for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
+ //we must check premade and normal team's queue - because when players from premade are joining bg,
+ //they leave groupinfo so we can't use its players size to find out index
+ for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
{
- itr = m_QueuedPlayers[i].find(guid);
- if(itr != m_QueuedPlayers[i].end())
+ for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
{
- queue_id = i;
- IsSet = true;
- break;
+ if ((*group_itr_tmp) == group)
+ {
+ queue_id = queue_id_tmp;
+ group_itr = group_itr_tmp;
+ //we must store index to be able to erase iterator
+ index = j;
+ break;
+ }
}
}
}
-
- // couldn't find the player in bg queue, return
- if(!IsSet)
+ //player can't be in queue without group, but just in case
+ if (queue_id == -1)
{
- sLog.outError("Battleground: couldn't find player to remove.");
+ sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
return;
}
+ sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
- group = itr->second.GroupInfo;
+ // ALL variables are correctly set
+ // We can ignore leveling up in queue - it should not cause crash
+ // remove player from group
+ // if only one player there, remove group
+
+ // remove player queue info from group queue info
+ std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
+ if (pitr != group->Players.end())
+ group->Players.erase(pitr);
- for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
+ // if invited to bg, and should decrease invited count, then do it
+ if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
{
- if(group == (GroupQueueInfo*)(*group_itr))
- break;
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
+ if (bg)
+ bg->DecreaseInvitedCount(group->Team);
}
- // variables are set (what about leveling up when in queue????)
- // remove player from group
- // if only player there, remove group
+ // remove player queue info
+ m_QueuedPlayers.erase(itr);
- // remove player queue info from group queue info
- std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
+ //if we left BG queue(not porting) OR if arena team left queue for rated match
+ if ((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
+ AnnounceWorld(group, guid, false);
- if(pitr != group->Players.end())
- group->Players.erase(pitr);
+ //if player leaves queue and he is invited to rated arena match, then he have to loose
+ if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
+ {
+ ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId);
+ if (at)
+ {
+ sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
+ Player *plr = objmgr.GetPlayer(guid);
+ if (plr)
+ at->MemberLost(plr, group->OpponentsTeamRating);
+ else
+ at->OfflineMemberLost(guid, group->OpponentsTeamRating);
+ at->SaveToDB();
+ }
+ }
- // check for iterator correctness
- if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
+ // remove group queue info if needed
+ if (group->Players.empty())
{
- // used when player left the queue, NOT used when porting to bg
- if (decreaseInvitedCount)
+ m_QueuedGroups[queue_id][index].erase(group_itr);
+ delete group;
+ }
+ // if group wasn't empty, so it wasn't deleted, and player have left a rated
+ // queue -> everyone from the group should leave too
+ // don't remove recursively if already invited to bg!
+ else if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
+ {
+ // remove next player, this is recursive
+ // first send removal information
+ if (Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
{
- // if invited to bg, and should decrease invited count, then do it
- if(group->IsInvitedToBGInstanceGUID)
- {
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
- if (bg)
- bg->DecreaseInvitedCount(group->Team);
- if (bg && !bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))
- {
- // no more players on battleground, set delete it
- bg->SetDeleteThis();
- }
- }
- // update the join queue, maybe now the player's group fits in a queue!
- // not yet implemented (should store bgTypeId in group queue info?)
+ BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
+ uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
+ plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
+ // queue->removeplayer, it causes bugs
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
+ plr2->GetSession()->SendPacket(&data);
}
- // remove player queue info
- m_QueuedPlayers[queue_id].erase(itr);
- // remove group queue info if needed
- if(group->Players.empty())
+ // then actually delete, this may delete the group as well!
+ RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
+ }
+}
+
+//Announce world message
+void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
+{
+ if(ginfo->ArenaType) //if Arena
+ {
+ if (sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
{
- m_QueuedGroups[queue_id].erase(group_itr);
- delete group;
+ BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
+ if (!bg)
+ return;
+
+ char const* bgName = bg->GetName();
+ if (isAddedToQueue)
+ sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
+ else
+ sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
}
- // NEEDS TESTING!
- // group wasn't empty, so it wasn't deleted, and player have left a rated queue -> everyone from the group should leave too
- // don't remove recursively if already invited to bg!
- else if(!group->IsInvitedToBGInstanceGUID && decreaseInvitedCount && group->IsRated)
+ }
+ else //if BG
+ {
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
{
- // remove next player, this is recursive
- // first send removal information
- if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
+ Player *plr = objmgr.GetPlayer(playerGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
+ if (!bg || !plr)
+ return;
+
+ BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
+ char const* bgName = bg->GetName();
+ uint32 MinPlayers = bg->GetMinPlayersPerTeam();
+ uint32 qHorde = 0;
+ uint32 qAlliance = 0;
+ uint32 q_min_level = (queue_id + 1) * 10;
+ GroupsQueueType::const_iterator itr;
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
+ if (!(*itr)->IsInvitedToBGInstanceGUID)
+ qAlliance += (*itr)->Players.size();
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
+ if (!(*itr)->IsInvitedToBGInstanceGUID)
+ qHorde += (*itr)->Players.size();
+
+ // Show queue status to player only (when joining queue)
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
+ {
+ ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
+ bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
+ }
+ // System message
+ else
{
- BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(group->BgTypeId,group->ArenaType);
- uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
- plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
- plr2->GetSession()->SendPacket(&data);
+ sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
+ bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
}
- // then actually delete, this may delete the group as well!
- RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
}
}
}
@@ -290,30 +423,48 @@ void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
{
// set side if needed
- if(side)
+ if (side)
ginfo->Team = side;
- if(!ginfo->IsInvitedToBGInstanceGUID)
+ if (!ginfo->IsInvitedToBGInstanceGUID)
{
// not yet invited
// set invitation
ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ BattleGroundTypeId bgTypeId = bg->GetTypeID();
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
+ BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
+
+ // set ArenaTeamId for rated matches
+ if (bg->isArena() && bg->isRated())
+ bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
+
+ ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
+
// loop through the players
for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
{
- // set status
- itr->second->InviteTime = getMSTime();
- itr->second->LastInviteTime = getMSTime();
-
// get the player
Player* plr = objmgr.GetPlayer(itr->first);
- // if offline, skip him
- if(!plr)
+ // if offline, skip him, this should not happen - player is removed from queue when he logs out
+ if (!plr)
continue;
// invite the player
- sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
+ PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
+ //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
+
+ // set invited player counters
+ bg->IncreaseInvitedCount(ginfo->Team);
+
+ plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
+
+ // create remind invite events
+ BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime);
+ plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
+ // create automatic remove events
+ BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
+ plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
WorldPacket data;
@@ -322,7 +473,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID());
// send status packet
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
plr->GetSession()->SendPacket(&data);
}
return true;
@@ -331,190 +482,292 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b
return false;
}
-// used to recursively select groups from eligible groups
-bool BattleGroundQueue::SelectionPool::Build(uint32 MinPlayers, uint32 MaxPlayers, EligibleGroups::iterator startitr)
+/*
+This function is inviting players to already running battlegrounds
+Invitation type is based on config file
+large groups are disadvantageous, because they will be kicked first if invitation type = 1
+*/
+void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
{
- // start from the specified start iterator
- for(EligibleGroups::iterator itr1 = startitr; itr1 != m_CurrEligGroups->end(); ++itr1)
+ int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
+ int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
+
+ //iterator for iterating through bg queue
+ GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
+ //count of groups in queue - used to stop cycles
+ uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
+ //index to queue which group is current
+ uint32 aliIndex = 0;
+ for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
+ ++Ali_itr;
+ //the same thing for horde
+ GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
+ uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
+ uint32 hordeIndex = 0;
+ for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
+ ++Horde_itr;
+
+ //if ofc like BG queue invitation is set in config, then we are happy
+ if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
+ return;
+
+ /*
+ if we reached this code, then we have to solve NP - complete problem called Subset sum problem
+ So one solution is to check all possible invitation subgroups, or we can use these conditions:
+ 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
+ that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
+ 2. Other thing we should consider is group order in queue
+ */
+
+ // At first we need to compare free space in bg and our selection pool
+ int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
+ int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
+ while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
{
- // if it fits in, select it
- if(GetPlayerCount() + (*itr1)->Players.size() <= MaxPlayers)
+ //each cycle execution we need to kick at least 1 group
+ if (diffAli < diffHorde)
{
- EligibleGroups::iterator next = itr1;
- ++next;
- AddGroup((*itr1));
- if(GetPlayerCount() >= MinPlayers)
+ //kick alliance group, add to pool new group if needed
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
{
- // enough players are selected
- return true;
+ for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
+ ++Ali_itr;
+ }
+ //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
+ if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ {
+ if (aliFree <= diffHorde + 1)
+ break;
+ m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
+ }
+ }
+ else
+ {
+ //kick horde group, add to pool new group if needed
+ if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde))
+ {
+ for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
+ ++Horde_itr;
+ }
+ if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ if (hordeFree <= diffAli + 1)
+ break;
+ m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
}
- // try building from the rest of the elig. groups
- // if that succeeds, return true
- if(Build(MinPlayers,MaxPlayers,next))
- return true;
- // the rest didn't succeed, so this group cannot be included
- RemoveGroup((*itr1));
}
+ //count diffs after small update
+ diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
+ diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
}
- // build didn't succeed
- return false;
}
-// this function is responsible for the selection of queued groups when trying to create new battlegrounds
-bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime, uint32 excludeTeam)
+// this method checks if premade versus premade battleground is possible
+// then after 30 mins (default) in queue it moves premade group to normal queue
+// it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
+bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
{
- uint32 side;
- switch(mode)
- {
- case NORMAL_ALLIANCE:
- case ONESIDE_ALLIANCE_TEAM1:
- case ONESIDE_ALLIANCE_TEAM2:
- side = ALLIANCE;
- break;
- case NORMAL_HORDE:
- case ONESIDE_HORDE_TEAM1:
- case ONESIDE_HORDE_TEAM2:
- side = HORDE;
- break;
- default:
- //unknown mode, return false
- sLog.outDebug("Battleground: unknown selection pool build mode, returning...");
- return false;
- break;
- }
-
- // initiate the groups eligible to create the bg
- m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime, excludeTeam);
- // init the selected groups (clear)
- // and set m_CurrEligGroups pointer
- // we set it this way to only have one EligibleGroups object to save some memory
- m_SelectionPools[mode].Init(&m_EligibleGroups);
- // build succeeded
- if(m_SelectionPools[mode].Build(MinPlayers,MaxPlayers,m_EligibleGroups.begin()))
- {
- // the selection pool is set, return
- sLog.outDebug("Battleground-debug: pool build succeeded, return true");
- sLog.outDebug("Battleground-debug: Player size for mode %u is %u", mode, m_SelectionPools[mode].GetPlayerCount());
- for(std::list<GroupQueueInfo* >::iterator itr = m_SelectionPools[mode].SelectedGroups.begin(); itr != m_SelectionPools[mode].SelectedGroups.end(); ++itr)
+ //check match
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
+ {
+ //start premade match
+ //if groups aren't invited
+ GroupsQueueType::const_iterator ali_group, horde_group;
+ for( ali_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
+ if (!(*ali_group)->IsInvitedToBGInstanceGUID)
+ break;
+ for( horde_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
+ if (!(*horde_group)->IsInvitedToBGInstanceGUID)
+ break;
+
+ if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
{
- sLog.outDebug("Battleground-debug: queued group in selection with %u players",(*itr)->Players.size());
- for(std::map<uint64, PlayerQueueInfo * >::iterator itr2 = (*itr)->Players.begin(); itr2 != (*itr)->Players.end(); ++itr2)
- sLog.outDebug("Battleground-debug: player in above group GUID %u", (uint32)(itr2->first));
+ m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
+ m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
+ //add groups/players from normal queue to size of bigger group
+ uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
+ GroupsQueueType::const_iterator itr;
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
+ {
+ //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
+ if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
+ break;
+ }
+ }
+ //premade selection pools are set
+ return true;
}
- return true;
}
- // failed to build a selection pool matching the given values
+ // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
+ // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
+ // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
+ // and when they click or after 80 seconds the queue info is removed from queue
+ uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
+ {
+ GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
+ if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
+ {
+ //we must insert group to normal queue and erase pointer from premade queue
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
+ }
+ }
+ }
+ //selection pools are not set
return false;
}
-// used to remove the Enter Battle window if the battle has already, but someone still has it
-// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
-void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
+// this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
+bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
{
- uint32 queue_id = bg->GetQueueType();
- uint32 bgInstanceId = bg->GetInstanceID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- QueuedGroupsList::iterator itr, next;
- for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)
- {
- // must do this way, because the groupinfo will be deleted when all playerinfos are removed
- GroupQueueInfo * ginfo = (*itr);
- next = itr;
- ++next;
- // if group was invited to this bg instance, then remove all references
- if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)
+ GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ {
+ itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
+ for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
{
- // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
- uint32 to_remove = ginfo->Players.size();
- uint32 team = ginfo->Team;
- for(int i = 0; i < to_remove; ++i)
+ if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
{
- // always remove the first one in the group
- std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
- if(itr2 == ginfo->Players.end())
- {
- sLog.outError("Empty Players in ginfo, this should never happen!");
- return;
- }
+ m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
+ if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
+ break;
+ }
+ }
+ }
+ //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
+ uint32 j = BG_TEAM_ALLIANCE;
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ j = BG_TEAM_HORDE;
+ if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
+ && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
+ {
+ //we will try to invite more groups to team with less players indexed by j
+ ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
+ for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
+ {
+ if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
+ if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
+ break;
+ }
+ // do not allow to start bg with more than 2 players more on 1 faction
+ if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2)
+ return false;
+ }
+ //allow 1v0 if debug bg
+ if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()))
+ return true;
+ //return true if there are enough players in selection pools - enable to work .debug bg command correctly
+ return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
+}
- // get the player
- Player * plr = objmgr.GetPlayer(itr2->first);
- if(!plr)
- {
- sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
- continue;
- }
+// this method will check if we can invite players to same faction skirmish match
+bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
+{
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
+ return false;
+ uint32 teamIndex = BG_TEAM_ALLIANCE;
+ uint32 otherTeam = BG_TEAM_HORDE;
+ uint32 otherTeamId = HORDE;
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
+ {
+ teamIndex = BG_TEAM_HORDE;
+ otherTeam = BG_TEAM_ALLIANCE;
+ otherTeamId = ALLIANCE;
+ }
+ //clear other team's selection
+ m_SelectionPools[otherTeam].Init();
+ //store last ginfo pointer
+ GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
+ //set itr_team to group that was added to selection pool latest
+ GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
+ for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
+ if (ginfo == *itr_team)
+ break;
+ if (itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
+ return false;
+ GroupsQueueType::iterator itr_team2 = itr_team;
+ ++itr_team2;
+ //invite players to other selection pool
+ for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
+ {
+ //if selection pool is full then break;
+ if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
+ break;
+ }
+ if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
+ return false;
- // get the queueslot
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
- {
- plr->RemoveBattleGroundQueueId(bgQueueTypeId);
- // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
- RemovePlayer(itr2->first, true);
- // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups
- // but updating the queue can't hurt
- Update(bgQueueTypeId, bg->GetQueueType());
- // send info to client
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);
- plr->GetSession()->SendPacket(&data);
- }
+ //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
+ for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
+ {
+ //set correct team
+ (*itr)->Team = otherTeamId;
+ //add team to other queue
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
+ //remove team from old queue
+ GroupsQueueType::iterator itr2 = itr_team;
+ ++itr2;
+ for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
+ {
+ if (*itr2 == *itr)
+ {
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
+ break;
}
}
}
+ return true;
}
/*
this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
it must be called after fully adding the members of a group to ensure group joining
-should be called after removeplayer functions in some cases
+should be called from BattleGround::RemovePlayer function in some cases
*/
-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
+void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
{
- if (queue_id >= MAX_BATTLEGROUND_QUEUES)
- {
- //this is error, that caused crashes (not in , but now it shouldn't)
- sLog.outError("BattleGroundQueue::Update() called for non existing queue type - this can cause crash, pls report problem, if this is the last line of error log before crash");
- return;
- }
-
- //if no players in queue ... do nothing
- if (m_QueuedGroups[queue_id].empty())
+ //if no players in queue - do nothing
+ if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
return;
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
-
- //battleground with free slot for player should be always the last in this queue
+ //battleground with free slot for player should be always in the beggining of the queue
+ // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
BGFreeSlotQueueType::iterator itr, next;
for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
{
next = itr;
++next;
- // battleground is running, so if:
- // DO NOT allow queue manager to invite new player to running arena
- if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
+ // DO NOT allow queue manager to invite new player to arena
+ if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
+ (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
{
- //we must check both teams
BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
// and iterator is invalid
- for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
- {
- // did the group join for this bg type?
- if((*itr)->BgTypeId != bgTypeId)
- continue;
- // if so, check if fits in
- if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size())
- {
- // if group fits in, invite it
- InviteGroupToBG((*itr),bg,(*itr)->Team);
- }
- }
+ // clear selection pools
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
+
+ // call a function that does the job for us
+ FillPlayersToBG(bg, queue_id);
+
+ // now everything is set, invite players
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg, (*citr)->Team);
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg, (*citr)->Team);
if (!bg->HasFreeSlots())
{
- //remove BG from BGFreeSlotQueue
+ // remove BG from BGFreeSlotQueue
bg->RemoveFromBGFreeSlotQueue();
}
}
@@ -523,25 +776,29 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
// finished iterating through the bgs with free slots, maybe we need to create a new bg
BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- if(!bg_template)
+ if (!bg_template)
{
sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
return;
}
-
// get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
- if(bg_template->isArena())
+ if (sBattleGroundMgr.isTesting())
+ MinPlayersPerTeam = 1;
+ if (bg_template->isArena())
{
- if(sBattleGroundMgr.isArenaTesting())
+ if (sBattleGroundMgr.isArenaTesting())
{
MaxPlayersPerTeam = 1;
MinPlayersPerTeam = 1;
}
else
{
- switch(arenatype)
+ //this switch can be much shorter
+ MaxPlayersPerTeam = arenaType;
+ MinPlayersPerTeam = arenaType;
+ /*switch(arenaType)
{
case ARENA_TYPE_2v2:
MaxPlayersPerTeam = 2;
@@ -555,293 +812,192 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
MaxPlayersPerTeam = 5;
MinPlayersPerTeam = 5;
break;
- }
+ }*/
}
}
- // found out the minimum and maximum ratings the newly added team should battle against
- // arenaRating is the rating of the latest joined team
- uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
- // if no rating is specified, set maxrating to 0
- uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
- uint32 discardTime = 0;
- // if max rating difference is set and the time past since server startup is greater than the rating discard time
- // (after what time the ratings aren't taken into account when making teams) then
- // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
- // else leave the discard time on 0, this way all ratings will be discarded
- if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())
- discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
-
- // try to build the selection pools
- bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bAllyOK)
- sLog.outDebug("Battleground: ally pool successfully built");
- else
- sLog.outDebug("Battleground: ally pool wasn't created");
- bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bHordeOK)
- sLog.outDebug("Battleground: horde pool successfully built");
- else
- sLog.outDebug("Battleground: horde pool wasn't created");
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
- // if selection pools are ready, create the new bg
- if (bAllyOK && bHordeOK)
+ if (bg_template->isBattleGround())
{
- BattleGround * bg2 = 0;
- // special handling for arenas
- if(bg_template->isArena())
+ //check if there is premade against premade match
+ if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam))
{
- // Find a random arena, that can be created
- uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
- uint32 arena_num = urand(0,2);
- if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
+ //create new battleground
+ BattleGround * bg2 = NULL;
+ if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)))
{
- sLog.outError("Battleground: couldn't create any arena instance!");
+ sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
return;
}
-
- // set the MaxPlayersPerTeam values based on arenatype
- // setting the min player values isn't needed, since we won't be using that value later on.
- if(sBattleGroundMgr.isArenaTesting())
- {
- bg2->SetMaxPlayersPerTeam(1);
- bg2->SetMaxPlayers(2);
- }
- else
- {
- switch(arenatype)
- {
- case ARENA_TYPE_2v2:
- bg2->SetMaxPlayersPerTeam(2);
- bg2->SetMaxPlayers(4);
- break;
- case ARENA_TYPE_3v3:
- bg2->SetMaxPlayersPerTeam(3);
- bg2->SetMaxPlayers(6);
- break;
- case ARENA_TYPE_5v5:
- bg2->SetMaxPlayersPerTeam(5);
- bg2->SetMaxPlayers(10);
- break;
- default:
- break;
- }
- }
- }
- else
- {
- // create new battleground
- bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);
- }
-
- if(!bg2)
- {
- sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
- return;
- }
-
- // start the joining of the bg
- bg2->SetStatus(STATUS_WAIT_JOIN);
- bg2->SetQueueType(queue_id);
- // initialize arena / rating info
- bg2->SetArenaType(arenatype);
- // set rating
- bg2->SetRated(isRated);
-
- std::list<GroupQueueInfo* >::iterator itr;
-
- // Send amount of invites based on the difference between the sizes of the two faction's queues
- uint32 QUEUED_HORDE = m_SelectionPools[NORMAL_HORDE].SelectedGroups.size();
- uint32 QUEUED_ALLIANCE = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.size();
- uint16 maxbginvites = 0;
-
- if(QUEUED_ALLIANCE <= QUEUED_HORDE)
- maxbginvites = QUEUED_ALLIANCE;
- else
- maxbginvites = QUEUED_HORDE;
-
- // invite groups from horde selection pool
- uint16 invitecounter = 0;
- for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
- {
- if (invitecounter >= maxbginvites)
- return;
- InviteGroupToBG((*itr),bg2,HORDE);
- ++invitecounter;
- }
-
- // invite groups from ally selection pool
- invitecounter = 0;
- for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
- {
- if (invitecounter >= maxbginvites)
- return;
- InviteGroupToBG((*itr),bg2,ALLIANCE);
- ++invitecounter;
- }
-
- if (isRated)
- {
- std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin();
- std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin();
- (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
- sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_alliance)->ArenaTeamId, (*itr_alliance)->OpponentsTeamRating);
- (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
- sLog.outDebug("setting opposite team rating for team %u to %u", (*itr_horde)->ArenaTeamId, (*itr_horde)->OpponentsTeamRating);
+ //invite those selection pools
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg2, (*citr)->Team);
+ //start bg
+ bg2->StartBattleGround();
+ //clear structures
+ m_SelectionPools[BG_TEAM_ALLIANCE].Init();
+ m_SelectionPools[BG_TEAM_HORDE].Init();
}
-
- // start the battleground
- bg2->StartBattleGround();
}
- // there weren't enough players for a "normal" match
- // if arena, enable horde versus horde or alliance versus alliance teams here
-
- else if(bg_template->isArena())
+ // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
+ if (!isRated)
{
- bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;
- bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;
- bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bOneSideHordeTeam1)
+ // if there are enough players in pools, start new battleground or non rated arena
+ if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
+ || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
{
- // one team has been selected, find out if other can be selected too
- std::list<GroupQueueInfo* >::iterator itr;
- // temporarily change the team side to enable building the next pool excluding the already selected groups
- for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=ALLIANCE;
-
- bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime, (*(m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
-
- // change back the team to horde
- for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=HORDE;
-
- if(!bOneSideHordeTeam2)
- bOneSideHordeTeam1 = false;
- }
- if(!bOneSideHordeTeam1)
- {
- // check for one sided ally
- bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);
- if(bOneSideAllyTeam1)
+ // we successfully created a pool
+ BattleGround * bg2 = NULL;
+ if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)))
{
- // one team has been selected, find out if other can be selected too
- std::list<GroupQueueInfo* >::iterator itr;
- // temporarily change the team side to enable building the next pool excluding the already selected groups
- for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=HORDE;
-
- bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime,(*(m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin()))->ArenaTeamId);
-
- // change back the team to ally
- for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)
- (*itr)->Team=ALLIANCE;
+ sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
+ return;
}
- if(!bOneSideAllyTeam2)
- bOneSideAllyTeam1 = false;
+ // invite those selection pools
+ for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
+ for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
+ InviteGroupToBG((*citr), bg2, (*citr)->Team);
+ // start bg
+ bg2->StartBattleGround();
}
- // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
- if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
- (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
+ }
+ else if (bg_template->isArena())
+ {
+ // found out the minimum and maximum ratings the newly added team should battle against
+ // arenaRating is the rating of the latest joined team, or 0
+ // 0 is on (automatic update call) and we must set it to team's with longest wait time
+ if (!arenaRating )
{
- // which side has enough players?
- uint32 side = 0;
- SelectionPoolBuildMode mode1, mode2;
- // find out what pools are we using
- if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
+ GroupQueueInfo* front1 = NULL;
+ GroupQueueInfo* front2 = NULL;
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
{
- side = ALLIANCE;
- mode1 = ONESIDE_ALLIANCE_TEAM1;
- mode2 = ONESIDE_ALLIANCE_TEAM2;
+ front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
+ arenaRating = front1->ArenaTeamRating;
}
- else
+ if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
{
- side = HORDE;
- mode1 = ONESIDE_HORDE_TEAM1;
- mode2 = ONESIDE_HORDE_TEAM2;
+ front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
+ arenaRating = front2->ArenaTeamRating;
}
-
- // create random arena
- uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
- uint32 arena_num = urand(0,2);
- BattleGround* bg2 = NULL;
- if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&
- !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )
+ if (front1 && front2)
{
- sLog.outError("Could not create arena.");
- return;
+ if (front1->JoinTime < front2->JoinTime)
+ arenaRating = front1->ArenaTeamRating;
}
+ else if (!front1 && !front2)
+ return; //queues are empty
+ }
+
+ //set rating range
+ uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
+ uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
+ // if max rating difference is set and the time past since server startup is greater than the rating discard time
+ // (after what time the ratings aren't taken into account when making teams) then
+ // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
+ // else leave the discard time on 0, this way all ratings will be discarded
+ uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
+
+ // we need to find 2 teams which will play next game
+
+ GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
- sLog.outDebug("Battleground: One-faction arena created.");
- // init stats
- if(sBattleGroundMgr.isArenaTesting())
+ //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
+
+ for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
+ {
+ // take the group that joined first
+ itr_team[i] = m_QueuedGroups[queue_id][i].begin();
+ for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
{
- bg2->SetMaxPlayersPerTeam(1);
- bg2->SetMaxPlayers(2);
+ // if group match conditions, then add it to pool
+ if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[i])->JoinTime < discardTime) )
+ {
+ m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
+ // break for cycle to be able to start selecting another group from same faction queue
+ break;
+ }
}
- else
+ }
+ // now we are done if we have 2 groups - ali vs horde!
+ // if we don't have, we must try to continue search in same queue
+ // tmp variables are correctly set
+ // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
+ ++itr_team[BG_TEAM_ALLIANCE];
+ for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
{
- switch(arenatype)
+ if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
{
- case ARENA_TYPE_2v2:
- bg2->SetMaxPlayersPerTeam(2);
- bg2->SetMaxPlayers(4);
- break;
- case ARENA_TYPE_3v3:
- bg2->SetMaxPlayersPerTeam(3);
- bg2->SetMaxPlayers(6);
+ m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
break;
- case ARENA_TYPE_5v5:
- bg2->SetMaxPlayersPerTeam(5);
- bg2->SetMaxPlayers(10);
- break;
- default:
+ }
+ }
+ }
+ // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
+ if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
+ {
+ itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
+ ++itr_team[BG_TEAM_HORDE];
+ for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
+ {
+ if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
+ && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
+ || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
+ {
+ m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
break;
}
}
+ }
- bg2->SetRated(isRated);
-
- // assigned team of the other group
- uint32 other_side;
- if(side == ALLIANCE)
- other_side = HORDE;
- else
- other_side = ALLIANCE;
-
- // start the joining of the bg
- bg2->SetStatus(STATUS_WAIT_JOIN);
- bg2->SetQueueType(queue_id);
- // initialize arena / rating info
- bg2->SetArenaType(arenatype);
-
- std::list<GroupQueueInfo* >::iterator itr;
-
- // invite players from the first group as horde players (actually green team)
- for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)
+ //if we have 2 teams, then start new arena and invite players!
+ if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
+ {
+ BattleGround* arena = NULL;
+ if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)))
{
- InviteGroupToBG((*itr),bg2,HORDE);
+ sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
+ return;
}
- // invite players from the second group as ally players (actually gold team)
- for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)
+ (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
+ sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
+ (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
+ sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
+ // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
+ if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
{
- InviteGroupToBG((*itr),bg2,ALLIANCE);
+ // add to alliance queue
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
+ // erase from horde queue
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
+ itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
}
-
- if (isRated)
+ if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
{
- std::list<GroupQueueInfo* >::iterator itr_alliance = m_SelectionPools[mode1].SelectedGroups.begin();
- std::list<GroupQueueInfo* >::iterator itr_horde = m_SelectionPools[mode2].SelectedGroups.begin();
- (*itr_alliance)->OpponentsTeamRating = (*itr_horde)->ArenaTeamRating;
- (*itr_horde)->OpponentsTeamRating = (*itr_alliance)->ArenaTeamRating;
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
+ m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
+ itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
}
- bg2->StartBattleGround();
+ InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
+ InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
+
+ sLog.outDebug("Starting rated arena match!");
+
+ arena->StartBattleGround();
}
}
}
@@ -853,36 +1009,29 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype
bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
-
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
if (!plr)
return true;
- // Player can be in another BG queue and must be removed in normal way in any case
- // // player is already in battleground ... do nothing (battleground queue status is deleted when player is teleported to BG)
- // if (plr->GetBattleGroundId() > 0)
- // return true;
-
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
+ //if battleground ended and its instance deleted - do nothing
if (!bg)
return true;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+ if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground
{
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ // check if player is invited to this bg
+ BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
+ if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
+ && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{
- // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
- BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
- if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
- {
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
- plr->GetSession()->SendPacket(&data);
- }
+ WorldPacket data;
+ //we must send remaining time in queue
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
+ plr->GetSession()->SendPacket(&data);
}
}
return true; //event will be deleted
@@ -890,10 +1039,18 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
{
- //this should not be called
- sLog.outError("Battleground invite event ABORTED!");
+ //do nothing
}
+/*
+ this event has many possibilities when it is executed:
+ 1. player is in battleground ( he clicked enter on invitation window )
+ 2. player left battleground queue and he isn't there any more
+ 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
+ 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
+ 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
+ we must remove player in the 5. case even if battleground object doesn't exist!
+*/
bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
Player* plr = objmgr.GetPlayer( m_PlayerGuid );
@@ -901,40 +1058,33 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
// player logged off (we should do nothing, he is correctly removed from queue in another procedure)
return true;
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID);
- if (!bg)
- return true;
-
- sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
+ //battleground can be deleted already when we are removing queue info
+ //bg pointer can be NULL! so use it carefully!
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
+ if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground
{
- // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
- BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid);
- if (qMapItr != sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ // check if player is in queue for this BG and if we are removing his invite event
+ BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers;
+ BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
+ if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo
+ && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
+ && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
{
- if (qMapItr->second.GroupInfo->IsRated)
- {
- ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId);
- if (at)
- {
- sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating);
- at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating);
- at->SaveToDB();
- }
- }
- plr->RemoveBattleGroundQueueId(bgQueueTypeId);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
+ sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
+
+ plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
+ //update queues if battleground isn't ended
+ if (bg)
+ sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].Update(m_BgTypeId, bg->GetQueueId());
+
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
- else
- sLog.outDebug("Battleground: Player was already removed from queue");
//event will be deleted
return true;
@@ -942,82 +1092,104 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
{
- //this should not be called
- sLog.outError("Battleground remove event ABORTED!");
+ //do nothing
}
/*********************************************************/
/*** BATTLEGROUND MANAGER ***/
/*********************************************************/
-BattleGroundMgr::BattleGroundMgr()
+BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
{
- m_BattleGrounds.clear();
- m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);
- m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
- m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
- m_PrematureFinishTimer = sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
- m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
- m_AutoDistributionTimeChecker = 0;
- m_ArenaTesting = false;
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
+ m_BattleGrounds[i].clear();
+ m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
+ m_Testing=false;
}
BattleGroundMgr::~BattleGroundMgr()
{
- BattleGroundSet::iterator itr, next;
- for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ DeleteAllBattleGrounds();
+}
+
+void BattleGroundMgr::DeleteAllBattleGrounds()
+{
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- next = itr;
- ++next;
- BattleGround * bg = itr->second;
- m_BattleGrounds.erase(itr);
- delete bg;
+ for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
+ {
+ BattleGround * bg = itr->second;
+ m_BattleGrounds[i].erase(itr++);
+ if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
+ m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
+ delete bg;
+ }
+ }
+
+ // destroy template battlegrounds that listed only in queues (other already terminated)
+ for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
+ {
+ // ~BattleGround call unregistring BG from queue
+ while(!BGFreeSlotQueue[bgTypeId].empty())
+ delete BGFreeSlotQueue[bgTypeId].front();
}
- m_BattleGrounds.clear();
}
// used to update running battlegrounds, and delete finished ones
-void BattleGroundMgr::Update(time_t diff)
+void BattleGroundMgr::Update(uint32 diff)
{
BattleGroundSet::iterator itr, next;
- for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- next = itr;
- ++next;
- itr->second->Update(diff);
- // use the SetDeleteThis variable
- // direct deletion caused crashes
- if(itr->second->m_SetDeleteThis)
+ itr = m_BattleGrounds[i].begin();
+ // skip updating battleground template
+ if (itr != m_BattleGrounds[i].end())
+ ++itr;
+ for(; itr != m_BattleGrounds[i].end(); itr = next)
{
- BattleGround * bg = itr->second;
- m_BattleGrounds.erase(itr);
- delete bg;
+ next = itr;
+ ++next;
+ itr->second->Update(diff);
+ // use the SetDeleteThis variable
+ // direct deletion caused crashes
+ if (itr->second->m_SetDeleteThis)
+ {
+ BattleGround * bg = itr->second;
+ m_BattleGrounds[i].erase(itr);
+ if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
+ m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
+ delete bg;
+ }
}
}
// if rating difference counts, maybe force-update queues
- if(m_MaxRatingDifference)
+ if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
{
// it's time to force update
- if(m_NextRatingDiscardUpdate < diff)
+ if (m_NextRatingDiscardUpdate < diff)
{
// forced update for level 70 rated arenas
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);
- m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);
- m_NextRatingDiscardUpdate = m_RatingDiscardTimer;
+ sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
+ m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
}
else
m_NextRatingDiscardUpdate -= diff;
}
- if(m_AutoDistributePoints)
+ if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
{
- if(m_AutoDistributionTimeChecker < diff)
+ if (m_AutoDistributionTimeChecker < diff)
{
if(time(NULL) > m_NextAutoDistributionTime)
{
DistributeArenaPoints();
m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
- CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
+ CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", m_NextAutoDistributionTime);
}
m_AutoDistributionTimeChecker = 600000; // check 10 minutes
}
@@ -1026,10 +1198,11 @@ void BattleGroundMgr::Update(time_t diff)
}
}
-void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
{
// we can be in 3 queues in same time...
- if(StatusID == 0)
+
+ if (StatusID == 0 || !bg)
{
data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
*data << uint32(QueueSlot); // queue id (0...2)
@@ -1040,10 +1213,11 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
*data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
// uint64 in client
- *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
- *data << uint32(0); // unknown
+ *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
+ *data << uint32(bg->GetClientInstanceID());
// alliance/horde for BG and skirmish/rated for Arenas
- *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
+ // following displays the minimap-icon 0 = faction icon 1 = arenaicon
+ *data << uint8(bg->isRated());
/* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
switch(bg->GetTypeID()) // value depends on bg id
{
@@ -1071,12 +1245,21 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
case BATTLEGROUND_RL:
*data << uint8(8);
break;
+ case BATTLEGROUND_SA:
+ *data << uint8(9);
+ break;
+ case BATTLEGROUND_DS:
+ *data << uint8(10);
+ break;
+ case BATTLEGROUND_RV:
+ *data << uint8(11);
+ break;
default: // unknown
*data << uint8(0);
break;
}
- if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
+ if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
*data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
else
*data << uint32(bg->GetTypeID()); // BG id from DBC
@@ -1084,17 +1267,14 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
*data << uint16(0x1F90); // unk value 8080
*data << uint32(bg->GetInstanceID()); // instance id
- if(bg->isBattleGround())
- *data << uint8(bg->GetTeamIndexByTeamId(team)); // team
- else
- *data << uint8(israted?israted:bg->isRated()); // is rated battle
+ *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
*/
*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?
+ *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
break;
case STATUS_WAIT_JOIN: // status_invite
*data << uint32(bg->GetMapId()); // map id
@@ -1102,7 +1282,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
break;
case STATUS_IN_PROGRESS: // status_in_progress
*data << uint32(bg->GetMapId()); // map id
- *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
+ *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(0x1); // unk sometimes 0x0!
break;
@@ -1115,33 +1295,34 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro
void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
uint8 type = (bg->isArena() ? 1 : 0);
- // last check on 2.4.1
+ // last check on 3.0.3
data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
- *data << uint8(type); // seems to be type (battleground=0/arena=1)
+ *data << uint8(type); // type (battleground=0/arena=1)
if(type) // arena
{
// it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
for(int i = 1; i >= 0; --i)
{
- *data << uint32(3000-bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000
- *data << uint32(3999); // huge thanks for TOM_RUS for this!
+ *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
+ *data << uint32(3999); // huge thanks for TOM_RUS for this!
+ *data << uint32(0); // added again in 3.1
sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
}
for(int i = 1; i >= 0; --i)
{
uint32 at_id = bg->m_ArenaTeamIds[i];
ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
- if(at)
+ if (at)
*data << at->GetName();
- else//*/
+ else
*data << (uint8)0;
}
}
- if(bg->GetWinner() == 2)
+ if (bg->GetStatus() != STATUS_WAIT_LEAVE)
{
- *data << uint8(0); // bg in progress
+ *data << uint8(0); // bg not ended
}
else
{
@@ -1155,10 +1336,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
*data << (uint64)itr->first;
*data << (int32)itr->second->KillingBlows;
- Player *plr = objmgr.GetPlayer(itr->first);
- uint32 team = bg->GetPlayerTeam(itr->first);
- if(!team && plr) team = plr->GetTeam();
- if(type == 0)
+ if (type == 0)
{
*data << (int32)itr->second->HonorableKills;
*data << (int32)itr->second->Deaths;
@@ -1166,18 +1344,12 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
}
else
{
- // that part probably wrong
- if(plr)
- {
- if(team == HORDE)
- *data << uint8(0);
- else if(team == ALLIANCE)
- {
- *data << uint8(1);
- }
- else
- *data << uint8(0);
- }
+ Player *plr = objmgr.GetPlayer(itr->first);
+ uint32 team = bg->GetPlayerTeam(itr->first);
+ if (!team && plr)
+ team = plr->GetTeam();
+ if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
+ *data << uint8(1);
else
*data << uint8(0);
}
@@ -1204,13 +1376,16 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
*data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
break;
case BATTLEGROUND_EY:
- *data << (uint32)0x00000001; // count of next fields
+ *data << (uint32)0x00000001; // count of next fields
*data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
break;
case BATTLEGROUND_NA:
case BATTLEGROUND_BE:
case BATTLEGROUND_AA:
case BATTLEGROUND_RL:
+ case BATTLEGROUND_SA: // wotlk
+ case BATTLEGROUND_DS: // wotlk
+ case BATTLEGROUND_RV: // wotlk
*data << (int32)0; // 0
break;
default:
@@ -1221,7 +1396,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
}
}
-void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId)
+void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
{
/*bgTypeId is:
0 - Your group has joined a battleground queue, but you are not eligible
@@ -1249,10 +1424,10 @@ void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
*data << uint32(soundid);
}
-void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr)
+void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
{
data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
- *data << uint64(plr->GetGUID());
+ *data << uint64(guid);
}
void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
@@ -1261,62 +1436,97 @@ void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Pla
*data << uint64(plr->GetGUID());
}
-void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
+BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
{
- // set invited player counters:
- BattleGround* bg = GetBattleGround(bgInstanceGUID);
- if(!bg)
- return;
- bg->IncreaseInvitedCount(team);
+ //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;
- plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
+ if (bg->isArena())
+ return GetBattleGround(instanceId, bgTypeId);
+
+ for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
+ {
+ if (itr->second->GetClientInstanceID() == instanceId)
+ return itr->second;
+ }
+ return NULL;
+}
- // set the arena teams for rated matches
- if(bg->isArena() && bg->isRated())
+BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
+{
+ //search if needed
+ BattleGroundSet::iterator itr;
+ if (bgTypeId == BATTLEGROUND_TYPE_NONE)
{
- switch(bg->GetArenaType())
+ for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
{
- case ARENA_TYPE_2v2:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
- break;
- case ARENA_TYPE_3v3:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
- break;
- case ARENA_TYPE_5v5:
- bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
- break;
- default:
- break;
+ itr = m_BattleGrounds[i].find(InstanceID);
+ if (itr != m_BattleGrounds[i].end())
+ return itr->second;
}
+ return NULL;
}
+ itr = m_BattleGrounds[bgTypeId].find(InstanceID);
+ return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
+}
- // create invite events:
- //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
- BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID);
- plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME/2));
- BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
- plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
+BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
+{
+ //map is sorted and we can be sure that lowest instance id has only BG template
+ return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
}
-BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)
+uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
{
- return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
+ 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
+ uint32 lastId = 0;
+ for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
+ {
+ if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
+ break;
+ lastId = *itr;
+ }
+ m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
+ return lastId + 1;
}
// create a new battleground that will really be used to play
-BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
+BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
{
- BattleGround *bg = NULL;
-
// get the template BG
BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
-
- if(!bg_template)
+ if (!bg_template)
{
sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
- return 0;
+ return NULL;
}
+ //for arenas there is random map used
+ if (bg_template->isArena())
+ {
+ BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
+ uint32 arena_num = urand(0,2);
+ bgTypeId = arenas[arena_num];
+ bg_template = GetBattleGroundTemplate(bgTypeId);
+ if (!bg_template)
+ {
+ sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
+ return NULL;
+ }
+ }
+
+ BattleGround *bg = NULL;
// create a copy of the BG template
switch(bgTypeId)
{
@@ -1344,42 +1554,47 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
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;
default:
- //bg = new BattleGround;
+ //error, but it is handled few lines above
return 0;
- break; // placeholder for non implemented BG
}
// generate a new instance id
bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
+ bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
// reset the new bg (set status to status_wait_queue from status_none)
bg->Reset();
- /* will be setup in BG::Update() when the first player is ported in
- if(!(bg->SetupBattleGround()))
- {
- sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);
- delete bg;
- return 0;
- }
- */
+ // start the joining of the bg
+ bg->SetStatus(STATUS_WAIT_JOIN);
+ bg->SetQueueId(queue_id);
+ bg->SetArenaType(arenaType);
+ bg->SetRated(isRated);
// add BG to free slot queue
bg->AddToBGFreeSlotQueue();
// add bg to update list
- AddBattleGround(bg->GetInstanceID(), bg);
+ AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
return bg;
}
// used to create the BG templates
-uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
+uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
{
// Create the BG
BattleGround *bg = NULL;
-
switch(bgTypeId)
{
case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
@@ -1390,35 +1605,27 @@ uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPer
case BATTLEGROUND_AA: bg = new BattleGroundAA; 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;
default:bg = new BattleGround; break; // placeholder for non implemented BG
}
bg->SetMapId(MapID);
-
- bg->Reset();
-
- BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
- //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
- if (bl)
- {
- bg->SetArenaorBGType(bl->type == TYPE_ARENA);
- }
-
bg->SetTypeID(bgTypeId);
- bg->SetInstanceID(0); // template bg, instance id is 0
+ bg->SetInstanceID(0);
+ bg->SetArenaorBGType(IsArena);
bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
- bg->SetMinPlayers(MinPlayersPerTeam*2);
- bg->SetMaxPlayers(MaxPlayersPerTeam*2);
+ bg->SetMinPlayers(MinPlayersPerTeam * 2);
+ bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
bg->SetName(BattleGroundName);
bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
bg->SetLevelRange(LevelMin, LevelMax);
- //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
- bg->AddToBGFreeSlotQueue();
-
- // do NOT add to update list, since this is a template battleground!
+ // add bg to update list
+ AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
// return some not-null value, bgTypeId is good enough for me
return bgTypeId;
@@ -1431,13 +1638,14 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
BattlemasterListEntry const *bl;
WorldSafeLocsEntry const *start;
+ bool IsArena;
uint32 count = 0;
// 0 1 2 3 4 5 6 7 8
QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
- if(!result)
+ if (!result)
{
barGoLink bar(1);
@@ -1455,44 +1663,46 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
Field *fields = result->Fetch();
bar.step();
- uint32 bgTypeID = fields[0].GetUInt32();
+ uint32 bgTypeID_ = fields[0].GetUInt32();
- // can be overwrited by values from DB
- bl = sBattlemasterListStore.LookupEntry(bgTypeID);
- if(!bl)
+ // can be overwrite by values from DB
+ bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
+ if (!bl)
{
- sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.",bgTypeID);
+ sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
continue;
}
- MaxPlayersPerTeam = bl->maxplayersperteam;
- MinPlayersPerTeam = bl->maxplayersperteam/2;
- MinLvl = bl->minlvl;
- MaxLvl = bl->maxlvl;
-
- if(fields[1].GetUInt32())
- MinPlayersPerTeam = fields[1].GetUInt32();
-
- if(fields[2].GetUInt32())
- MaxPlayersPerTeam = fields[2].GetUInt32();
+ BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
- if(fields[3].GetUInt32())
- MinLvl = fields[3].GetUInt32();
-
- if(fields[4].GetUInt32())
- MaxLvl = fields[4].GetUInt32();
+ IsArena = (bl->type == TYPE_ARENA);
+ MinPlayersPerTeam = fields[1].GetUInt32();
+ MaxPlayersPerTeam = fields[2].GetUInt32();
+ MinLvl = fields[3].GetUInt32();
+ MaxLvl = fields[4].GetUInt32();
+ //check values from DB
+ if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
+ {
+ MaxPlayersPerTeam = bl->maxplayersperteam;
+ MinPlayersPerTeam = bl->maxplayersperteam / 2;
+ }
+ if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
+ {
+ MinLvl = bl->minlvl;
+ MaxLvl = bl->maxlvl;
+ }
start1 = fields[5].GetUInt32();
start = sWorldSafeLocsStore.LookupEntry(start1);
- if(start)
+ if (start)
{
AStartLoc[0] = start->x;
AStartLoc[1] = start->y;
AStartLoc[2] = start->z;
AStartLoc[3] = fields[6].GetFloat();
}
- else if(bgTypeID == BATTLEGROUND_AA)
+ else if (bgTypeID == BATTLEGROUND_AA)
{
AStartLoc[0] = 0;
AStartLoc[1] = 0;
@@ -1501,21 +1711,21 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
}
else
{
- sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.",bgTypeID,start1);
+ sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
continue;
}
start2 = fields[7].GetUInt32();
start = sWorldSafeLocsStore.LookupEntry(start2);
- if(start)
+ if (start)
{
HStartLoc[0] = start->x;
HStartLoc[1] = start->y;
HStartLoc[2] = start->z;
HStartLoc[3] = fields[8].GetFloat();
}
- else if(bgTypeID == BATTLEGROUND_AA)
+ else if (bgTypeID == BATTLEGROUND_AA)
{
HStartLoc[0] = 0;
HStartLoc[1] = 0;
@@ -1524,12 +1734,12 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
}
else
{
- sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.",bgTypeID,start2);
+ sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
continue;
}
//sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
- if(!CreateBattleGround(bgTypeID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
+ if (!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
continue;
++count;
@@ -1543,19 +1753,19 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
void BattleGroundMgr::InitAutomaticArenaPointDistribution()
{
- if(m_AutoDistributePoints)
+ if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
{
sLog.outDebug("Initializing Automatic Arena Point Distribution");
QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
- if(!result)
+ if (!result)
{
sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
- CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
+ CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", m_NextAutoDistributionTime);
}
else
{
- m_NextAutoDistributionTime = (*result)[0].GetUInt64();
+ m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
delete result;
}
sLog.outDebug("Automatic Arena Point Distribution initialized.");
@@ -1565,9 +1775,9 @@ void BattleGroundMgr::InitAutomaticArenaPointDistribution()
void BattleGroundMgr::DistributeArenaPoints()
{
// used to distribute arena points based on last week's stats
- sWorld.SendGlobalText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
- sWorld.SendGlobalText("Distributing arena points to players...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
//temporary structure for storing maximum points to add values for all players
std::map<uint32, uint32> PlayerPoints;
@@ -1575,7 +1785,7 @@ void BattleGroundMgr::DistributeArenaPoints()
//at first update all points for all team members
for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
{
- if(ArenaTeam * at = team_itr->second)
+ if (ArenaTeam * at = team_itr->second)
{
at->UpdateArenaPointsHelper(PlayerPoints);
}
@@ -1585,7 +1795,7 @@ void BattleGroundMgr::DistributeArenaPoints()
for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
{
//update to database
- CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first);
+ CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
//add points if player is online
Player* pl = objmgr.GetPlayer(plr_itr->first);
if (pl)
@@ -1594,12 +1804,12 @@ void BattleGroundMgr::DistributeArenaPoints()
PlayerPoints.clear();
- sWorld.SendGlobalText("Finished setting arena points for online players.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
- sWorld.SendGlobalText("Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
{
- if(ArenaTeam * at = titr->second)
+ if (ArenaTeam * at = titr->second)
{
at->FinishWeek(); // set played this week etc values to 0 in memory, too
at->SaveToDB(); // save changes
@@ -1607,55 +1817,55 @@ void BattleGroundMgr::DistributeArenaPoints()
}
}
- sWorld.SendGlobalText("Modification done.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
- sWorld.SendGlobalText("Done flushing Arena points.", NULL);
+ sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
}
-void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
+void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
{
- uint32 PlayerLevel = 10;
+ if (!plr)
+ return;
- if(plr)
- PlayerLevel = plr->getLevel();
+ uint32 PlayerLevel = 10;
+ PlayerLevel = plr->getLevel();
data->Initialize(SMSG_BATTLEFIELD_LIST);
*data << uint64(guid); // battlemaster guid
+ *data << uint8(fromWhere); // from where you joined
*data << uint32(bgTypeId); // battleground id
if(bgTypeId == BATTLEGROUND_AA) // arena
{
- *data << uint8(5); // unk
- *data << uint32(0); // unk
+ *data << uint8(4); // unk
+ *data << uint32(0); // unk (count?)
}
else // battleground
{
- *data << uint8(0x00); // unk
+ *data << uint8(0x00); // unk, different for each bg type
size_t count_pos = data->wpos();
uint32 count = 0;
*data << uint32(0x00); // number of bg instances
- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
+ uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
+ for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
{
- if(itr->second->GetTypeID() == bgTypeId && (PlayerLevel >= itr->second->GetMinLevel()) && (PlayerLevel <= itr->second->GetMaxLevel()))
- {
- *data << uint32(itr->second->GetInstanceID());
- ++count;
- }
+ *data << uint32(*itr);
+ ++count;
}
data->put<uint32>( count_pos , count);
}
}
-void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
{
- BattleGround *bg = GetBattleGround(instanceId);
- if(bg)
+ BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
+ if (bg)
{
uint32 mapid = bg->GetMapId();
float x, y, z, O;
uint32 team = pl->GetBGTeam();
- if(team==0)
+ if (team==0)
team = pl->GetTeam();
bg->GetTeamStartLoc(team, x, y, z, O);
@@ -1668,24 +1878,17 @@ void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
}
}
-void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
+void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
{
WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
- if(time_ == uint32(-1))
+ if (time_ == uint32(-1))
time_ = 0;
data << guid << time_;
pl->GetSession()->SendPacket(&data);
}
-void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)
-{
- BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);
- if(itr!=m_BattleGrounds.end())
- m_BattleGrounds.erase(itr);
-}
-
-bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
+bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
{
return ( bgTypeId == BATTLEGROUND_AA ||
bgTypeId == BATTLEGROUND_BE ||
@@ -1693,96 +1896,169 @@ bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const
bgTypeId == BATTLEGROUND_RL );
}
-bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const
-{
- return !IsArenaType(bgTypeId);
-}
-
-uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const
+BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
{
switch(bgTypeId)
{
- case BATTLEGROUND_WS:
- return BATTLEGROUND_QUEUE_WS;
- case BATTLEGROUND_AB:
- return BATTLEGROUND_QUEUE_AB;
- case BATTLEGROUND_AV:
- return BATTLEGROUND_QUEUE_AV;
- case BATTLEGROUND_EY:
- return BATTLEGROUND_QUEUE_EY;
- case BATTLEGROUND_AA:
- case BATTLEGROUND_NA:
- case BATTLEGROUND_RL:
- case BATTLEGROUND_BE:
- 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;
+ case BATTLEGROUND_WS:
+ return BATTLEGROUND_QUEUE_WS;
+ case BATTLEGROUND_AB:
+ return BATTLEGROUND_QUEUE_AB;
+ case BATTLEGROUND_AV:
+ return BATTLEGROUND_QUEUE_AV;
+ case BATTLEGROUND_EY:
+ return BATTLEGROUND_QUEUE_EY;
+ case BATTLEGROUND_SA:
+ return BATTLEGROUND_QUEUE_SA;
+ case BATTLEGROUND_AA:
+ case BATTLEGROUND_NA:
+ case BATTLEGROUND_RL:
+ case BATTLEGROUND_BE:
+ case BATTLEGROUND_DS:
+ 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 0;
- }
- default:
- return 0;
+ return BATTLEGROUND_QUEUE_NONE;
}
}
-uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const
+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_2v2:
- case BATTLEGROUND_QUEUE_3v3:
- case BATTLEGROUND_QUEUE_5v5:
- return BATTLEGROUND_AA;
- default:
- return 0;
+ 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_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(uint32 bgQueueTypeId) const
+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;
+ 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;
+ if (m_Testing)
+ sWorld.SendWorldText(LANG_DEBUG_BG_ON);
+ else
+ sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
+}
+
void BattleGroundMgr::ToggleArenaTesting()
{
m_ArenaTesting = !m_ArenaTesting;
- if(m_ArenaTesting)
- sWorld.SendGlobalText("Arenas are set to 1v1 for debugging. So, don't join as group.", NULL);
+ if (m_ArenaTesting)
+ sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
else
- sWorld.SendGlobalText("Arenas are set to normal playercount.", NULL);
+ sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
}
void BattleGroundMgr::SetHolidayWeekends(uint32 mask)
{
- for(uint32 bgtype = 1; bgtype <= 8; ++bgtype)
+ for(uint32 bgtype = 1; bgtype < MAX_BATTLEGROUND_TYPE_ID; ++bgtype)
{
- if(BattleGround * bg = GetBattleGroundTemplate(bgtype))
+ if(BattleGround * bg = GetBattleGroundTemplate(BattleGroundTypeId(bgtype)))
{
bg->SetHoliday(mask & (1 << bgtype));
}
}
}
+uint32 BattleGroundMgr::GetMaxRatingDifference() const
+{
+ // this is for stupid people who can't use brain and set max rating difference to 0
+ uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
+ if (diff == 0)
+ diff = 5000;
+ return diff;
+}
+
+uint32 BattleGroundMgr::GetRatingDiscardTimer() const
+{
+ return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
+}
+
+uint32 BattleGroundMgr::GetPrematureFinishTime() const
+{
+ return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
+}
+
+void BattleGroundMgr::LoadBattleMastersEntry()
+{
+ mBattleMastersMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint32 bgTypeId = fields[1].GetUInt32();
+ if (!sBattlemasterListStore.LookupEntry(bgTypeId))
+ {
+ sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
+ continue;
+ }
+
+ mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
+
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u battlemaster entries", count );
+}