void InitSentinelsNear(Unit* pTarget) { if (!m_lAssistList.empty()) { for (GuidList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) { if (*itr == m_creature->GetObjectGuid()) continue; if (Creature* pBuddy = m_creature->GetMap()->GetCreature(*itr)) { if (pBuddy->isAlive()) pBuddy->AI()->AttackStart(pTarget); } } return; } std::list<Creature*> lAssistList; GetCreatureListWithEntryInGrid(lAssistList, m_creature, m_creature->GetEntry(), 80.0f); for (std::list<Creature*>::iterator iter = lAssistList.begin(); iter != lAssistList.end(); ++iter) { m_lAssistList.push_back((*iter)->GetObjectGuid()); if ((*iter)->GetObjectGuid() == m_creature->GetObjectGuid()) continue; (*iter)->AI()->AttackStart(pTarget); } if (m_lAssistList.size() != MAX_BUDDY) script_error_log("npc_anubisath_sentinel for %s found too few/too many buddies, expected %u.", m_creature->GetGuidStr().c_str(), MAX_BUDDY); }
Unit* SelectTargetWithinDist() { ThreatList const& m_threatlist = m_creature->getThreatManager().getThreatList(); if (m_threatlist.empty()) return NULL; GuidList distPositive; for (ThreatList::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) { if (Unit* pTemp = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid())) { //player within 80 yards if ((pTemp->GetTypeId() == TYPEID_PLAYER && !m_creature->IsWithinDist(pTemp, 10.0f) && m_creature->IsWithinDist(pTemp, 80.0f))) distPositive.push_back(pTemp->GetObjectGuid()); } } if (!distPositive.empty()) { GuidList::iterator m_uiPlayerGUID = distPositive.begin(); advance(m_uiPlayerGUID, (rand()%distPositive.size())); if (Player* pTemp = m_creature->GetMap()->GetPlayer(*m_uiPlayerGUID)) return pTemp; } return NULL; }
void UpdateEscortAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); // Check if all Onyxia guards are dead if (m_uiGuardCheckTimer) { if (m_uiGuardCheckTimer <= uiDiff) { uint8 uiDeadGuardsCount = 0; for (GuidList::const_iterator itr = m_lRoyalGuardsGuidList.begin(); itr != m_lRoyalGuardsGuidList.end(); ++itr) { if (Creature* pGuard = m_creature->GetMap()->GetCreature(*itr)) { if (!pGuard->isAlive() && pGuard->GetEntry() == NPC_GUARD_ONYXIA) ++uiDeadGuardsCount; } } if (uiDeadGuardsCount == m_lRoyalGuardsGuidList.size()) { StartNextDialogueText(NPC_GUARD_ONYXIA); m_uiGuardCheckTimer = 0; } else m_uiGuardCheckTimer = 1000; } else m_uiGuardCheckTimer -= uiDiff; } }
// Activate a random Constellation void ActivateRandomConstellation() { // spawn a new set of constellations if empty if (m_lConstellationsGuids.empty()) { DoSpawnConstellations(); m_uiConstellationTimer = 5000; return; } GuidList::iterator iter = m_lConstellationsGuids.begin(); advance(iter, urand(0, m_lConstellationsGuids.size() - 1)); if (Creature* pConstellation = m_creature->GetMap()->GetCreature(*iter)) { // follow second top aggro player if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, uint32(0), SELECT_FLAG_PLAYER)) { pConstellation->GetMotionMaster()->MoveFollow(pTarget, CONTACT_DISTANCE, 0); SendAIEvent(AI_EVENT_CUSTOM_A, m_creature, pConstellation); ++m_uiActiveConstelations; } } m_lConstellationsGuids.remove(*iter); }
void GetAIInformation(ChatHandler& reader) override { if (m_lAssistList.empty()) reader.PSendSysMessage("Anubisath Sentinel - group not assigned, will be assigned OnAggro"); if (m_lAssistList.size() == MAX_BUDDY) reader.PSendSysMessage("Anubisath Sentinel - proper group found"); else reader.PSendSysMessage("Anubisath Sentinel - not correct number of mobs for group found. Number found %u, should be %u", uint32(m_lAssistList.size()), MAX_BUDDY); }
void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FLAMEWAKER_HEALER || pSummoned->GetEntry() == NPC_FLAMEWAKER_ELITE) { m_uiAddsKilled += 1; // Yell if only one Add alive if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size() - 1) DoScriptText(SAY_LAST_ADD, m_creature); // All adds are killed, retreat else if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size()) { m_bHasEncounterFinished = true; m_creature->GetMotionMaster()->MoveTargetedHome(); } } }
// function to return a random arena upper Bunny Creature* SelectRandomUpperBunny() { if (m_lUpperBunniesGuids.empty()) return NULL; GuidList::iterator iter = m_lUpperBunniesGuids.begin(); advance(iter, urand(0, m_lUpperBunniesGuids.size() - 1)); return m_creature->GetMap()->GetCreature(*iter); }
// function to return a random arena bunny for Blizzard spell ObjectGuid SelectRandomBunnyGuid() { if (m_lBunniesGuids.empty()) return ObjectGuid(); GuidList::iterator iter = m_lBunniesGuids.begin(); advance(iter, urand(0, m_lBunniesGuids.size() - 1)); return *iter; }
ObjectGuid SelectRandomCrowdNpc() { if (m_lCrowdGuidList.empty()) return ObjectGuid(); GuidList::iterator iter = m_lCrowdGuidList.begin(); advance(iter, urand(0, m_lCrowdGuidList.size() - 1)); return *iter; }
ObjectGuid SelectRandomVolunteer() { if (m_lVolunteerGuidList.empty()) return ObjectGuid(); GuidList::iterator iter = m_lVolunteerGuidList.begin(); advance(iter, urand(0, m_lVolunteerGuidList.size() - 1)); return *iter; }
void SummonedCreatureJustDied(Creature* pSummoned) override { if (pSummoned->GetEntry() == NPC_FLAMEWAKER_HEALER || pSummoned->GetEntry() == NPC_FLAMEWAKER_ELITE) { m_uiAddsKilled += 1; // If 4 adds (half of them) are dead, make all remaining healers immune to polymorph via aura if (m_uiAddsKilled >= MAX_MAJORDOMO_ADDS / 2) DoCastSpellIfCan(m_creature, SPELL_IMMUNE_POLY); // Yell if only one Add alive if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size() - 1) DoScriptText(SAY_LAST_ADD, m_creature); // All adds are killed, retreat else if (m_uiAddsKilled == m_luiMajordomoAddsGUIDs.size()) { m_bHasEncounterFinished = true; m_creature->GetMotionMaster()->MoveTargetedHome(); } } }
void UpdateEscortAI(const uint32 uiDiff) override { DialogueUpdate(uiDiff); // Check if all Onyxia guards are dead if (m_uiGuardCheckTimer) { if (m_uiGuardCheckTimer <= uiDiff) { uint8 uiDeadGuardsCount = 0; for (GuidList::const_iterator itr = m_lRoyalGuardsGuidList.begin(); itr != m_lRoyalGuardsGuidList.end(); ++itr) { if (Creature* pGuard = m_creature->GetMap()->GetCreature(*itr)) { if (!pGuard->isAlive() && pGuard->GetEntry() == NPC_GUARD_ONYXIA) ++uiDeadGuardsCount; } } if (uiDeadGuardsCount == m_lRoyalGuardsGuidList.size()) { StartNextDialogueText(NPC_GUARD_ONYXIA); m_uiGuardCheckTimer = 0; } else m_uiGuardCheckTimer = 1000; } else m_uiGuardCheckTimer -= uiDiff; } if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiHammerTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_HAMMER_OF_JUSTICE) == CAST_OK) m_uiHammerTimer = 60000; } else m_uiHammerTimer -= uiDiff; if (m_uiCleaveTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_STRONG_CLEAVE) == CAST_OK) m_uiCleaveTimer = urand(1000, 5000); } else m_uiCleaveTimer -= uiDiff; DoMeleeAttackIfReady(); }
void DoSetupAdds() { m_uiSetupAddsTimer = 0; if (!m_pInstance) return; GuidList lAddGuids; m_pInstance->GetKelidanAddList(lAddGuids); // Sort Adds to vector if not already done if (!lAddGuids.empty()) { m_vAddGuids.reserve(lAddGuids.size()); std::list<Creature*> lAdds; for (GuidList::const_iterator itr = lAddGuids.begin(); itr != lAddGuids.end(); ++itr) { if (Creature* pAdd = m_pInstance->instance->GetCreature(*itr)) lAdds.push_back(pAdd); } // Sort them by angle lAdds.sort(SortByAngle(m_creature)); for (std::list<Creature*>::const_iterator itr = lAdds.begin(); itr != lAdds.end(); ++itr) m_vAddGuids.push_back((*itr)->GetObjectGuid()); } // Respawn killed adds and reset counter m_uiKilledAdds = 0; for (GuidVector::const_iterator itr = m_vAddGuids.begin(); itr != m_vAddGuids.end(); ++itr) { Creature* pAdd = m_pInstance->instance->GetCreature(*itr); if (pAdd && !pAdd->isAlive()) pAdd->Respawn(); } // Cast pentagram uint8 s = m_vAddGuids.size(); for (uint8 i = 0; i < s; ++i) { Creature* pCaster = m_pInstance->instance->GetCreature(m_vAddGuids[i]); Creature* pTarget = m_pInstance->instance->GetCreature(m_vAddGuids[(i + 2) % s]); if (pCaster && pTarget) pCaster->CastSpell(pTarget, SPELL_CHANNELING, TRIGGERED_NONE); } m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); }
Creature* instance_zulgurub::SelectRandomPantherTrigger(bool bIsLeft) { GuidList* plTempList = bIsLeft ? &m_lLeftPantherTriggerGUIDList : &m_lRightPantherTriggerGUIDList; std::vector<Creature*> vTriggers; vTriggers.reserve(plTempList->size()); for (GuidList::const_iterator itr = plTempList->begin(); itr != plTempList->end(); ++itr) { if (Creature* pTemp = instance->GetCreature(*itr)) vTriggers.push_back(pTemp); } if (vTriggers.empty()) return NULL; return vTriggers[urand(0, vTriggers.size()-1)]; }
Player* SelectRandomPlayerForMark() { Player* pResult = NULL; GuidList lPlayers; ThreatList const& threatlist = m_creature->getThreatManager().getThreatList(); if (!threatlist.empty()) { for (ThreatList::const_iterator itr = threatlist.begin();itr != threatlist.end(); ++itr) { ObjectGuid const& guid = (*itr)->getUnitGuid(); if (guid.IsPlayer() && guid != m_creature->getVictim()->GetObjectGuid()) // exclude current target { // check if player already has the mark if (Player* pPlayer = m_creature->GetMap()->GetPlayer(guid)) { if (!pPlayer->HasAura(SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF)) lPlayers.push_back(guid); } } } } if (!lPlayers.empty()) { GuidList::iterator i = lPlayers.begin(); uint32 max = uint32(lPlayers.size() - 1); if (max > 0) std::advance(i, urand(0, max)); pResult = m_creature->GetMap()->GetPlayer(*i); } // last option - current target if (!pResult) { Unit* pVictim = m_creature->getVictim(); if (pVictim && pVictim->GetTypeId() == TYPEID_PLAYER && !pVictim->HasAura(SPELL_MARK_OF_FALLEN_CHAMPION_DEBUFF)) pResult = (Player*)pVictim; } return pResult; }
void UpdateAI(const uint32 uiDiff) override { switch (m_uiPhase) { case PHASE_CHANNEL: if (m_uiSummonDefenderTimer < uiDiff) { DoSummonAshtongue(SPELL_SUMMON_DEFENDER); m_uiSummonDefenderTimer = 15000; } else m_uiSummonDefenderTimer -= uiDiff; if (m_lSorcerersGUIDList.size() <= m_uiChannelersDead) { if (m_uiSummonSorcererTimer < uiDiff) { DoSummonAshtongue(SPELL_SUMMON_SORCERER); m_uiSummonSorcererTimer = urand(20000, 30000); } else m_uiSummonSorcererTimer -= uiDiff; } if (m_uiSummonPackTimer < uiDiff) { DoSummonAshtongue(); m_uiSummonPackTimer = 35000; } else m_uiSummonPackTimer -= uiDiff; break; case PHASE_COMBAT: if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (!m_bHasYelledOnce && m_creature->GetHealthPercent() < 15.0f) { DoScriptText(SAY_LOW_HEALTH, m_creature); m_bHasYelledOnce = true; } if (m_uiDestructivePoisonTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_DESTRUCTIVE_POISON) == CAST_OK) m_uiDestructivePoisonTimer = 15000; } else m_uiDestructivePoisonTimer -= uiDiff; if (m_uiLightningBoltTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHAIN_LIGHTNING) == CAST_OK) m_uiLightningBoltTimer = 10000; } else m_uiLightningBoltTimer -= uiDiff; DoMeleeAttackIfReady(); break; case PHASE_EPILOGUE: DialogueUpdate(uiDiff); break; } }
void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // // Mortal Wound if (m_uiMortalWoundTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MORTAL_WOUND) == CAST_OK) m_uiMortalWoundTimer = urand(4000, 8000); } else m_uiMortalWoundTimer -= uiDiff; // // Summon Worm (1-3) if (m_uiSummonWorm1Timer < uiDiff) { // randomize order of Summon Worm pattern std::random_shuffle(vIndex.begin(), vIndex.end()); m_creature->SummonCreature(NPC_SPAWN_FANKRISS, aSummonWormLocs[vIndex[0]].m_fX, aSummonWormLocs[vIndex[0]].m_fY, aSummonWormLocs[vIndex[0]].m_fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 50000); m_uiSummonWorm1Timer = urand(50000, 70000); m_uiSummonWorm2Timer = urand(1000, 30000); m_uiSummonWorm3Timer = urand(2000, 30000); } else m_uiSummonWorm1Timer -= uiDiff; if (m_uiSummonWorm2Timer) { if (m_uiSummonWorm2Timer <= uiDiff) { m_creature->SummonCreature(NPC_SPAWN_FANKRISS, aSummonWormLocs[vIndex[1]].m_fX, aSummonWormLocs[vIndex[1]].m_fY, aSummonWormLocs[vIndex[1]].m_fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 50000); m_uiSummonWorm2Timer = 0; } else m_uiSummonWorm2Timer -= uiDiff; } if (m_uiSummonWorm3Timer) { if (m_uiSummonWorm3Timer <= uiDiff) { m_creature->SummonCreature(NPC_SPAWN_FANKRISS, aSummonWormLocs[vIndex[2]].m_fX, aSummonWormLocs[vIndex[2]].m_fY, aSummonWormLocs[vIndex[2]].m_fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 50000); m_uiSummonWorm3Timer = 0; } else m_uiSummonWorm3Timer -= uiDiff; } // // Entangle (1-3) if (m_uiEntangle1Timer < uiDiff) { // randomize order of Entangle pattern std::random_shuffle(vEntangleSpells.begin(), vEntangleSpells.end()); if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, nullptr, SELECT_FLAG_PLAYER)) { if (DoCastSpellIfCan(pTarget, vEntangleSpells[0]) == CAST_OK) { m_uiEntangle1Timer = urand(35000, 45000); m_uiEntangle2Timer = urand(2000, 20000); m_uiEntangle3Timer = urand(2000, 20000); m_EntangleTargetGUID = pTarget->GetObjectGuid(); m_uiEntangleSummonTimer = 1000; } } } else m_uiEntangle1Timer -= uiDiff; if (m_uiEntangle2Timer && !m_uiEntangleSummonTimer) { if (m_uiEntangle2Timer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, nullptr, SELECT_FLAG_PLAYER)) { if (DoCastSpellIfCan(pTarget, vEntangleSpells[1]) == CAST_OK) { m_uiEntangle2Timer = 0; m_EntangleTargetGUID = pTarget->GetObjectGuid(); m_uiEntangleSummonTimer = 1000; } } } else m_uiEntangle2Timer -= uiDiff; } if (m_uiEntangle3Timer && !m_uiEntangleSummonTimer) { if (m_uiEntangle3Timer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, nullptr, SELECT_FLAG_PLAYER)) { if (DoCastSpellIfCan(pTarget, vEntangleSpells[2]) == CAST_OK) { m_uiEntangle3Timer = 0; m_EntangleTargetGUID = pTarget->GetObjectGuid(); m_uiEntangleSummonTimer = 1000; } } } else m_uiEntangle3Timer -= uiDiff; } // // Spawn 4 Hatchlings on top of players who have been entangled if (m_uiEntangleSummonTimer) { if (m_uiEntangleSummonTimer < uiDiff) { if (m_lHatchlingsGUIDs.size() < (MAX_HATCHLINGS + 4)) // If there are already more than MAX_HATCHLINGS - 4 up, prevent spawn { if (Player* pTarget = m_creature->GetMap()->GetPlayer(m_EntangleTargetGUID)) { float fX, fY, fZ; for (uint8 i = 0; i < 4; ++i) { m_creature->GetRandomPoint(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 3.0f, fX, fY, fZ); m_creature->SummonCreature(NPC_VEKNISS_HATCHLING, fX, fY, fZ, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 65000); } } } m_uiEntangleAttackTimer = 1500; m_uiEntangleSummonTimer = 0; } else m_uiEntangleSummonTimer -= uiDiff; } // Summoned Hatchlings should be set in combat with Zone after meleeing the person they've spawned next to once (if not picked up by a tank) if (m_uiEntangleAttackTimer) { if (m_uiEntangleAttackTimer < uiDiff) { for (GuidList::const_iterator itr = m_lHatchlingsGUIDs.begin(); itr != m_lHatchlingsGUIDs.end(); itr++) { if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) pSummoned->SetInCombatWithZone(); } } else m_uiEntangleAttackTimer -= uiDiff; } DoMeleeAttackIfReady(); // Evade in case Fankriss starts running after someone at zone in if (m_uiEvadeCheckTimer < uiDiff) { m_uiEvadeCheckTimer = 2500; if (m_creature->GetPositionY() > 1400) EnterEvadeMode(); } else m_uiEvadeCheckTimer -= uiDiff; }
/** Check compatibilities between groups. If group is Matched proposal will be created @param[in] check List of guids to check compatibilities @return LfgCompatibility type of compatibility */ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) { std::string strGuids = ConcatenateGuids(check); LfgProposal proposal; LfgDungeonSet proposalDungeons; LfgGroupsMap proposalGroups; LfgRolesMap proposalRoles; // Check for correct size if (check.size() > MAXGROUPSIZE || check.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s): Size wrong - Not compatibles", strGuids.c_str()); return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE; } // Check all-but-new compatiblitity if (check.size() > 2) { ObjectGuid frontGuid = check.front(); check.pop_front(); // Check all-but-new compatibilities (New, A, B, C, D) --> check(A, B, C, D) LfgCompatibility child_compatibles = CheckCompatibility(check); if (child_compatibles < LFG_COMPATIBLES_WITH_LESS_PLAYERS) // Group not compatible { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) child %s not compatibles", strGuids.c_str(), ConcatenateGuids(check).c_str()); SetCompatibles(strGuids, child_compatibles); return child_compatibles; } check.push_front(frontGuid); } // Check if more than one LFG group and number of players joining uint8 numPlayers = 0; uint8 numLfgGroups = 0; for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) { ObjectGuid guid = *it; LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid); if (itQueue == QueueDataStore.end()) { TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guid: [%s] is not queued but listed as queued!", guid.ToString().c_str()); RemoveFromQueue(guid); return LFG_COMPATIBILITY_PENDING; } // Store group so we don't need to call Mgr to get it later (if it's player group will be 0 otherwise would have joined as group) for (LfgRolesMap::const_iterator it2 = itQueue->second.roles.begin(); it2 != itQueue->second.roles.end(); ++it2) proposalGroups[it2->first] = itQueue->first.IsGroup() ? itQueue->first : ObjectGuid::Empty; numPlayers += itQueue->second.roles.size(); if (sLFGMgr->IsLfgGroup(guid)) { if (!numLfgGroups) proposal.group = guid; ++numLfgGroups; } } // Group with less that MAXGROUPSIZE members always compatible if (check.size() == 1 && numPlayers != MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) sigle group. Compatibles", strGuids.c_str()); LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front()); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); data.roles = itQueue->second.roles; LFGMgr::CheckGroupRoles(data.roles); UpdateBestCompatibleInQueue(itQueue, strGuids, data.roles); SetCompatibilityData(strGuids, data); return LFG_COMPATIBLES_WITH_LESS_PLAYERS; } if (numLfgGroups > 1) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) More than one Lfggroup (%u)", strGuids.c_str(), numLfgGroups); SetCompatibles(strGuids, LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS); return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS; } if (numPlayers > MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); return LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS; } // If it's single group no need to check for duplicate players, ignores, bad roles or bad dungeons as it's been checked before joining if (check.size() > 1) { for (GuidList::const_iterator it = check.begin(); it != check.end(); ++it) { LfgRolesMap const& roles = QueueDataStore[(*it)].roles; for (LfgRolesMap::const_iterator itRoles = roles.begin(); itRoles != roles.end(); ++itRoles) { LfgRolesMap::const_iterator itPlayer; for (itPlayer = proposalRoles.begin(); itPlayer != proposalRoles.end(); ++itPlayer) { if (itRoles->first == itPlayer->first) TC_LOG_ERROR("lfg.queue.match.compatibility.check", "Guids: ERROR! Player multiple times in queue! [%s]", itRoles->first.ToString().c_str()); else if (sLFGMgr->HasIgnore(itRoles->first, itPlayer->first)) break; } if (itPlayer == proposalRoles.end()) proposalRoles[itRoles->first] = itRoles->second; } } if (uint8 playersize = numPlayers - proposalRoles.size()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) not compatible, %u players are ignoring each other", strGuids.c_str(), playersize); SetCompatibles(strGuids, LFG_INCOMPATIBLES_HAS_IGNORES); return LFG_INCOMPATIBLES_HAS_IGNORES; } LfgRolesMap debugRoles = proposalRoles; if (!LFGMgr::CheckGroupRoles(proposalRoles)) { std::ostringstream o; for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it) o << ", " << it->first.GetRawValue() << ": " << GetRolesString(it->second); TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES); return LFG_INCOMPATIBLES_NO_ROLES; } GuidList::iterator itguid = check.begin(); proposalDungeons = QueueDataStore[*itguid].dungeons; std::ostringstream o; o << ", " << itguid->GetRawValue() << ": (" << ConcatenateDungeons(proposalDungeons) << ")"; for (++itguid; itguid != check.end(); ++itguid) { LfgDungeonSet temporal; LfgDungeonSet& dungeons = QueueDataStore[*itguid].dungeons; o << ", " << itguid->GetRawValue() << ": (" << ConcatenateDungeons(dungeons) << ")"; std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); proposalDungeons = temporal; } if (proposalDungeons.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) No compatible dungeons%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_DUNGEONS); return LFG_INCOMPATIBLES_NO_DUNGEONS; } } else { ObjectGuid gguid = *check.begin(); const LfgQueueData &queue = QueueDataStore[gguid]; proposalDungeons = queue.dungeons; proposalRoles = queue.roles; LFGMgr::CheckGroupRoles(proposalRoles); // assing new roles } // Enough players? if (numPlayers != MAXGROUPSIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); data.roles = proposalRoles; for (GuidList::const_iterator itr = check.begin(); itr != check.end(); ++itr) UpdateBestCompatibleInQueue(QueueDataStore.find(*itr), strGuids, data.roles); SetCompatibilityData(strGuids, data); return LFG_COMPATIBLES_WITH_LESS_PLAYERS; } ObjectGuid gguid = *check.begin(); proposal.queues = check; proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON; if (!sLFGMgr->AllQueued(check)) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Group MATCH but can't create proposal!", strGuids.c_str()); SetCompatibles(strGuids, LFG_COMPATIBLES_BAD_STATES); return LFG_COMPATIBLES_BAD_STATES; } // Create a new proposal proposal.cancelTime = time(NULL) + LFG_TIME_PROPOSAL; proposal.state = LFG_PROPOSAL_INITIATING; proposal.leader.Clear(); proposal.dungeonId = Trinity::Containers::SelectRandomContainerElement(proposalDungeons); bool leader = false; for (LfgRolesMap::const_iterator itRoles = proposalRoles.begin(); itRoles != proposalRoles.end(); ++itRoles) { // Assing new leader if (itRoles->second & PLAYER_ROLE_LEADER) { if (!leader || !proposal.leader || urand(0, 1)) proposal.leader = itRoles->first; leader = true; } else if (!leader && (!proposal.leader || urand(0, 1))) proposal.leader = itRoles->first; // Assing player data and roles LfgProposalPlayer &data = proposal.players[itRoles->first]; data.role = itRoles->second; data.group = proposalGroups.find(itRoles->first)->second; if (!proposal.isNew && data.group && data.group == proposal.group) // Player from existing group, autoaccept data.accept = LFG_ANSWER_AGREE; } // Mark proposal members as not queued (but not remove queue data) for (GuidList::const_iterator itQueue = proposal.queues.begin(); itQueue != proposal.queues.end(); ++itQueue) { ObjectGuid guid = (*itQueue); RemoveFromNewQueue(guid); RemoveFromCurrentQueue(guid); } sLFGMgr->AddProposal(proposal); TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) MATCH! Group formed", strGuids.c_str()); SetCompatibles(strGuids, LFG_COMPATIBLES_MATCH); return LFG_COMPATIBLES_MATCH; }