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.cpp1401
1 files changed, 1159 insertions, 242 deletions
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index 52dad08345b..c21a79535a3 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -30,9 +30,12 @@
#include "SharedDefines.h"
#include "Policies/SingletonImp.h"
#include "MapManager.h"
+#include "Map.h"
+#include "MapInstanced.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "World.h"
+#include "ArenaTeam.h"
#include "Chat.h"
INSTANTIATE_SINGLETON_1( BattleGroundMgr );
@@ -44,12 +47,12 @@ 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++)
+/* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
- m_QueuedPlayers[i].Horde = 0;
- m_QueuedPlayers[i].Alliance = 0;
+ //m_QueuedPlayers[i].Horde = 0;
+ //m_QueuedPlayers[i].Alliance = 0;
//m_QueuedPlayers[i].AverageTime = 0;
- }
+ }*/
}
BattleGroundQueue::~BattleGroundQueue()
@@ -57,61 +60,190 @@ BattleGroundQueue::~BattleGroundQueue()
for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
{
m_QueuedPlayers[i].clear();
+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)
+ {
+ delete (*itr);
+ }
+ m_QueuedGroups[i].clear();
}
}
-void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId)
+// 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)
{
- uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
+ // clear from prev initialization
+ clear();
+ BattleGroundQueue::QueuedGroupsList::iterator itr, next;
+ // iterate through the source
+ for(itr = source->begin(); itr!= source->end(); itr = next)
+ {
+ 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)
+ ( (*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 ) ) )
+ {
+ // the group matches the conditions
+ // insert it in order of groupsize, and join time
+ uint32 size = (*itr)->Players.size();
+ uint32 jointime = (*itr)->JoinTime;
+ bool inserted = false;
- //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.IsInvitedToBGInstanceGUID = 0;
- info.LastInviteTime = 0;
- info.LastOnlineTime = getMSTime();
- info.Team = plr->GetTeam();
+ for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)
+ {
+ // if the next one's size is smaller, then insert
+ // also insert if the next one's size is equal, but it joined the queue later
+ if( ((*elig_itr)->Players.size()<size) ||
+ ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )
+ {
+ insert(elig_itr,(*itr));
+ inserted = true;
+ break;
+ }
+ }
+ // if not inserted -> this is the smallest group -> push_back
+ if(!inserted)
+ {
+ push_back((*itr));
+ }
+ }
+ }
+}
- //add player to waiting order queue
- m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID());
+// remove group from eligible groups
+// used when building selection pools
+void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)
+{
+ for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)
+ {
+ if((*itr)==ginfo)
+ {
+ erase(itr);
+ return;
+ }
+ }
+}
- if(plr->GetTeam() == ALLIANCE)
- ++m_QueuedPlayers[queue_id].Alliance;
- else
- ++m_QueuedPlayers[queue_id].Horde;
+// selection pool initialization, used to clean up from prev selection
+void BattleGroundQueue::SelectionPool::Init()
+{
+ SelectedGroups.clear();
+ MaxGroup = 0;
+ PlayerCount = 0;
+}
- this->Update(bgTypeId, queue_id);
+// get the maximal group from the selection pool
+// used when building the pool, and have to remove the largest
+GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()
+{
+ if(SelectedGroups.empty())
+ {
+ sLog.outError("Getting max group when selection pool is empty, this should never happen.");
+ MaxGroup = NULL;
+ return 0;
+ }
+ // actually select the max group if it's not set
+ if(MaxGroup==0 && !SelectedGroups.empty())
+ {
+ uint32 max_size = 0;
+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
+ {
+ if(max_size<(*itr)->Players.size())
+ {
+ MaxGroup =(*itr);
+ max_size = MaxGroup->Players.size();
+ }
+ }
+ }
+ return MaxGroup;
+}
- if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
+// remove group info from selection pool
+// used when building selection pools and have to remove maximal group
+void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)
+{
+ // uninitiate max group info if needed
+ if(MaxGroup == ginfo)
+ MaxGroup = 0;
+ // find what to remove
+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)
{
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(bgTypeId);
- char const* bgName = bg->GetName();
+ if((*itr)==ginfo)
+ {
+ SelectedGroups.erase(itr);
+ // decrease selected players count
+ PlayerCount -= ginfo->Players.size();
+ return;
+ }
+ }
+}
- uint32 q_min_level = Player::GetMinLevelForBattleGroundQueueId(queue_id);
- uint32 q_max_level = Player::GetMaxLevelForBattleGroundQueueId(queue_id);
+// add group to selection
+// used when building selection pools
+void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)
+{
+ SelectedGroups.push_back(ginfo);
+ // increase selected players count
+ PlayerCount+=ginfo->Players.size();
+ if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())
+ {
+ // update max group info if needed
+ MaxGroup = ginfo;
+ }
+}
- // replace hardcoded max level by player max level for nice output
- if(q_max_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- q_max_level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
+// 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)
+{
+ uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();
+
+ // create new ginfo
+ // cannot use the method like in addplayer, because that could modify an in-queue group's stats
+ // (e.g. leader leaving queue then joining as individual again)
+ GroupQueueInfo* ginfo = new GroupQueueInfo;
+ ginfo->BgTypeId = BgTypeId;
+ 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->JoinTime = getMSTime();
+ ginfo->Team = leader->GetTeam();
+
+ if(sBattleGroundMgr.GetMaxRatingDifference()) // if max difference is set, then store rating info for queue
+ ginfo->ArenaTeamRating = arenaRating;
+ else
+ ginfo->ArenaTeamRating = 0; // don't if it doesn't matter
- int8 MinPlayers = bg->GetMinPlayersPerTeam();
+ ginfo->Players.clear();
- uint8 qHorde = m_QueuedPlayers[queue_id].Horde;
- uint8 qAlliance = m_QueuedPlayers[queue_id].Alliance;
+ m_QueuedGroups[queue_id].push_back(ginfo);
- // 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_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde);
- }
- // System message
- else
- {
- sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
- bgName, q_min_level, q_max_level, qAlliance, MinPlayers - qAlliance, qHorde, MinPlayers - qHorde);
- }
- }
+ // return ginfo, because it is needed to add players to this group info
+ return ginfo;
+}
+
+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;
+ info.LastOnlineTime = getMSTime();
+ info.GroupInfo = ginfo;
+
+ // add the pinfo to ginfo's list
+ ginfo->Players[plr->GetGUID()] = &info;
}
void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
@@ -120,11 +252,22 @@ void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
uint32 queue_id = 0;
QueuedPlayersMap::iterator itr;
+ GroupQueueInfo * group;
+ QueuedGroupsList::iterator group_itr;
bool IsSet = false;
- if(!plr)
- { //player is offline, we need to find him somewhere in queues
- /// there is something wrong if this code is run, because we have in queue only online players!
- sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");
+ if(plr)
+ {
+ queue_id = plr->GetBattleGroundQueueIdFromLevel();
+
+ itr = m_QueuedPlayers[queue_id].find(guid);
+ if(itr != m_QueuedPlayers[queue_id].end())
+ IsSet = true;
+ }
+
+ if(!IsSet)
+ {
+ // 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++)
{
itr = m_QueuedPlayers[i].find(guid);
@@ -136,44 +279,248 @@ void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)
}
}
}
- else
- { //player is online, we have his level, so we can find exact queue from his level
- queue_id = plr->GetBattleGroundQueueIdFromLevel();
- itr = m_QueuedPlayers[queue_id].find(guid);
- IsSet = true;
+
+ // couldn't find the player in bg queue, return
+ if(!IsSet)
+ {
+ sLog.outError("Battleground: couldn't find player to remove.");
+ return;
}
- //all variables are set, so remove player
- //remove player from time queue
- m_PlayersSortedByWaitTime[queue_id].remove(guid);
+ group = itr->second.GroupInfo;
- if (IsSet && itr != m_QueuedPlayers[queue_id].end())
+ for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr)
{
- if (!itr->second.IsInvitedToBGInstanceGUID)
- {
- if(itr->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
- }
- else
+ if(group == (GroupQueueInfo*)(*group_itr))
+ break;
+ }
+
+ // variables are set (what about leveling up when in queue????)
+ // remove player from group
+ // if only 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);
+
+ // check for iterator correctness
+ if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())
+ {
+ // used when player left the queue, NOT used when porting to bg
+ if (decreaseInvitedCount)
{
- if (decreaseInvitedCount)
+ // if invited to bg, and should decrease invited count, then do it
+ if(group->IsInvitedToBGInstanceGUID)
{
- BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);
+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID);
if (bg)
- bg->DecreaseInvitedCount(itr->second.Team);
+ 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?)
}
+ // remove player queue info
m_QueuedPlayers[queue_id].erase(itr);
+ // remove group queue info if needed
+ if(group->Players.empty())
+ {
+ m_QueuedGroups[queue_id].erase(group_itr);
+ delete group;
+ }
+ // 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)
+ {
+ // remove next player, this is recursive
+ // first send removal information
+ if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
+ {
+ 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);
+ }
+ // then actually delete, this may delete the group as well!
+ RemovePlayer(group->Players.begin()->first,decreaseInvitedCount);
+ }
+ }
+}
+
+bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
+{
+ // set side if needed
+ if(side)
+ ginfo->Team = side;
+
+ if(!ginfo->IsInvitedToBGInstanceGUID)
+ {
+ // not yet invited
+ // set invitation
+ ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ // 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)
+ continue;
+
+ // invite the player
+ sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);
+
+ WorldPacket data;
+
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+
+ 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);
+ plr->GetSession()->SendPacket(&data);
+ }
+ return true;
+ }
+
+ 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)
+{
+ 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;
+ }
+
+ // inititate 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)
+ m_SelectionPools[mode].Init();
+ while(!(m_EligibleGroups.empty()))
+ {
+ sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");
+ // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players
+ for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)
+ {
+ // get the maximal not yet checked group
+ GroupQueueInfo * MaxGroup = (*itr);
+ // if it fits in the maxplayer size, add it
+ if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )
+ {
+ m_SelectionPools[mode].AddGroup(MaxGroup);
+ }
+ }
+ if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)
+ {
+ // the selection pool is set, return
+ sLog.outDebug("pool build succeeded, return true");
+ return true;
+ }
+ // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.
+ GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();
+ m_EligibleGroups.RemoveGroup(MaxGroup);
+ m_SelectionPools[mode].RemoveGroup(MaxGroup);
+ }
+ // failed to build a selection pool matching the given values
+ 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)
+{
+ 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)
+ {
+ // 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)
+ {
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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 updateing 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);
+ }
+ }
+ }
}
}
/*
-this method is called when player is inserted, or removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
-add method calls this by itself, the remove method could works in other way, so you have to call this method from other code after calling remove method
+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
*/
-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)
+void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating)
{
if (queue_id >= MAX_BATTLEGROUND_QUEUES)
{
@@ -183,157 +530,333 @@ void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)
}
//if no players in queue ... do nothing
- if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0)
+ if (this->m_QueuedGroups[queue_id].size() == 0)
return;
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
+
//battleground with free slot for player should be always the last in this queue
- for (BGFreeSlotQueueType::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr)
+ 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)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)
+ if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == 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
- //check if there are some players in queue
- if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0)
+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr)
{
- for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
+ // 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())
{
- Player* plr = objmgr.GetPlayer(*itr2);
- if (!plr)
- {
- //something is wrong!, kick player from queue
- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
- uint64 oldval = *itr2;
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
- RemovePlayer(oldval, true);
- continue;
- }
-
- // player will be invited, if in bg there is a free slot for him
- if (bg->HasFreeSlotsForTeam(plr->GetTeam()))
- {
- // iterator to player's queue status
- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
-
- // remove him from time queue
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
-
- // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and pls report it)
- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
- continue;
-
- // check if player is not already invited
- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
- {
- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID();
- itrPlayerStatus->second.InviteTime = getMSTime();
- itrPlayerStatus->second.LastInviteTime = getMSTime();
- if(itrPlayerStatus->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
- sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID());
-
- WorldPacket data;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
- plr->GetSession()->SendPacket(&data);
- }
- }
- else
- ++itr2;
-
- //if battleground is FULL, then it is removed from free slot queue - not yet implemented!
- if (!bg->HasFreeSlots())
- {
- //if bg is full, there is no need to invite other players, so break
- break;
- //remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue
- //bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented
- }
+ // if group fits in, invite it
+ InviteGroupToBG((*itr),bg,(*itr)->Team);
}
}
+
+ if (!bg->HasFreeSlots())
+ {
+ //remove BG from BGFreeSlotQueue
+ bg->RemoveFromBGFreeSlotQueue();
+ }
}
}
- /* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */
- //itr->end is the last BG - template, which is not already started!
-
- /* here will be a most of change, when we create battlegrounds instantiated */
- /* if (there is enough players to start new BG)
- Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId)
- - that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template
- (battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */
+ // finished iterating through the bgs with free slots, maybe we need to create a new bg
- /* following code is working with current Battleground system and it should be removed, when BGs will work like instances */
- BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId);
- if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE)
+ BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ if(!bg_template)
+ {
+ sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
return;
- if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam())
+ }
+
+ // 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())
{
- bg2->SetStatus(STATUS_WAIT_JOIN);
- bg2->SetQueueType(queue_id);
+ if(sBattleGroundMgr.isArenaTesting())
+ {
+ MaxPlayersPerTeam = 1;
+ MinPlayersPerTeam = 1;
+ }
+ else
+ {
+ switch(arenatype)
+ {
+ case ARENA_TYPE_2v2:
+ MaxPlayersPerTeam = 2;
+ MinPlayersPerTeam = 2;
+ break;
+ case ARENA_TYPE_3v3:
+ MaxPlayersPerTeam = 3;
+ MinPlayersPerTeam = 3;
+ break;
+ case ARENA_TYPE_5v5:
+ 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 succesfully build");
+ 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 succesfully built");
+ else
+ sLog.outDebug("Battleground: horde pool wasn't created");
- for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)
+ // if selection pools are ready, create the new bg
+ if (bAllyOK && bHordeOK)
+ {
+ BattleGround * bg2 = 0;
+ // special handling for arenas
+ if(bg_template->isArena())
{
- Player* plr = objmgr.GetPlayer(*itr2);
- if (!plr)
+ // 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])) )
{
- //something is wrong!, kick player from queue
- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");
- uint64 oldval = *itr2;
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
- RemovePlayer(oldval, true);
- continue;
+ sLog.outError("Battleground: couldn't create arena");
+ return;
}
- /* TODO: (i'm not sure this code will be useful:
- here should be some condition like if (bg2->isArena() && bg2->isRated())
+ // 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())
{
- invite players from 1 certain group on each faction to play arena match
- } else if ....and existing code
- */
- // player will be invited, if in bg there is a free slot for him
- if (bg2->HasFreeSlotsForTeam(plr->GetTeam()))
+ bg2->SetMaxPlayersPerTeam(1);
+ bg2->SetMaxPlayers(2);
+ }
+ else
{
- // iterator to player's queue status
- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);
+ 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);
+ }
- // remove him from time queue
- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);
+ if(!bg2)
+ {
+ sLog.outError("Battleground: couldn't create bg %u",bgTypeId);
+ return;
+ }
- // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and report it)
- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())
- continue;
+ // 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);
- //check if player is not already invited
- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)
- {
- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();
- itrPlayerStatus->second.InviteTime = getMSTime();
- itrPlayerStatus->second.LastInviteTime = getMSTime();
+ std::list<GroupQueueInfo* >::iterator itr;
- if(itrPlayerStatus->second.Team == ALLIANCE)
- --m_QueuedPlayers[queue_id].Alliance;
- else
- --m_QueuedPlayers[queue_id].Horde;
+ // invite groups from horde selection pool
+ for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr)
+ {
+ InviteGroupToBG((*itr),bg2,HORDE);
+ }
- sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());
+ // invite groups from ally selection pools
+ for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)
+ {
+ InviteGroupToBG((*itr),bg2,ALLIANCE);
+ }
- WorldPacket data;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
- plr->GetSession()->SendPacket(&data);
+ // 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())
+ {
+ 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)
+ {
+ // 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)
+ {
+ // 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;
+ }
+
+ if(!bOneSideAllyTeam2)
+ bOneSideAllyTeam1 = false;
+ }
+ // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!
+ if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||
+ (bOneSideAllyTeam1 && bOneSideAllyTeam2) )
+ {
+ // which side has enough players?
+ uint32 side = 0;
+ SelectionPoolBuildMode mode1, mode2;
+ // find out what pools are we using
+ if(bOneSideAllyTeam1 && bOneSideAllyTeam2)
+ {
+ side = ALLIANCE;
+ mode1 = ONESIDE_ALLIANCE_TEAM1;
+ mode2 = ONESIDE_ALLIANCE_TEAM2;
+ }
+ else
+ {
+ side = HORDE;
+ mode1 = ONESIDE_HORDE_TEAM1;
+ mode2 = ONESIDE_HORDE_TEAM2;
+ }
+
+ // 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])) )
+ {
+ sLog.outError("Could not create arena.");
+ return;
+ }
+
+ sLog.outDebug("Battleground: One-faction arena created.");
+ // init stats
+ 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;
}
}
+
+ bg2->SetRated(isRated);
+
+ // assigned team of the other group
+ uint32 other_side;
+ if(side == ALLIANCE)
+ other_side = HORDE;
else
- ++itr2;
+ 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)
+ {
+ InviteGroupToBG((*itr),bg2,HORDE);
+ }
+
+ // 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)
+ {
+ InviteGroupToBG((*itr),bg2,ALLIANCE);
+ }
+
+ bg2->StartBattleGround();
}
- bg2->StartBattleGround();
}
}
@@ -361,14 +884,19 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 p_time)
uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
{
- // 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[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
- BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
- if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
+ if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
{
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME/2, 0);
- plr->GetSession()->SendPacket(&data);
+ // 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);
+ }
}
}
return true; //event will be deleted
@@ -396,23 +924,26 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
if (!bg)
return true;
- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());
- if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue (base at player data
+ sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
+
+ 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 ... 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[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];
- BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
- if (qItr!=qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
+ 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)
{
- plr->RemoveBattleGroundQueueId(bg->GetTypeID());
- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true);
- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType());
-
+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType());
WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0);
plr->GetSession()->SendPacket(&data);
}
}
+ else
+ sLog.outDebug("Battleground: Player was already removed from queue");
//event will be deleted
return true;
@@ -431,22 +962,80 @@ void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
BattleGroundMgr::BattleGroundMgr()
{
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;
}
BattleGroundMgr::~BattleGroundMgr()
{
- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
- delete itr->second;
+ BattleGroundSet::iterator itr, next;
+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ {
+ next = itr;
+ ++next;
+ BattleGround * bg = itr->second;
+ m_BattleGrounds.erase(itr);
+ delete bg;
+ }
m_BattleGrounds.clear();
}
+// used to update running battlegrounds, and delete finished ones
void BattleGroundMgr::Update(time_t diff)
{
- for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)
+ BattleGroundSet::iterator itr, next;
+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)
+ {
+ 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.erase(itr);
+ delete bg;
+ }
+ }
+ // if rating difference counts, maybe force-update queues
+ if(m_MaxRatingDifference)
+ {
+ // it's time to force update
+ 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;
+ }
+ else
+ m_NextRatingDiscardUpdate -= diff;
+ }
+ if(m_AutoDistributePoints)
+ {
+ 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 = FROM_UNIXTIME('"I64FMTD"')",(uint64)m_NextAutoDistributionTime);
+ }
+ m_AutoDistributionTimeChecker = 600000; // check 10 minutes
+ }
+ else
+ m_AutoDistributionTimeChecker -= diff;
+ }
}
-void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2)
+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted)
{
// we can be in 3 queues in same time...
if(StatusID == 0)
@@ -460,10 +1049,55 @@ 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(bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
+ *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
*data << uint32(0); // unknown
// alliance/horde for BG and skirmish/rated for Arenas
- *data << uint8(bg->isArena() ? (bg->isRated() ? 1 : 0) : bg->GetTeamIndexByTeamId(team));
+ *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team));
+/* *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
+ {
+ case BATTLEGROUND_AV:
+ *data << uint8(1);
+ break;
+ case BATTLEGROUND_WS:
+ *data << uint8(2);
+ break;
+ case BATTLEGROUND_AB:
+ *data << uint8(3);
+ break;
+ case BATTLEGROUND_NA:
+ *data << uint8(4);
+ break;
+ case BATTLEGROUND_BE:
+ *data << uint8(5);
+ break;
+ case BATTLEGROUND_AA:
+ *data << uint8(6);
+ break;
+ case BATTLEGROUND_EY:
+ *data << uint8(7);
+ break;
+ case BATTLEGROUND_RL:
+ *data << uint8(8);
+ break;
+ default: // unknown
+ *data << uint8(0);
+ break;
+ }
+
+ 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
+
+ *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 << uint32(StatusID); // status
switch(StatusID)
{
@@ -493,13 +1127,24 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
// last check on 2.4.1
data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
*data << uint8(type); // seems to be type (battleground=0/arena=1)
+
if(type) // arena
{
- for(uint8 i = 0; i < 2; i++)
+ // 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!
+ sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
+ }
+ for(int i = 1; i >= 0; --i)
{
- *data << uint32(3000+1+i); // rating change: showed value - 3000
- *data << uint32(0); // 2.4.0, has some to do with rating change...
- *data << uint8(0); // some unknown string
+ uint32 at_id = bg->m_ArenaTeamIds[i];
+ ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
+ if(at)
+ *data << at->GetName();
+ else//*/
+ *data << (uint8)0;
}
}
@@ -519,32 +1164,35 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
{
*data << (uint64)itr->first;
*data << (int32)itr->second->KillingBlows;
- if(type)
+ Player *plr = objmgr.GetPlayer(itr->first);
+ uint32 team = bg->GetPlayerTeam(itr->first);
+ if(!team && plr) team = plr->GetTeam();
+ if(type == 0)
+ {
+ *data << (int32)itr->second->HonorableKills;
+ *data << (int32)itr->second->Deaths;
+ *data << (int32)(itr->second->BonusHonor);
+ }
+ else
{
- // this value is team (green/gold)?
// that part probably wrong
- Player *plr = objmgr.GetPlayer(itr->first);
if(plr)
{
- if(plr->GetTeam() == HORDE)
+ if(team == HORDE)
*data << uint8(0);
- else if(plr->GetTeam() == ALLIANCE)
+ else if(team == ALLIANCE)
+ {
*data << uint8(1);
+ }
else
*data << uint8(0);
}
else
*data << uint8(0);
}
- else
- {
- *data << (int32)itr->second->HonorableKills;
- *data << (int32)itr->second->Deaths;
- *data << (int32)itr->second->BonusHonor; // bonus honor
- }
- *data << (int32)itr->second->DamageDone; // damage done
- *data << (int32)itr->second->HealingDone; // healing done
- switch(bg->GetTypeID()) // battleground specific things
+ *data << (int32)itr->second->DamageDone; // damage done
+ *data << (int32)itr->second->HealingDone; // healing done
+ switch(bg->GetTypeID()) // battleground specific things
{
case BATTLEGROUND_AV:
*data << (uint32)0x00000005; // count of next fields
@@ -622,23 +1270,120 @@ void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Pla
*data << uint64(plr->GetGUID());
}
-void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)
+void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team)
{
// set invited player counters:
BattleGround* bg = this->GetBattleGround(bgInstanceGUID);
if(!bg)
return;
+ bg->IncreaseInvitedCount(team);
+
+ plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
+
+ // set the arena teams for rated matches
+ if(bg->isArena() && bg->isRated())
+ {
+ switch(bg->GetArenaType())
+ {
+ 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;
+ }
+ }
- bg->IncreaseInvitedCount(plr->GetTeam());
- plr->SetInviteForBattleGroundType(bg->GetTypeID());
// 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, plr->GetTeam());
+ BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team);
plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
}
+BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)
+{
+ return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();
+}
+
+// create a new battleground that will really be used to play
+BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)
+{
+ BattleGround *bg = NULL;
+
+ // get the template BG
+ BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
+
+ if(!bg_template)
+ {
+ sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
+ return 0;
+ }
+
+ // create a copy of the BG template
+ switch(bgTypeId)
+ {
+ case BATTLEGROUND_AV:
+ bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
+ break;
+ case BATTLEGROUND_WS:
+ bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
+ break;
+ case BATTLEGROUND_AB:
+ bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
+ break;
+ case BATTLEGROUND_NA:
+ bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
+ break;
+ case BATTLEGROUND_BE:
+ bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
+ break;
+ case BATTLEGROUND_AA:
+ bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
+ break;
+ case BATTLEGROUND_EY:
+ bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
+ break;
+ case BATTLEGROUND_RL:
+ bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
+ break;
+ default:
+ //bg = new BattleGround;
+ return 0;
+ break; // placeholder for non implemented BG
+ }
+
+ // generate a new instance id
+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance 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;
+ }
+ */
+
+ // add BG to free slot queue
+ bg->AddToBGFreeSlotQueue();
+
+ // add bg to update list
+ AddBattleGround(bg->GetInstanceID(), 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)
{
// Create the BG
@@ -658,12 +1403,8 @@ uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPer
}
bg->SetMapId(MapID);
+
bg->Reset();
- if(!bg->SetupBattleGround())
- {
- delete bg;
- return 0;
- }
BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId);
//in previous method is checked if exists entry in sBattlemasterListStore, so no check needed
@@ -673,7 +1414,7 @@ uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPer
}
bg->SetTypeID(bgTypeId);
- bg->SetInstanceID(bgTypeId); // temporary
+ bg->SetInstanceID(0); // template bg, instance id is 0
bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
bg->SetMinPlayers(MinPlayersPerTeam*2);
@@ -682,12 +1423,14 @@ uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPer
bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
bg->SetLevelRange(LevelMin, LevelMax);
- //add BaggleGround instance to FreeSlotQueue
+
+ //add BattleGround instance to FreeSlotQueue (.back() will return the template!)
bg->AddToBGFreeSlotQueue();
- AddBattleGround(bg->GetInstanceID(), bg);
- //sLog.outDetail("BattleGroundMgr: Created new battleground: %u %s (Map %u, %u players per team, Levels %u-%u)", bg_TypeID, bg->m_Name, bg->m_MapId, bg->m_MaxPlayersPerTeam, bg->m_LevelMin, bg->m_LevelMax);
- return bg->GetInstanceID();
+ // do NOT add to update list, since this is a template battleground!
+
+ // return some not-null value, bgTypeId is good enough for me
+ return bgTypeId;
}
void BattleGroundMgr::CreateInitialBattleGrounds()
@@ -807,6 +1550,79 @@ void BattleGroundMgr::CreateInitialBattleGrounds()
sLog.outString( ">> Loaded %u battlegrounds", count );
}
+void BattleGroundMgr::InitAutomaticArenaPointDistribution()
+{
+ if(m_AutoDistributePoints)
+ {
+ sLog.outDebug("Initializing Automatic Arena Point Distribution");
+ QueryResult * result = CharacterDatabase.Query("SELECT UNIX_TIMESTAMP(NextArenaPointDistributionTime) FROM saved_variables");
+ 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 ( FROM_UNIXTIME('"I64FMTD"') )",(uint64)m_NextAutoDistributionTime);
+ }
+ else
+ {
+ m_NextAutoDistributionTime = (*result)[0].GetUInt64();
+ delete result;
+ }
+ sLog.outDebug("Automatic Arena Point Distribution initialized.");
+ }
+}
+
+void BattleGroundMgr::DistributeArenaPoints()
+{
+ // used to distribute arena points based on last week's stats
+
+ CharacterDatabase.BeginTransaction();
+ // direct execute, because of the later GetUInt32ValueFromDB() calls
+ // 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
+ CharacterDatabase.DirectPExecute("UPDATE characters b, arena_team_member a SET b.data = CONCAT( SUBSTRING_INDEX(b.data, ' ', '%u'),' ', CAST( IF ( ((CAST( SUBSTRING( b.data FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(c.points_to_add) FROM arena_team_member c WHERE c.guid = b.guid GROUP BY c.guid) ) < '%u'), CAST(SUBSTRING(b.data FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(d.points_to_add) FROM arena_team_member d WHERE d.guid = b.guid GROUP BY d.guid), '%u') AS CHAR),' ',SUBSTRING(b.data FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.data,' ','%u')) + 2))) WHERE b.guid = a.guid",PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_MAX_ARENA_POINTS),PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_MAX_ARENA_POINTS), PLAYER_FIELD_ARENA_CURRENCY+1);
+ for(int i=0; i<3; ++i)
+ {
+ // reset weekly played matches
+ uint32 position = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2;
+ CharacterDatabase.DirectPExecute("UPDATE characters SET data = CONCAT( SUBSTRING_INDEX(data,' ','%u'),' ','0',' ',SUBSTRING(data FROM (CHAR_LENGTH(SUBSTRING_INDEX(data,' ','%u')) + 2)))",position, position + 1);
+ }
+ CharacterDatabase.DirectExecute("UPDATE arena_team_member SET points_to_add = '0', played_week = '0', wons_week = '0'");
+ CharacterDatabase.DirectExecute("UPDATE arena_team_stats SET games = '0', wins = '0'");
+ CharacterDatabase.CommitTransaction();
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid, data FROM characters WHERE online = '1'");
+ if( result )
+ {
+ do
+ {
+ Field *fields = result->Fetch();
+
+ uint32 guid = fields[0].GetUInt32();
+ if(Player * pl = objmgr.GetPlayer(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)))
+ {
+ Tokens data = StrSplit(fields[1].GetCppString(), " ");
+ // update arena currency
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_ARENA_CURRENCY));
+ // reset played this week count for all teams
+ for(int i= 0; i < 3; ++i)
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2, 0);
+ }
+
+ } while (result->NextRow());
+
+ delete result;
+ }
+
+ for(ObjectMgr::ArenaTeamSet::iterator titr = objmgr.GetArenaTeamSetBegin(); titr != objmgr.GetArenaTeamSetEnd(); ++titr)
+ {
+ if(ArenaTeam * at = (*titr))
+ {
+ at->FinishWeek(); // set played this week etc values to 0 in memory, too
+ // at->SaveToDB(); // no need, the modified values are already saved above
+ at->NotifyStatsChanged(); // notify the players of the changes
+ }
+ }
+}
+
void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId)
{
uint32 PlayerLevel = 10;
@@ -842,18 +1658,25 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid
}
}
-void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId)
+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId)
{
- BattleGround *bg = GetBattleGround(bgTypeId);
+ BattleGround *bg = GetBattleGround(instanceId);
if(bg)
{
uint32 mapid = bg->GetMapId();
float x, y, z, O;
- bg->GetTeamStartLoc(pl->GetTeam(), x, y, z, O);
+ uint32 team = pl->GetBGTeam();
+ if(team==0)
+ team = pl->GetTeam();
+ bg->GetTeamStartLoc(team, x, y, z, O);
sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
pl->TeleportTo(mapid, x, y, z, O);
}
+ else
+ {
+ sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
+ }
}
void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)
@@ -865,3 +1688,97 @@ void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *
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
+{
+ return ( bgTypeId == BATTLEGROUND_AA ||
+ bgTypeId == BATTLEGROUND_BE ||
+ bgTypeId == BATTLEGROUND_NA ||
+ bgTypeId == BATTLEGROUND_RL );
+}
+
+bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const
+{
+ return !IsArenaType(bgTypeId);
+}
+
+uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const
+{
+ 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;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const
+{
+ 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;
+ }
+}
+
+uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const
+{
+ switch(bgQueueTypeId)
+ {
+ case BATTLEGROUND_QUEUE_2v2:
+ return ARENA_TYPE_2v2;
+ case BATTLEGROUND_QUEUE_3v3:
+ return ARENA_TYPE_3v3;
+ case BATTLEGROUND_QUEUE_5v5:
+ return ARENA_TYPE_5v5;
+ default:
+ return 0;
+ }
+}
+
+void BattleGroundMgr::ToggleArenaTesting()
+{
+ m_ArenaTesting = !m_ArenaTesting;
+ sWorld.SendWorldText(LANG_ARENA_TESTING, m_ArenaTesting ? "on" : "off");
+}