/* * Copyright (C) 2005-2009 MaNGOS * * Copyright (C) 2008-2009 Trinity * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __BATTLEGROUNDMGR_H #define __BATTLEGROUNDMGR_H #include "Common.h" #include "BattleGround.h" typedef std::map BattleGroundSet; //this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears typedef std::list BGFreeSlotQueueType; typedef UNORDERED_MAP BattleMastersMap; #define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day #define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10 struct GroupQueueInfo; // type predefinition struct PlayerQueueInfo // stores information for players in queue { uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo }; struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!) { std::map Players; // player queue info map uint32 Team; // Player team (ALLIANCE/HORDE) BattleGroundTypeId BgTypeId; // battleground type id bool IsRated; // rated uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG uint32 ArenaTeamId; // team id if rated match uint32 JoinTime; // time when group was added uint32 RemoveInviteTime; // time when we will remove invite for players in group uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG uint32 ArenaTeamRating; // if rated match, inited to the rating of the team uint32 OpponentsTeamRating; // for rated arena matches }; enum BattleGroundQueueGroupTypes { BG_QUEUE_PREMADE_ALLIANCE = 0, BG_QUEUE_PREMADE_HORDE = 1, BG_QUEUE_NORMAL_ALLIANCE = 2, BG_QUEUE_NORMAL_HORDE = 3 }; #define BG_QUEUE_GROUP_TYPES_COUNT 4 class BattleGround; class BattleGroundQueue { public: BattleGroundQueue(); ~BattleGroundQueue(); void Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0); void FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id); bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam); bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers); bool CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam); GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0); void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); void BGEndedRemoveInvites(BattleGround * bg); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); typedef std::map QueuedPlayersMap; QueuedPlayersMap m_QueuedPlayers; //we need constant add to begin and constant remove / add from the end, therefore deque suits our problem well typedef std::list GroupsQueueType; /* This two dimensional array is used to store All queued groups First dimension specifies the bgTypeId Second dimension specifies the player's group types - BG_QUEUE_PREMADE_ALLIANCE is used for premade alliance groups and alliance rated arena teams BG_QUEUE_PREMADE_HORDE is used for premade horde groups and horde rated arena teams BG_QUEUE_NORMAL_ALLIANCE is used for normal (or small) alliance groups or non-rated arena matches BG_QUEUE_NORMAL_HORDE is used for normal (or small) horde groups or non-rated arena matches */ GroupsQueueType m_QueuedGroups[MAX_BATTLEGROUND_QUEUES][BG_QUEUE_GROUP_TYPES_COUNT]; // class to select and invite groups to bg class SelectionPool { public: void Init(); bool AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount); bool KickGroup(uint32 size); uint32 GetPlayerCount() const {return PlayerCount;} public: GroupsQueueType SelectedGroups; private: uint32 PlayerCount; }; //one selection pool for horde, other one for alliance SelectionPool m_SelectionPools[BG_TEAMS_COUNT]; private: bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; uint32 m_SumOfWaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; }; /* This class is used to invite player to BG again, when minute lasts from his first invitation it is capable to solve all possibilities */ class BGQueueInviteEvent : public BasicEvent { public: BGQueueInviteEvent(const uint64& pl_guid, uint32 BgInstanceGUID, BattleGroundTypeId BgTypeId) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId) { }; virtual ~BGQueueInviteEvent() {}; virtual bool Execute(uint64 e_time, uint32 p_time); virtual void Abort(uint64 e_time); private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; BattleGroundTypeId m_BgTypeId; }; /* This class is used to remove player from BG queue after 2 minutes from first invitation */ class BGQueueRemoveEvent : public BasicEvent { public: BGQueueRemoveEvent(const uint64& pl_guid, uint32 bgInstanceGUID, BattleGroundTypeId BgTypeId, uint32 playersTeam) : m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_BgTypeId(BgTypeId), m_PlayersTeam(playersTeam) { }; virtual ~BGQueueRemoveEvent() {}; virtual bool Execute(uint64 e_time, uint32 p_time); virtual void Abort(uint64 e_time); private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID; uint32 m_PlayersTeam; BattleGroundTypeId m_BgTypeId; }; class BattleGroundMgr { public: /* Construction */ BattleGroundMgr(); ~BattleGroundMgr(); void Update(uint32 diff); /* Packet Building */ void BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr); void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid); void BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player *plr, BattleGroundTypeId bgTypeId); void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId); void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value); void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg); void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); /* Player invitation */ // called from Queue update, or from Addplayer to queue void InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team); /* Battlegrounds */ BattleGround* GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown BattleGround* GetBattleGroundTemplate(BattleGroundTypeId bgTypeId); BattleGround* CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated); uint32 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); void AddBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId, BattleGround* BG) { m_BattleGrounds[bgTypeId][InstanceID] = BG; }; void RemoveBattleGround(uint32 instanceID, BattleGroundTypeId bgTypeId) { m_BattleGrounds[bgTypeId].erase(instanceID); } uint32 CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); void CreateInitialBattleGrounds(); void DeleteAllBattleGrounds(); void SendToBattleGround(Player *pl, uint32 InstanceID, BattleGroundTypeId bgTypeId); /* Battleground queues */ //these queues are instantiated when creating BattlegroundMrg BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; // public, because we need to access them in BG handler code BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPE_ID]; uint32 GetMaxRatingDifference() const; uint32 GetRatingDiscardTimer() const; uint32 GetPrematureFinishTime() const; void InitAutomaticArenaPointDistribution(); void DistributeArenaPoints(); void ToggleArenaTesting(); void ToggleTesting(); void SetHolidayWeekends(uint32 mask); void LoadBattleMastersEntry(); BattleGroundTypeId GetBattleMasterBG(uint32 entry) const { BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry); if(itr != mBattleMastersMap.end()) return itr->second; return BATTLEGROUND_WS; } bool isArenaTesting() const { return m_ArenaTesting; } bool isTesting() const { return m_Testing; } static bool IsArenaType(BattleGroundTypeId bgTypeId); static bool IsBattleGroundType(BattleGroundTypeId bgTypeId) { return !BattleGroundMgr::IsArenaType(bgTypeId); } static BattleGroundQueueTypeId BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType); static BattleGroundTypeId BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId); static uint8 BGArenaType(BattleGroundQueueTypeId bgQueueTypeId); private: BattleMastersMap mBattleMastersMap; /* Battlegrounds */ BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID]; std::set m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client uint32 m_NextRatingDiscardUpdate; uint64 m_NextAutoDistributionTime; uint32 m_AutoDistributionTimeChecker; bool m_ArenaTesting; bool m_Testing; }; #define sBattleGroundMgr Trinity::Singleton::Instance() #endif