mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-20 09:17:36 +01:00
Dungeon Finder: Add proposals, find group algorithm and teleport support
Note: Adds hability to find a group and be teleported to dungeon, but no rewards yet (WIP) --HG-- branch : trunk
This commit is contained in:
@@ -33,6 +33,7 @@ LFGMgr::LFGMgr()
|
||||
m_waitTimeHealer = -1;
|
||||
m_waitTimeDps = -1;
|
||||
m_update = true;
|
||||
m_lfgProposalId = 1;
|
||||
}
|
||||
|
||||
LFGMgr::~LFGMgr()
|
||||
@@ -51,6 +52,10 @@ LFGMgr::~LFGMgr()
|
||||
delete it->second;
|
||||
m_QueueInfoMap.clear();
|
||||
|
||||
for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end(); ++it)
|
||||
delete it->second;
|
||||
m_Proposals.clear();
|
||||
|
||||
for (LfgRoleCheckMap::iterator it = m_RoleChecks.begin(); it != m_RoleChecks.end(); ++it)
|
||||
delete it->second;
|
||||
m_RoleChecks.clear();
|
||||
@@ -102,6 +107,63 @@ void LFGMgr::Update(uint32 diff)
|
||||
m_RoleChecks.erase(itRoleCheck);
|
||||
}
|
||||
|
||||
// Remove obsolete proposals
|
||||
LfgProposalMap::iterator itRemove;
|
||||
for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end();)
|
||||
{
|
||||
itRemove = it++;
|
||||
if (itRemove->second->cancelTime < currTime)
|
||||
RemoveProposal(itRemove, LFG_UPDATETYPE_PROPOSAL_FAILED);
|
||||
}
|
||||
|
||||
// Check if a proposal can be formed with the new groups being added
|
||||
LfgProposalList proposals;
|
||||
LfgGuidList firstNew;
|
||||
while(!m_newToQueue.empty())
|
||||
{
|
||||
firstNew.push_back(m_newToQueue.front());
|
||||
FindNewGroups(firstNew, m_currentQueue, &proposals);
|
||||
if (proposals.size()) // Group found!
|
||||
{
|
||||
LfgProposal *pProposal = *proposals.begin();
|
||||
// TODO: Create algorithm to select better group based on GS (uses to be good tank with bad healer and viceversa)
|
||||
|
||||
// Remove groups in the proposal from the queue
|
||||
for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
|
||||
m_currentQueue.remove(*it);
|
||||
m_Proposals[++m_lfgProposalId] = pProposal;
|
||||
|
||||
for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers)
|
||||
{
|
||||
if (Player *plr = sObjectMgr.GetPlayer(itPlayers->first))
|
||||
{
|
||||
if (plr->GetGroup())
|
||||
plr->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_PROPOSAL_BEGIN);
|
||||
else
|
||||
plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_PROPOSAL_BEGIN);
|
||||
SendUpdateProposal(plr, m_lfgProposalId, pProposal);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for (LfgProposalList::iterator it = proposals.begin(); it != proposals.end(); ++it)
|
||||
{
|
||||
if ((*it) == pProposal) // Do not remove the selected proposal;
|
||||
continue;
|
||||
(*it)->queues.clear();
|
||||
for (LfgProposalPlayerMap::iterator itPlayers = (*it)->players.begin(); itPlayers != (*it)->players.end(); ++itPlayers)
|
||||
delete itPlayers->second;
|
||||
(*it)->players.clear();
|
||||
delete (*it);
|
||||
}
|
||||
proposals.clear();
|
||||
}
|
||||
else
|
||||
m_currentQueue.push_back(m_newToQueue.front()); // Group not found, add this group to the queue.
|
||||
m_newToQueue.pop_front();
|
||||
firstNew.clear();
|
||||
}
|
||||
|
||||
// Update all players status queue info
|
||||
if (m_QueueTimer > LFG_QUEUEUPDATE_INTERVAL)
|
||||
{
|
||||
@@ -323,6 +385,15 @@ void LFGMgr::Leave(Player *plr, Group *grp /* = NULL*/)
|
||||
// Remove from queue
|
||||
RemoveFromQueue(guid);
|
||||
|
||||
// Remove from Proposals
|
||||
for (LfgProposalMap::iterator it = m_Proposals.begin(); it != m_Proposals.end(); ++it)
|
||||
{
|
||||
// Mark the player/leader of group who left as didn't accept the proposal
|
||||
for (LfgProposalPlayerMap::iterator itPlayer = it->second->players.begin(); itPlayer != it->second->players.end(); ++itPlayer)
|
||||
if ((plr && itPlayer->first == plr->GetGUIDLow()) || (grp && itPlayer->first == GUID_LOPART(grp->GetLeaderGUID())))
|
||||
itPlayer->second->accept = 0;
|
||||
}
|
||||
|
||||
if (grp)
|
||||
{
|
||||
for (GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
@@ -341,6 +412,19 @@ void LFGMgr::Leave(Player *plr, Group *grp /* = NULL*/)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a Lfg group checks if leader needs to be show the popup to select more players
|
||||
/// </summary>
|
||||
/// <param name="Group *">Group than needs new players</param>
|
||||
void LFGMgr::OfferContinue(Group *grp)
|
||||
{
|
||||
ASSERT(grp);
|
||||
|
||||
if (grp->GetLfgStatus() != LFG_STATUS_COMPLETE)
|
||||
if (Player *leader = sObjectMgr.GetPlayer(grp->GetLeaderGUID()))
|
||||
leader->GetSession()->SendLfgOfferContinue(grp->GetLfgDungeonEntry(false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a QueueInfo and adds it to the queue. Tries to match a group before joining.
|
||||
/// </summary>
|
||||
@@ -397,6 +481,211 @@ bool LFGMgr::RemoveFromQueue(uint64 guid)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the queue to try to match groups. Returns all the posible matches
|
||||
/// </summary>
|
||||
/// <param name="LfgGuidList &">Guids we trying to match with the rest of groups</param>
|
||||
/// <param name="LfgGuidList">All guids in queue</param>
|
||||
/// <param name="LfgProposalList *">Proposals found.</param>
|
||||
void LFGMgr::FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList *proposals)
|
||||
{
|
||||
uint8 numPlayers = 0;
|
||||
uint8 numLfgGroups = 0;
|
||||
uint32 groupLowGuid = 0;
|
||||
LfgQueueInfoMap pqInfoMap;
|
||||
|
||||
for (LfgGuidList::const_iterator it = check.begin(); it != check.end(); ++it)
|
||||
{
|
||||
if (!m_QueueInfoMap[*it])
|
||||
{
|
||||
sLog.outError("LFGMgr::FindNewGroups: " UI64FMTD " is not queued but listed as queued!", *it);
|
||||
return;
|
||||
}
|
||||
pqInfoMap[*it] = m_QueueInfoMap[*it];
|
||||
numPlayers += m_QueueInfoMap[*it]->roles.size();
|
||||
|
||||
if (IS_GROUP(*it))
|
||||
{
|
||||
uint32 lowGuid = GUID_LOPART(*it);
|
||||
if (Group *grp = sObjectMgr.GetGroupByGUID(lowGuid))
|
||||
if (grp->isLFGGroup())
|
||||
{
|
||||
if (!numLfgGroups)
|
||||
groupLowGuid = lowGuid;
|
||||
++numLfgGroups;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do not match groups already in a lfgDungeon
|
||||
if (numLfgGroups > 1 || numPlayers > MAXGROUPSIZE)
|
||||
{
|
||||
pqInfoMap.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (numPlayers < MAXGROUPSIZE)
|
||||
{
|
||||
while (!all.empty())
|
||||
{
|
||||
check.push_back(all.front());
|
||||
all.pop_front();
|
||||
FindNewGroups(check, all, proposals);
|
||||
check.pop_back();
|
||||
}
|
||||
pqInfoMap.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// ----- Player checks -----
|
||||
LfgRolesMap rolesMap;
|
||||
uint32 newLeaderLowGuid = 0;
|
||||
for (LfgQueueInfoMap::const_iterator it = pqInfoMap.begin(); it != pqInfoMap.end(); ++it)
|
||||
{
|
||||
for (LfgRolesMap::const_iterator itRoles = it->second->roles.begin(); itRoles != it->second->roles.end(); ++itRoles)
|
||||
{
|
||||
// Assign new leader
|
||||
if (itRoles->second & ROLE_LEADER && (!newLeaderLowGuid || urand(0, 1)))
|
||||
newLeaderLowGuid = itRoles->first;
|
||||
rolesMap[itRoles->first] = itRoles->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (rolesMap.size() != MAXGROUPSIZE)
|
||||
{
|
||||
sLog.outError("LFGMgr::FindNewGroups: There is a player multiple times in queue.");
|
||||
return;
|
||||
}
|
||||
|
||||
Player *plr;
|
||||
PlayerSet players;
|
||||
for (LfgRolesMap::const_iterator it = rolesMap.begin(); it != rolesMap.end(); ++it)
|
||||
{
|
||||
plr = sObjectMgr.GetPlayer(it->first);
|
||||
for (PlayerSet::const_iterator itPlayer = players.begin(); itPlayer != players.end() && plr; ++itPlayer)
|
||||
{
|
||||
// Do not form a group with ignoring candidates
|
||||
if (plr->GetSocial()->HasIgnore((*itPlayer)->GetGUIDLow()) || (*itPlayer)->GetSocial()->HasIgnore(plr->GetGUIDLow()))
|
||||
plr = NULL;
|
||||
// neither with diferent faction if it's not a mixed faction server
|
||||
else if (plr->GetTeam() != (*itPlayer)->GetTeam() && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
|
||||
plr = NULL;
|
||||
}
|
||||
if (plr)
|
||||
players.insert(plr);
|
||||
}
|
||||
|
||||
// if we dont have MAXGROUPSIZE (5) then we have self ignoring candidates or different faction groups
|
||||
// otherwise check if roles are compatible
|
||||
if (players.size() != MAXGROUPSIZE || !CheckGroupRoles(rolesMap))
|
||||
{
|
||||
players.clear();
|
||||
pqInfoMap.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// ----- Selected Dungeon checks -----
|
||||
// Check if there are any compatible dungeon from the selected dungeons
|
||||
|
||||
LfgDungeonSet *compatibleDungeons = new LfgDungeonSet();
|
||||
bool compatibleDungeon;
|
||||
LfgQueueInfoMap::const_iterator itFirst = pqInfoMap.begin();
|
||||
LfgQueueInfoMap::const_iterator itOther;
|
||||
LfgDungeonSet::const_iterator itDungeon;
|
||||
|
||||
// Get the first group and compare with the others to select all common dungeons
|
||||
for (itDungeon = itFirst->second->dungeons.begin(); itDungeon != itFirst->second->dungeons.end(); ++itDungeon)
|
||||
{
|
||||
itOther = itFirst;
|
||||
compatibleDungeon = true;
|
||||
for (++itOther; itOther != pqInfoMap.end() && compatibleDungeon; ++itOther)
|
||||
if (itOther->second->dungeons.find(*itDungeon) == itOther->second->dungeons.end())
|
||||
compatibleDungeon = false;
|
||||
if (compatibleDungeon)
|
||||
compatibleDungeons->insert(*itDungeon);
|
||||
}
|
||||
|
||||
// now remove those with restrictions
|
||||
LfgLockStatusMap *pLockDungeons = GetGroupLockStatusDungeons(&players, compatibleDungeons);
|
||||
if (pLockDungeons) // Found dungeons not compatible, remove them from the set
|
||||
{
|
||||
LfgLockStatusSet *pLockSet = NULL;
|
||||
for (LfgLockStatusMap::const_iterator itLockMap = pLockDungeons->begin(); itLockMap != pLockDungeons->end() && compatibleDungeons->size(); ++itLockMap)
|
||||
{
|
||||
pLockSet = itLockMap->second;
|
||||
for(LfgLockStatusSet::const_iterator itLockSet = pLockSet->begin(); itLockSet != pLockSet->end(); ++itLockSet)
|
||||
{
|
||||
itDungeon = compatibleDungeons->find((*itLockSet)->dungeon);
|
||||
if (itDungeon != compatibleDungeons->end())
|
||||
compatibleDungeons->erase(itDungeon);
|
||||
}
|
||||
pLockSet->clear();
|
||||
delete pLockSet;
|
||||
}
|
||||
pLockDungeons->clear();
|
||||
delete pLockDungeons;
|
||||
}
|
||||
|
||||
pqInfoMap.clear();
|
||||
// Any compatible dungeon after checking restrictions?
|
||||
if (!compatibleDungeons->size())
|
||||
{
|
||||
delete compatibleDungeons;
|
||||
compatibleDungeons = NULL;
|
||||
players.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Select a random dungeon from the compatible list
|
||||
itDungeon = compatibleDungeons->begin();
|
||||
uint32 selectedDungeon = urand(0, compatibleDungeons->size() - 1);
|
||||
while (selectedDungeon > 0)
|
||||
{
|
||||
++itDungeon;
|
||||
--selectedDungeon;
|
||||
}
|
||||
selectedDungeon = *itDungeon;
|
||||
compatibleDungeons->clear();
|
||||
delete compatibleDungeons;
|
||||
|
||||
// Create a new proposal
|
||||
LfgProposal *pProposal = new LfgProposal(selectedDungeon);
|
||||
pProposal->cancelTime = time_t(time(NULL)) + LFG_TIME_PROPOSAL;
|
||||
pProposal->queues = check;
|
||||
pProposal->groupLowGuid = groupLowGuid;
|
||||
|
||||
// Assign new roles to players and assign new leader
|
||||
LfgProposalPlayer *ppPlayer;
|
||||
uint32 lowGuid;
|
||||
PlayerSet::const_iterator itPlayers = players.begin();
|
||||
if (!newLeaderLowGuid)
|
||||
{
|
||||
uint8 pos = urand(0, players.size() - 1);
|
||||
for (uint8 i = 0; i < pos; ++i)
|
||||
++itPlayers;
|
||||
newLeaderLowGuid = (*itPlayers)->GetGUIDLow();
|
||||
}
|
||||
pProposal->leaderLowGuid = newLeaderLowGuid;
|
||||
|
||||
for (itPlayers = players.begin(); itPlayers != players.end(); ++itPlayers)
|
||||
{
|
||||
lowGuid = (*itPlayers)->GetGUIDLow();
|
||||
ppPlayer = new LfgProposalPlayer();
|
||||
if ((*itPlayers)->GetGroup())
|
||||
{
|
||||
ppPlayer->groupLowGuid = (*itPlayers)->GetGroup()->GetLowGUID();
|
||||
if (ppPlayer->groupLowGuid == pProposal->groupLowGuid) // Player from existing group, autoaccept
|
||||
ppPlayer->accept = 1;
|
||||
}
|
||||
ppPlayer->role = rolesMap[lowGuid];
|
||||
pProposal->players[lowGuid] = ppPlayer;
|
||||
}
|
||||
if (!proposals)
|
||||
proposals = new LfgProposalList();
|
||||
proposals->push_back(pProposal);
|
||||
players.clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the Role check info with the player selected role.
|
||||
/// </summary>
|
||||
@@ -612,6 +901,210 @@ bool LFGMgr::CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag /*= true
|
||||
return tank == LFG_TANKS_NEEDED && healer == LFG_HEALERS_NEEDED && damage == LFG_DPS_NEEDED;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Proposal info with player answer
|
||||
/// </summary>
|
||||
/// <param name="uint32">Id of the proposal</param>
|
||||
/// <param name="uint32">Player low guid</param>
|
||||
/// <param name="uint8">Player answer</param>
|
||||
void LFGMgr::UpdateProposal(uint32 proposalId, uint32 lowGuid, uint8 accept)
|
||||
{
|
||||
// Check if the proposal exists
|
||||
LfgProposalMap::iterator itProposal = m_Proposals.find(proposalId);
|
||||
if (itProposal == m_Proposals.end())
|
||||
return;
|
||||
LfgProposal *pProposal = itProposal->second;
|
||||
|
||||
// Check if proposal have the current player
|
||||
LfgProposalPlayer *ppPlayer = pProposal->players[lowGuid];
|
||||
if (!ppPlayer)
|
||||
return;
|
||||
|
||||
ppPlayer->accept = accept;
|
||||
if (!accept)
|
||||
{
|
||||
RemoveProposal(itProposal, LFG_UPDATETYPE_PROPOSAL_DECLINED);
|
||||
return;
|
||||
}
|
||||
|
||||
LfgPlayerList players;
|
||||
Player *plr;
|
||||
|
||||
// check if all have answered and reorder players (leader first)
|
||||
bool allAnswered = true;
|
||||
for (LfgProposalPlayerMap::const_iterator itPlayers = pProposal->players.begin(); itPlayers != pProposal->players.end(); ++itPlayers)
|
||||
{
|
||||
plr = sObjectMgr.GetPlayer(itPlayers->first);
|
||||
|
||||
if (plr && itPlayers->first == pProposal->leaderLowGuid)
|
||||
players.push_front(plr);
|
||||
else
|
||||
players.push_back(plr);
|
||||
|
||||
if (itPlayers->second->accept < 1) // No answer (-1) or not accepted (0)
|
||||
allAnswered = false;
|
||||
}
|
||||
|
||||
if (!allAnswered)
|
||||
{
|
||||
for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
|
||||
SendUpdateProposal(*it, proposalId, pProposal);
|
||||
}
|
||||
else
|
||||
{
|
||||
pProposal->state = LFG_PROPOSAL_SUCCESS;
|
||||
|
||||
// Create a new group (if needed)
|
||||
Group *grp = sObjectMgr.GetGroupByGUID(pProposal->groupLowGuid);
|
||||
for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
|
||||
{
|
||||
plr = *it;
|
||||
SendUpdateProposal(plr, proposalId, pProposal);
|
||||
//plr->SetLfgSendUpdates(false);
|
||||
if (plr->GetGroup())
|
||||
{
|
||||
if (plr->GetGroup() != grp)
|
||||
plr->RemoveFromGroup();
|
||||
plr->GetSession()->SendLfgUpdateParty(LFG_UPDATETYPE_GROUP_FOUND);
|
||||
}
|
||||
else
|
||||
plr->GetSession()->SendLfgUpdatePlayer(LFG_UPDATETYPE_GROUP_FOUND);
|
||||
|
||||
if (!grp)
|
||||
{
|
||||
grp = new Group();
|
||||
grp->Create(plr->GetGUID(), plr->GetName());
|
||||
grp->ConvertToLFG();
|
||||
sObjectMgr.AddGroup(grp);
|
||||
}
|
||||
else if (plr->GetGroup() != grp)
|
||||
grp->AddMember(plr->GetGUID(), plr->GetName());
|
||||
grp->SetLfgRoles(plr->GetGUID(), pProposal->players[plr->GetGUIDLow()]->role);
|
||||
//plr->SetLfgSendUpdates(true);
|
||||
}
|
||||
|
||||
// Set the dungeon difficulty
|
||||
LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(pProposal->dungeonId);
|
||||
ASSERT(dungeon);
|
||||
grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
|
||||
grp->SetLfgDungeonEntry(dungeon->Entry());
|
||||
grp->SetLfgStatus(LFG_STATUS_NOT_SAVED);
|
||||
grp->SendUpdate();
|
||||
|
||||
// Remove players/groups from Queue
|
||||
for (LfgGuidList::const_iterator it = pProposal->queues.begin(); it != pProposal->queues.end(); ++it)
|
||||
RemoveFromQueue(*it);
|
||||
|
||||
// Teleport Player
|
||||
for (LfgPlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
|
||||
TeleportPlayer(*it, false);
|
||||
|
||||
for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
|
||||
delete it->second;
|
||||
pProposal->players.clear();
|
||||
pProposal->queues.clear();
|
||||
delete pProposal;
|
||||
m_Proposals.erase(itProposal);
|
||||
}
|
||||
players.clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a proposal from the pool, remove the group that didn't accept (if needed) and readd the other members to the queue
|
||||
/// </summary>
|
||||
/// <param name="LfgProposalMap::iterator">Proposal to remove</param>
|
||||
/// <param name="LfgUpdateType">Type of removal (LFG_UPDATETYPE_PROPOSAL_FAILED, LFG_UPDATETYPE_PROPOSAL_DECLINED)</param>
|
||||
void LFGMgr::RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type)
|
||||
{
|
||||
Player *plr;
|
||||
uint64 guid;
|
||||
LfgUpdateType updateType;
|
||||
LfgQueueInfoMap::iterator itQueue;
|
||||
LfgProposal *pProposal = itProposal->second;
|
||||
pProposal->state = LFG_PROPOSAL_FAILED;
|
||||
|
||||
// Mark all people that didn't answered as no accept
|
||||
if (LFG_UPDATETYPE_PROPOSAL_FAILED)
|
||||
for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
|
||||
if (it->second->accept < 1)
|
||||
it->second->accept = 0;
|
||||
|
||||
// Inform players
|
||||
for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
|
||||
{
|
||||
plr = sObjectMgr.GetPlayer(it->first);
|
||||
if (!plr)
|
||||
continue;
|
||||
guid = plr->GetGroup() ? plr->GetGroup()->GetGUID(): plr->GetGUID();
|
||||
|
||||
SendUpdateProposal(plr, itProposal->first, pProposal);
|
||||
if (!it->second->accept) // Remove player/player group from queues
|
||||
{
|
||||
updateType = type;
|
||||
plr->GetLfgDungeons()->clear();
|
||||
plr->SetLfgRoles(ROLE_NONE);
|
||||
itQueue = m_QueueInfoMap.find(guid);
|
||||
if (itQueue != m_QueueInfoMap.end())
|
||||
m_QueueInfoMap.erase(itQueue);
|
||||
}
|
||||
else // Readd to queue
|
||||
{
|
||||
m_newToQueue.push_back(guid);
|
||||
updateType = LFG_UPDATETYPE_ADDED_TO_QUEUE;
|
||||
}
|
||||
|
||||
if (plr->GetGroup())
|
||||
plr->GetSession()->SendLfgUpdateParty(updateType);
|
||||
else
|
||||
plr->GetSession()->SendLfgUpdatePlayer(updateType);
|
||||
|
||||
}
|
||||
|
||||
for (LfgProposalPlayerMap::const_iterator it = pProposal->players.begin(); it != pProposal->players.end(); ++it)
|
||||
delete it->second;
|
||||
pProposal->players.clear();
|
||||
pProposal->queues.clear();
|
||||
delete pProposal;
|
||||
m_Proposals.erase(itProposal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports the player in or out the dungeon
|
||||
/// </summary>
|
||||
/// <param name="Player *">Player</param>
|
||||
/// <param name="bool">Teleport out</param>
|
||||
void LFGMgr::TeleportPlayer(Player *plr, bool out)
|
||||
{
|
||||
if (out)
|
||||
{
|
||||
plr->TeleportToBGEntryPoint();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plr->isAlive())
|
||||
{
|
||||
plr->GetSession()->SendLfgTeleportError(LFG_TELEPORTERROR_PLAYER_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plr->IsFalling() || plr->hasUnitState(UNIT_STAT_JUMPING))
|
||||
{
|
||||
plr->GetSession()->SendLfgTeleportError(LFG_TELEPORTERROR_FALLING);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Add support for LFG_TELEPORTERROR_FATIGUE and LFG_TELEPORTERROR_INVALID_LOCATION
|
||||
if (Group *grp = plr->GetGroup())
|
||||
if (LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(grp->GetLfgDungeonEntry()))
|
||||
if (AreaTrigger const* at = sObjectMgr.GetMapEntranceTrigger(dungeon->map))
|
||||
{
|
||||
if (!plr->GetMap()->IsDungeon() && !plr->GetMap()->IsRaid())
|
||||
plr->SetBattlegroundEntryPoint();
|
||||
// TODO: Teleport to group
|
||||
plr->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------//
|
||||
// Packet Functions
|
||||
// --------------------------------------------------------------------------//
|
||||
@@ -663,6 +1156,57 @@ void LFGMgr::BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build Proposal Update packet
|
||||
/// </summary>
|
||||
/// <param name="Player *">Player</param>
|
||||
/// <param name="uint32">ProposalID</param>
|
||||
/// <param name="LfgProposal *">Internal LFG Proposal</param>
|
||||
/// <returns></returns>
|
||||
void LFGMgr::SendUpdateProposal(Player *plr, uint32 proposalId, LfgProposal *pProp)
|
||||
{
|
||||
ASSERT(pProp);
|
||||
ASSERT(plr);
|
||||
uint32 pLogGuid = plr->GetGUIDLow();
|
||||
LfgProposalPlayerMap::const_iterator itPlayer = pProp->players.find(pLogGuid);
|
||||
ASSERT(itPlayer != pProp->players.end()); // Player MUST be in the proposal
|
||||
LfgProposalPlayer *ppPlayer = itPlayer->second;
|
||||
uint32 pLowGroupGuid = ppPlayer->groupLowGuid;
|
||||
uint32 dLowGuid = pProp->groupLowGuid;
|
||||
|
||||
sLog.outDebug("SMSG_LFG_PROPOSAL_UPDATE");
|
||||
WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + pProp->players.size() * (4 + 1 + 1 + 1 + 1 +1));
|
||||
if (plr->GetLfgDungeons()->size() == 1 && *plr->GetLfgDungeons()->begin() != pProp->dungeonId)
|
||||
data << uint32(*plr->GetLfgDungeons()->begin()); // Random dungeon
|
||||
else
|
||||
data << uint32(pProp->dungeonId); // Dungeon
|
||||
data << uint8(pProp->state); // Result state
|
||||
data << uint32(proposalId); // Internal Proposal ID
|
||||
data << uint32(0); // Bosses killed - FIXME
|
||||
data << uint8(pLowGroupGuid && pLowGroupGuid == dLowGuid); // Silent (show client window)
|
||||
data << uint8(pProp->players.size()); // Group size
|
||||
|
||||
for (itPlayer = pProp->players.begin(); itPlayer != pProp->players.end(); ++itPlayer)
|
||||
{
|
||||
ppPlayer = itPlayer->second;
|
||||
data << uint32(ppPlayer->role); // Role
|
||||
data << uint8(itPlayer->first == pLogGuid); // Self player
|
||||
if (!ppPlayer->groupLowGuid) // Player not it a group
|
||||
{
|
||||
data << uint8(0); // Not in dungeon
|
||||
data << uint8(0); // Not same group
|
||||
}
|
||||
else
|
||||
{
|
||||
data << uint8(ppPlayer->groupLowGuid == dLowGuid); // In dungeon (silent)
|
||||
data << uint8(ppPlayer->groupLowGuid == pLowGroupGuid); // Same Group than player
|
||||
}
|
||||
data << uint8(ppPlayer->accept != -1); // Answered
|
||||
data << uint8(ppPlayer->accept == 1); // Accepted
|
||||
}
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build and Send LFG lock player info and reward
|
||||
/// </summary>
|
||||
@@ -732,6 +1276,44 @@ void LFGMgr::SendLfgPartyInfo(Player *plr)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build and Send LFG player reward
|
||||
/// </summary>
|
||||
/// <param name="Player *">Player</param>
|
||||
void LFGMgr::SendLfgPlayerReward(Player *plr)
|
||||
{
|
||||
uint32 rdungeonId = 0;
|
||||
uint32 sdungeonId = 0;
|
||||
LFGDungeonEntry const *dungeon = sLFGDungeonStore.LookupEntry(*plr->GetLfgDungeons()->begin());
|
||||
if (dungeon)
|
||||
rdungeonId = dungeon->Entry();
|
||||
if (plr->GetGroup())
|
||||
sdungeonId = plr->GetGroup()->GetLfgDungeonEntry(false);
|
||||
bool done = plr->isLfgDungeonDone(rdungeonId);
|
||||
LfgReward *reward = GetRandomDungeonReward(rdungeonId, done, plr->getLevel());
|
||||
ASSERT(reward);
|
||||
uint8 itemNum = uint8(reward->itemId != 0);
|
||||
|
||||
sLog.outDebug("SMSG_LFG_PLAYER_REWARD");
|
||||
WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4));
|
||||
data << uint32(rdungeonId); // Random Dungeon Finished
|
||||
data << uint32(sdungeonId); // Dungeon Finished
|
||||
data << uint8(done);
|
||||
data << uint32(reward->strangers);
|
||||
data << uint32(reward->baseMoney);
|
||||
data << uint32(reward->baseXP);
|
||||
data << uint32(reward->variableMoney);
|
||||
data << uint32(reward->variableXP);
|
||||
data << uint8(itemNum);
|
||||
if (itemNum)
|
||||
{
|
||||
data << uint32(reward->itemId);
|
||||
data << uint32(reward->displayId);
|
||||
data << uint32(reward->stackCount);
|
||||
}
|
||||
plr->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build Party Dungeon lock status packet
|
||||
/// </summary>
|
||||
|
||||
@@ -27,12 +27,15 @@
|
||||
enum LFGenum
|
||||
{
|
||||
LFG_TIME_ROLECHECK = 2*MINUTE,
|
||||
LFG_TIME_PROPOSAL = 2*MINUTE,
|
||||
LFG_VOTES_NEEDED = 3,
|
||||
LFG_TANKS_NEEDED = 1,
|
||||
LFG_HEALERS_NEEDED = 1,
|
||||
LFG_DPS_NEEDED = 3,
|
||||
LFG_QUEUEUPDATE_INTERVAL = 15000,
|
||||
LFG_SPELL_COOLDOWN = 71328,
|
||||
LFG_SPELL_DESERTER = 71041,
|
||||
LFG_MAX_KICKS = 3,
|
||||
};
|
||||
|
||||
enum LfgType
|
||||
@@ -45,6 +48,13 @@ enum LfgType
|
||||
LFG_TYPE_RANDOM = 6,
|
||||
};
|
||||
|
||||
enum LfgProposalState
|
||||
{
|
||||
LFG_PROPOSAL_INITIATING = 0,
|
||||
LFG_PROPOSAL_FAILED = 1,
|
||||
LFG_PROPOSAL_SUCCESS = 2,
|
||||
};
|
||||
|
||||
enum LfgGroupType
|
||||
{
|
||||
LFG_GROUPTYPE_ALL = 0, // Internal use, represents all groups.
|
||||
@@ -75,6 +85,19 @@ enum LfgLockStatusType
|
||||
LFG_LOCKSTATUS_NOT_IN_SEASON = 1031,
|
||||
};
|
||||
|
||||
enum LfgTeleportError
|
||||
{
|
||||
//LFG_TELEPORTERROR_UNK1 = 0, // No reaction
|
||||
LFG_TELEPORTERROR_PLAYER_DEAD = 1,
|
||||
LFG_TELEPORTERROR_FALLING = 2,
|
||||
//LFG_TELEPORTERROR_UNK2 = 3, // You can't do that right now
|
||||
LFG_TELEPORTERROR_FATIGUE = 4,
|
||||
//LFG_TELEPORTERROR_UNK3 = 5, // No reaction
|
||||
LFG_TELEPORTERROR_INVALID_LOCATION = 6,
|
||||
//LFG_TELEPORTERROR_UNK4 = 7, // You can't do that right now
|
||||
//LFG_TELEPORTERROR_UNK5 = 8, // You can't do that right now
|
||||
};
|
||||
|
||||
enum LfgJoinResult
|
||||
{
|
||||
LFG_JOIN_OK = 0, // Joined (no client msg)
|
||||
@@ -135,6 +158,13 @@ enum LfgRewardEnums
|
||||
LFG_REWARD_DATA_SIZE = 10,
|
||||
};
|
||||
|
||||
enum LfgDungeonStatus
|
||||
{
|
||||
LFG_STATUS_SAVED = 0,
|
||||
LFG_STATUS_NOT_SAVED = 1,
|
||||
LFG_STATUS_COMPLETE = 2,
|
||||
};
|
||||
|
||||
const uint32 RewardDungeonData[LFG_REWARD_DATA_SIZE+1][5] =
|
||||
{ // XP, money, item, item display, count
|
||||
{310, 3500, 51999, 56915, 1}, // Classic 15-23
|
||||
@@ -201,6 +231,38 @@ struct LfgQueueInfo
|
||||
LfgRolesMap roles; // Selected Player Role/s
|
||||
};
|
||||
|
||||
struct LfgProposalPlayer
|
||||
{
|
||||
LfgProposalPlayer(): role(0), accept(-1), groupLowGuid(0) {};
|
||||
uint8 role; // Proposed role
|
||||
int8 accept; // Accept status (-1 not answer | 0 Not agree | 1 agree)
|
||||
uint32 groupLowGuid; // Original group guid (Low guid) 0 if no original group
|
||||
};
|
||||
|
||||
typedef std::map<uint32, LfgProposalPlayer*> LfgProposalPlayerMap;
|
||||
|
||||
// Stores all Dungeon Proposal after matching candidates
|
||||
struct LfgProposal
|
||||
{
|
||||
LfgProposal(uint32 dungeon): state(LFG_PROPOSAL_INITIATING), groupLowGuid(0), dungeonId(dungeon), leaderLowGuid(0) {}
|
||||
|
||||
~LfgProposal()
|
||||
{
|
||||
for (LfgProposalPlayerMap::iterator it = players.begin(); it != players.end(); ++it)
|
||||
delete it->second;
|
||||
players.clear();
|
||||
queues.clear();
|
||||
};
|
||||
uint32 dungeonId; // Dungeon to join
|
||||
LfgProposalState state; // State of the proposal
|
||||
uint32 groupLowGuid; // Proposal group (0 if new)
|
||||
uint32 leaderLowGuid; // Leader guid.
|
||||
time_t cancelTime; // Time when we will cancel this proposal
|
||||
LfgGuidList queues; // Queue Ids to remove/readd
|
||||
LfgProposalPlayerMap players; // Player current groupId
|
||||
|
||||
};
|
||||
|
||||
// Stores all rolecheck info of a group that wants to join LFG
|
||||
struct LfgRoleCheck
|
||||
{
|
||||
@@ -215,9 +277,11 @@ typedef std::set<Player*> PlayerSet;
|
||||
typedef std::set<LfgLockStatus*> LfgLockStatusSet;
|
||||
typedef std::vector<LfgReward*> LfgRewardList;
|
||||
typedef std::map<uint32, LfgReward*> LfgRewardMap;
|
||||
typedef std::vector<LfgProposal*> LfgProposalList;
|
||||
typedef std::map<uint32, LfgLockStatusSet*> LfgLockStatusMap;
|
||||
typedef std::map<uint64, LfgQueueInfo*> LfgQueueInfoMap;
|
||||
typedef std::map<uint32, LfgRoleCheck*> LfgRoleCheckMap;
|
||||
typedef std::map<uint32, LfgProposal*> LfgProposalMap;
|
||||
typedef std::list<Player *> LfgPlayerList;
|
||||
|
||||
class LFGMgr
|
||||
@@ -230,6 +294,9 @@ class LFGMgr
|
||||
void InitLFG();
|
||||
void Join(Player *plr);
|
||||
void Leave(Player *plr, Group *grp = NULL);
|
||||
void OfferContinue(Group *grp);
|
||||
void TeleportPlayer(Player *plr, bool out);
|
||||
void UpdateProposal(uint32 proposalId, uint32 lowGuid, uint8 accept);
|
||||
void UpdateRoleCheck(Group *grp, Player *plr = NULL);
|
||||
void Update(uint32 diff);
|
||||
|
||||
@@ -237,6 +304,9 @@ class LFGMgr
|
||||
void SendLfgPartyInfo(Player *plr);
|
||||
|
||||
private:
|
||||
void SendUpdateProposal(Player *plr, uint32 proposalId, LfgProposal *pProp);
|
||||
void SendLfgPlayerReward(Player *plr);
|
||||
|
||||
void BuildLfgRoleCheck(WorldPacket &data, LfgRoleCheck *pRoleCheck);
|
||||
void BuildAvailableRandomDungeonList(WorldPacket &data, Player *plr);
|
||||
void BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lockSet);
|
||||
@@ -245,7 +315,9 @@ class LFGMgr
|
||||
void AddToQueue(uint64 guid, LfgRolesMap *roles, LfgDungeonSet *dungeons);
|
||||
bool RemoveFromQueue(uint64 guid);
|
||||
bool isRandomDungeon(uint32 dungeonId);
|
||||
void FindNewGroups(LfgGuidList &check, LfgGuidList all, LfgProposalList *proposals);
|
||||
bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true);
|
||||
void RemoveProposal(LfgProposalMap::iterator itProposal, LfgUpdateType type);
|
||||
|
||||
LfgLockStatusMap* GetGroupLockStatusDungeons(PlayerSet *pPlayers, LfgDungeonSet *dungeons);
|
||||
LfgLockStatusMap* GetPartyLockStatusDungeons(Player *plr, LfgDungeonSet *dungeons);
|
||||
@@ -262,6 +334,7 @@ class LFGMgr
|
||||
LfgQueueInfoMap m_QueueInfoMap; // Queued groups
|
||||
LfgGuidList m_currentQueue; // Ordered list. Used to find groups
|
||||
LfgGuidList m_newToQueue; // New groups to add to queue;
|
||||
LfgProposalMap m_Proposals; // Current Proposals
|
||||
LfgRoleCheckMap m_RoleChecks; // Current Role checks
|
||||
uint32 m_QueueTimer; // used to check interval of update
|
||||
uint32 m_lfgProposalId; // used as internal counter for proposals
|
||||
|
||||
@@ -49,7 +49,7 @@ Group::Group()
|
||||
m_counter = 0;
|
||||
m_maxEnchantingLevel= 0;
|
||||
m_LfgQueued = false;
|
||||
m_LfgStatus = 1;
|
||||
m_LfgStatus = LFG_STATUS_NOT_SAVED;
|
||||
m_LfgDungeonEntry = 0;
|
||||
|
||||
for (uint8 i = 0; i < TARGETICONCOUNT; ++i)
|
||||
@@ -355,6 +355,8 @@ uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
|
||||
|
||||
if (isLfgQueued())
|
||||
sLFGMgr.Leave(NULL, this);
|
||||
else if (isLFGGroup())
|
||||
sLFGMgr.OfferContinue(this);
|
||||
|
||||
// remove member and change leader (if need) only if strong more 2 members _before_ member remove
|
||||
if (GetMembersCount() > (isBGGroup() ? 1 : 2)) // in BG group case allow 1 members group
|
||||
|
||||
@@ -203,7 +203,8 @@ class Group
|
||||
return (m_LfgDungeonEntry & 0x00FFFFFF);
|
||||
else
|
||||
return m_LfgDungeonEntry;
|
||||
}
|
||||
}
|
||||
|
||||
void SetLfgRoles(uint64 guid, const uint8 roles)
|
||||
{
|
||||
member_witerator slot = _getMemberWSlot(guid);
|
||||
|
||||
@@ -384,6 +384,8 @@ void WorldSession::HandleGroupDisbandOpcode(WorldPacket & /*recv_data*/)
|
||||
SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), ERR_PARTY_RESULT_OK);
|
||||
|
||||
GetPlayer()->RemoveFromGroup();
|
||||
if (grp->isLFGGroup() && GetPlayer()->GetMap()->IsDungeon())
|
||||
GetPlayer()->TeleportToBGEntryPoint();
|
||||
}
|
||||
|
||||
void WorldSession::HandleLootMethodOpcode(WorldPacket & recv_data)
|
||||
|
||||
@@ -78,6 +78,9 @@ void WorldSession::HandleLfgProposalResultOpcode(WorldPacket &recv_data)
|
||||
uint8 accept; // Accept to join?
|
||||
recv_data >> lfgGroupID;
|
||||
recv_data >> accept;
|
||||
|
||||
if (accept < 2)
|
||||
sLFGMgr.UpdateProposal(lfgGroupID, GetPlayer()->GetGUIDLow(), accept);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfgSetRolesOpcode(WorldPacket &recv_data)
|
||||
@@ -110,6 +113,7 @@ void WorldSession::HandleLfgSetBootVoteOpcode(WorldPacket &recv_data)
|
||||
|
||||
uint8 agree; // Agree to kick player
|
||||
recv_data >> agree;
|
||||
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfgTeleportOpcode(WorldPacket &recv_data)
|
||||
@@ -118,6 +122,8 @@ void WorldSession::HandleLfgTeleportOpcode(WorldPacket &recv_data)
|
||||
|
||||
bool out;
|
||||
recv_data >> out;
|
||||
|
||||
sLFGMgr.TeleportPlayer(GetPlayer(), out);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket &/*recv_data*/)
|
||||
@@ -129,6 +135,7 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket &/*recv_data
|
||||
void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket &/*recv_data*/)
|
||||
{
|
||||
sLog.outDebug("CMSG_LFD_PARTY_LOCK_INFO_REQUEST");
|
||||
//sLFGMgr.SendLfgPartyInfo(GetPlayer());
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfrSearchOpcode(WorldPacket &recv_data)
|
||||
@@ -137,6 +144,7 @@ void WorldSession::HandleLfrSearchOpcode(WorldPacket &recv_data)
|
||||
|
||||
uint32 entry; // Raid id to search
|
||||
recv_data >> entry;
|
||||
//SendLfrUpdateListOpcode(entry);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfrLeaveOpcode(WorldPacket &recv_data)
|
||||
@@ -145,6 +153,7 @@ void WorldSession::HandleLfrLeaveOpcode(WorldPacket &recv_data)
|
||||
|
||||
uint32 dungeonId; // Raid id queue to leave
|
||||
recv_data >> dungeonId;
|
||||
//sLFGMgr.LeaveLfr(GetPlayer(), dungeonId);
|
||||
}
|
||||
|
||||
void WorldSession::SendLfgUpdatePlayer(uint8 updateType)
|
||||
@@ -312,4 +321,14 @@ void WorldSession::SendLfgTeleportError(uint8 err)
|
||||
WorldPacket data(SMSG_LFG_TELEPORT_DENIED, 4);
|
||||
data << uint32(err); // Error
|
||||
SendPacket(&data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void WorldSession::SendLfrUpdateListOpcode(uint32 entry)
|
||||
{
|
||||
sLog.outDebug("SMSG_UPDATE_LFG_LIST");
|
||||
WorldPacket data(SMSG_UPDATE_LFG_LIST);
|
||||
sLFGMgr.BuildLfrUpdateList(data, entry);
|
||||
SendPacket(&data);
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user