/*
* Copyright (C) 2008-2012 TrinityCore
*
* 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, see .
*/
#ifndef _LFGMGR_H
#define _LFGMGR_H
#include "Common.h"
#include
#include "LFG.h"
class LfgGroupData;
class LfgPlayerData;
class Group;
class Player;
enum LFGenum
{
LFG_TIME_ROLECHECK = 2*MINUTE,
LFG_TIME_BOOT = 2*MINUTE,
LFG_TIME_PROPOSAL = 2*MINUTE,
LFG_TANKS_NEEDED = 1,
LFG_HEALERS_NEEDED = 1,
LFG_DPS_NEEDED = 3,
LFG_QUEUEUPDATE_INTERVAL = 15*IN_MILLISECONDS,
LFG_SPELL_DUNGEON_COOLDOWN = 71328,
LFG_SPELL_DUNGEON_DESERTER = 71041,
LFG_SPELL_LUCK_OF_THE_DRAW = 72221
};
/// Determines the type of instance
enum LfgType
{
LFG_TYPE_NONE = 0, // Internal use only
LFG_TYPE_DUNGEON = 1,
LFG_TYPE_RAID = 2,
LFG_TYPE_QUEST = 3,
LFG_TYPE_ZONE = 4,
LFG_TYPE_HEROIC = 5,
LFG_TYPE_RANDOM = 6
};
/// Proposal states
enum LfgProposalState
{
LFG_PROPOSAL_INITIATING = 0,
LFG_PROPOSAL_FAILED = 1,
LFG_PROPOSAL_SUCCESS = 2
};
/// Teleport errors
enum LfgTeleportError
{
// 3, 7, 8 = "You can't do that right now" | 5 = No client reaction
LFG_TELEPORTERROR_OK = 0, // Internal use
LFG_TELEPORTERROR_PLAYER_DEAD = 1,
LFG_TELEPORTERROR_FALLING = 2,
LFG_TELEPORTERROR_DONT_REPORT = 3,
LFG_TELEPORTERROR_FATIGUE = 4,
LFG_TELEPORTERROR_INVALID_LOCATION = 6
};
/// Queue join results
enum LfgJoinResult
{
// 3 = No client reaction | 18 = "Rolecheck failed"
LFG_JOIN_OK = 0, // Joined (no client msg)
LFG_JOIN_FAILED = 1, // RoleCheck Failed
LFG_JOIN_GROUPFULL = 2, // Your group is full
LFG_JOIN_INTERNAL_ERROR = 4, // Internal LFG Error
LFG_JOIN_NOT_MEET_REQS = 5, // You do not meet the requirements for the chosen dungeons
LFG_JOIN_PARTY_NOT_MEET_REQS = 6, // One or more party members do not meet the requirements for the chosen dungeons
LFG_JOIN_MIXED_RAID_DUNGEON = 7, // You cannot mix dungeons, raids, and random when picking dungeons
LFG_JOIN_MULTI_REALM = 8, // The dungeon you chose does not support players from multiple realms
LFG_JOIN_DISCONNECTED = 9, // One or more party members are pending invites or disconnected
LFG_JOIN_PARTY_INFO_FAILED = 10, // Could not retrieve information about some party members
LFG_JOIN_DUNGEON_INVALID = 11, // One or more dungeons was not valid
LFG_JOIN_DESERTER = 12, // You can not queue for dungeons until your deserter debuff wears off
LFG_JOIN_PARTY_DESERTER = 13, // One or more party members has a deserter debuff
LFG_JOIN_RANDOM_COOLDOWN = 14, // You can not queue for random dungeons while on random dungeon cooldown
LFG_JOIN_PARTY_RANDOM_COOLDOWN = 15, // One or more party members are on random dungeon cooldown
LFG_JOIN_TOO_MUCH_MEMBERS = 16, // You can not enter dungeons with more that 5 party members
LFG_JOIN_USING_BG_SYSTEM = 17 // You can not use the dungeon system while in BG or arenas
};
/// Role check states
enum LfgRoleCheckState
{
LFG_ROLECHECK_DEFAULT = 0, // Internal use = Not initialized.
LFG_ROLECHECK_FINISHED = 1, // Role check finished
LFG_ROLECHECK_INITIALITING = 2, // Role check begins
LFG_ROLECHECK_MISSING_ROLE = 3, // Someone didn't selected a role after 2 mins
LFG_ROLECHECK_WRONG_ROLES = 4, // Can't form a group with that role selection
LFG_ROLECHECK_ABORTED = 5, // Someone leave the group
LFG_ROLECHECK_NO_ROLE = 6 // Someone selected no role
};
/// Answer state (Also used to check compatibilites)
enum LfgAnswer
{
LFG_ANSWER_PENDING = -1,
LFG_ANSWER_DENY = 0,
LFG_ANSWER_AGREE = 1
};
// Forward declaration (just to have all typedef together)
struct LfgReward;
struct LfgLockStatus;
struct LfgQueueInfo;
struct LfgRoleCheck;
struct LfgProposal;
struct LfgProposalPlayer;
struct LfgPlayerBoot;
typedef std::set LfgGuidSet;
typedef std::list LfgGuidList;
typedef std::map LfgGuidListMap;
typedef std::set PlayerSet;
typedef std::list LfgPlayerList;
typedef std::multimap LfgRewardMap;
typedef std::pair LfgRewardMapBounds;
typedef std::map LfgCompatibleMap;
typedef std::map LfgDungeonMap;
typedef std::map LfgRolesMap;
typedef std::map LfgAnswerMap;
typedef std::map LfgRoleCheckMap;
typedef std::map LfgQueueInfoMap;
typedef std::map LfgProposalMap;
typedef std::map LfgProposalPlayerMap;
typedef std::map LfgPlayerBootMap;
typedef std::map LfgGroupDataMap;
typedef std::map LfgPlayerDataMap;
// Data needed by SMSG_LFG_JOIN_RESULT
struct LfgJoinResultData
{
LfgJoinResultData(LfgJoinResult _result = LFG_JOIN_OK, LfgRoleCheckState _state = LFG_ROLECHECK_DEFAULT):
result(_result), state(_state) {}
LfgJoinResult result;
LfgRoleCheckState state;
LfgLockPartyMap lockmap;
};
// Data needed by SMSG_LFG_UPDATE_PARTY and SMSG_LFG_UPDATE_PLAYER
struct LfgUpdateData
{
LfgUpdateData(LfgUpdateType _type = LFG_UPDATETYPE_DEFAULT): updateType(_type), comment("") {}
LfgUpdateData(LfgUpdateType _type, const LfgDungeonSet& _dungeons, std::string _comment):
updateType(_type), dungeons(_dungeons), comment(_comment) {}
LfgUpdateType updateType;
LfgDungeonSet dungeons;
std::string comment;
};
/// Reward info
struct LfgReward
{
uint32 maxLevel;
struct
{
uint32 questId;
uint32 variableMoney;
uint32 variableXP;
} reward[2];
LfgReward(uint32 _maxLevel = 0, uint32 firstQuest = 0, uint32 firstVarMoney = 0, uint32 firstVarXp = 0, uint32 otherQuest = 0, uint32 otherVarMoney = 0, uint32 otherVarXp = 0)
: maxLevel(_maxLevel)
{
reward[0].questId = firstQuest;
reward[0].variableMoney = firstVarMoney;
reward[0].variableXP = firstVarXp;
reward[1].questId = otherQuest;
reward[1].variableMoney = otherVarMoney;
reward[1].variableXP = otherVarXp;
}
};
/// Stores player or group queue info
struct LfgQueueInfo
{
LfgQueueInfo(): joinTime(0), tanks(LFG_TANKS_NEEDED), healers(LFG_HEALERS_NEEDED), dps(LFG_DPS_NEEDED) {};
time_t joinTime; ///< Player queue join time (to calculate wait times)
uint8 tanks; ///< Tanks needed
uint8 healers; ///< Healers needed
uint8 dps; ///< Dps needed
LfgDungeonSet dungeons; ///< Selected Player/Group Dungeon/s
LfgRolesMap roles; ///< Selected Player Role/s
};
/// Stores player data related to proposal to join
struct LfgProposalPlayer
{
LfgProposalPlayer(): role(0), accept(LFG_ANSWER_PENDING), groupLowGuid(0) {};
uint8 role; ///< Proposed role
LfgAnswer accept; ///< Accept status (-1 not answer | 0 Not agree | 1 agree)
uint32 groupLowGuid; ///< Original group guid (Low guid) 0 if no original group
};
/// Stores group data related to proposal to join
struct LfgProposal
{
LfgProposal(uint32 dungeon = 0): dungeonId(dungeon), state(LFG_PROPOSAL_INITIATING), groupLowGuid(0), leader(0), cancelTime(0) {}
~LfgProposal()
{
for (LfgProposalPlayerMap::iterator it = players.begin(); it != players.end(); ++it)
delete it->second;
};
uint32 dungeonId; ///< Dungeon to join
LfgProposalState state; ///< State of the proposal
uint32 groupLowGuid; ///< Proposal group (0 if new)
uint64 leader; ///< Leader guid.
time_t cancelTime; ///< Time when we will cancel this proposal
LfgGuidList queues; ///< Queue Ids to remove/readd
LfgProposalPlayerMap players; ///< Players data
};
/// Stores all rolecheck info of a group that wants to join
struct LfgRoleCheck
{
time_t cancelTime; ///< Time when the rolecheck will fail
LfgRolesMap roles; ///< Player selected roles
LfgRoleCheckState state; ///< State of the rolecheck
LfgDungeonSet dungeons; ///< Dungeons group is applying for (expanded random dungeons)
uint32 rDungeonId; ///< Random Dungeon Id.
uint64 leader; ///< Leader of the group
};
/// Stores information of a current vote to kick someone from a group
struct LfgPlayerBoot
{
time_t cancelTime; ///< Time left to vote
bool inProgress; ///< Vote in progress
LfgAnswerMap votes; ///< Player votes (-1 not answer | 0 Not agree | 1 agree)
uint64 victim; ///< Player guid to be kicked (can't vote)
uint8 votedNeeded; ///< Votes needed to kick the player
std::string reason; ///< kick reason
};
class LFGMgr
{
friend class ACE_Singleton;
private:
LFGMgr();
~LFGMgr();
public:
void Update(uint32 diff);
// Reward
void LoadRewards();
void RewardDungeonDoneFor(const uint32 dungeonId, Player* player);
LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level);
// Queue
void Join(Player* player, uint8 roles, const LfgDungeonSet& dungeons, const std::string& comment);
void Leave(Player* player, Group* grp = NULL);
// Role Check
void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = ROLE_NONE);
// Proposals
void UpdateProposal(uint32 proposalId, uint64 guid, bool accept);
// Teleportation
void TeleportPlayer(Player* player, bool out, bool fromOpcode = false);
// Vote kick
void InitBoot(Group* grp, uint64 kguid, uint64 vguid, std::string reason);
void UpdateBoot(Player* player, bool accept);
void OfferContinue(Group* grp);
void InitializeLockedDungeons(Player* player);
void _LoadFromDB(Field* fields, uint64 guid);
void _SaveToDB(uint64 guid, uint32 db_guid);
void SetComment(uint64 guid, const std::string& comment);
const LfgLockMap& GetLockedDungeons(uint64 guid);
LfgState GetState(uint64 guid);
const LfgDungeonSet& GetSelectedDungeons(uint64 guid);
uint32 GetDungeon(uint64 guid, bool asId = true);
void SetState(uint64 guid, LfgState state);
void ClearState(uint64 guid);
void RemovePlayerData(uint64 guid);
void RemoveGroupData(uint64 guid);
uint8 GetKicksLeft(uint64 gguid);
uint8 GetVotesNeeded(uint64 gguid);
bool IsTeleported(uint64 pguid);
void SetRoles(uint64 guid, uint8 roles);
void SetSelectedDungeons(uint64 guid, const LfgDungeonSet& dungeons);
private:
uint8 GetRoles(uint64 guid);
const std::string& GetComment(uint64 gguid);
void RestoreState(uint64 guid);
void SetDungeon(uint64 guid, uint32 dungeon);
void SetLockedDungeons(uint64 guid, const LfgLockMap& lock);
void DecreaseKicksLeft(uint64 guid);
// Queue
void AddToQueue(uint64 guid, uint8 queueId);
bool RemoveFromQueue(uint64 guid);
// Proposals
void RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type);
// Group Matching
LfgProposal* FindNewGroups(LfgGuidList& check, LfgGuidList& all);
bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
bool CheckCompatibility(LfgGuidList check, LfgProposal*& pProposal);
void GetCompatibleDungeons(LfgDungeonSet& dungeons, const PlayerSet& players, LfgLockPartyMap& lockMap);
void SetCompatibles(std::string concatenatedGuids, bool compatibles);
LfgAnswer GetCompatibles(std::string concatenatedGuids);
void RemoveFromCompatibles(uint64 guid);
// Generic
const LfgDungeonSet& GetDungeonsByRandom(uint32 randomdungeon);
LfgType GetDungeonType(uint32 dungeon);
std::string ConcatenateGuids(LfgGuidList check);
// General variables
bool m_update; ///< Doing an update?
uint32 m_QueueTimer; ///< used to check interval of update
uint32 m_lfgProposalId; ///< used as internal counter for proposals
int32 m_WaitTimeAvg; ///< Average wait time to find a group queuing as multiple roles
int32 m_WaitTimeTank; ///< Average wait time to find a group queuing as tank
int32 m_WaitTimeHealer; ///< Average wait time to find a group queuing as healer
int32 m_WaitTimeDps; ///< Average wait time to find a group queuing as dps
uint32 m_NumWaitTimeAvg; ///< Num of players used to calc avs wait time
uint32 m_NumWaitTimeTank; ///< Num of players used to calc tank wait time
uint32 m_NumWaitTimeHealer; ///< Num of players used to calc healers wait time
uint32 m_NumWaitTimeDps; ///< Num of players used to calc dps wait time
LfgDungeonMap m_CachedDungeonMap; ///< Stores all dungeons by groupType
// Reward System
LfgRewardMap m_RewardMap; ///< Stores rewards for random dungeons
// Queue
LfgQueueInfoMap m_QueueInfoMap; ///< Queued groups
LfgGuidListMap m_currentQueue; ///< Ordered list. Used to find groups
LfgGuidListMap m_newToQueue; ///< New groups to add to queue
LfgCompatibleMap m_CompatibleMap; ///< Compatible dungeons
LfgGuidList m_teleport; ///< Players being teleported
// Rolecheck - Proposal - Vote Kicks
LfgRoleCheckMap m_RoleChecks; ///< Current Role checks
LfgProposalMap m_Proposals; ///< Current Proposals
LfgPlayerBootMap m_Boots; ///< Current player kicks
LfgPlayerDataMap m_Players; ///< Player data
LfgGroupDataMap m_Groups; ///< Group data
};
#define sLFGMgr ACE_Singleton::instance()
#endif