From 59120fbd383fffe0090e5f5eb677630a12971787 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Thu, 20 Feb 2020 05:08:09 +0100 Subject: [PATCH] Core/Quests: ported breadcrumb quest handlings and cleaned up quest template loading handlings --- .../custom/custom_2020_02_20_01_world.sql | 2 + src/server/game/Entities/Player/Player.cpp | 58 ++++++++-- src/server/game/Entities/Player/Player.h | 10 +- src/server/game/Globals/ObjectMgr.cpp | 100 +++++++++++++----- src/server/game/Globals/ObjectMgr.h | 12 +-- src/server/game/Handlers/CharacterHandler.cpp | 9 +- src/server/game/Quests/QuestDef.cpp | 21 ++-- src/server/game/Quests/QuestDef.h | 3 + src/server/scripts/Commands/cs_lookup.cpp | 30 +++--- 9 files changed, 168 insertions(+), 77 deletions(-) create mode 100644 sql/updates/world/custom/custom_2020_02_20_01_world.sql diff --git a/sql/updates/world/custom/custom_2020_02_20_01_world.sql b/sql/updates/world/custom/custom_2020_02_20_01_world.sql new file mode 100644 index 00000000000..607993dbebc --- /dev/null +++ b/sql/updates/world/custom/custom_2020_02_20_01_world.sql @@ -0,0 +1,2 @@ +ALTER TABLE `quest_template_addon` +ADD COLUMN `BreadcrumbForQuestId` MEDIUMINT(8) NOT NULL DEFAULT '0' AFTER `ExclusiveGroup`; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a7e52b7bfc9..92c80ffc0b5 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14663,7 +14663,7 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* quest) const return nullptr; } -bool Player::CanSeeStartQuest(Quest const* quest) +bool Player::CanSeeStartQuest(Quest const* quest) const { if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) && @@ -14677,7 +14677,7 @@ bool Player::CanSeeStartQuest(Quest const* quest) return false; } -bool Player::CanTakeQuest(Quest const* quest, bool msg) +bool Player::CanTakeQuest(Quest const* quest, bool msg) const { return !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg) @@ -15439,7 +15439,8 @@ bool Player::SatisfyQuestLog(bool msg) const bool Player::SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const { - return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg); + return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg) && + SatisfyQuestBreadcrumbQuest(qInfo, msg) && SatisfyQuestDependentBreadcrumbQuests(qInfo, msg); } bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const @@ -15528,6 +15529,51 @@ bool Player::SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) c return false; } +bool Player::SatisfyQuestBreadcrumbQuest(Quest const* qInfo, bool msg) const +{ + uint32 breadcrumbTargetQuestId = std::abs(qInfo->GetBreadcrumbForQuestId()); + + //If this is not a breadcrumb quest. + if (!breadcrumbTargetQuestId) + return true; + + // If the target quest is not available + if (!CanTakeQuest(sObjectMgr->GetQuestTemplate(breadcrumbTargetQuestId), false)) + { + if (msg) + { + SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestBreadcrumbQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because target quest (QuestID: %u) is not available to player '%s' (%s).", + qInfo->GetQuestId(), breadcrumbTargetQuestId, GetName().c_str(), GetGUID().ToString().c_str()); + } + + return false; + } + + return true; +} + +bool Player::SatisfyQuestDependentBreadcrumbQuests(Quest const* qInfo, bool msg) const +{ + for (uint32 breadcrumbQuestId : qInfo->DependentBreadcrumbQuests) + { + QuestStatus status = GetQuestStatus(breadcrumbQuestId); + // If any of the breadcrumb quests are in the quest log, return false. + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED) + { + if (msg) + { + SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); + TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentBreadcrumbQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) has a breadcrumb quest towards this quest in the quest log.", + qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str()); + } + + return false; + } + } + return true; +} + bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const { uint32 reqClass = qInfo->GetAllowableClasses(); @@ -15569,7 +15615,7 @@ bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) const { uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep if (fIdMin && GetReputationMgr().GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue()) @@ -15637,9 +15683,9 @@ bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) const return true; } -bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) +bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) const { - if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, qInfo->GetQuestId(), this)) + if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, qInfo->GetQuestId(), const_cast(this))) { if (msg) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c452614f8ed..736198208ef 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1348,8 +1348,8 @@ class TC_GAME_API Player : public Unit, public GridObject void SendPreparedQuest(ObjectGuid guid); bool IsActiveQuest(uint32 quest_id) const; Quest const* GetNextQuest(ObjectGuid guid, Quest const* quest) const; - bool CanSeeStartQuest(Quest const* quest); - bool CanTakeQuest(Quest const* quest, bool msg); + bool CanSeeStartQuest(Quest const* quest) const; + bool CanTakeQuest(Quest const* quest, bool msg) const; bool CanAddQuest(Quest const* quest, bool msg) const; bool CanCompleteQuest(uint32 quest_id); bool CanCompleteRepeatableQuest(Quest const* quest); @@ -1369,11 +1369,13 @@ class TC_GAME_API Player : public Unit, public GridObject bool SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const; bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const; bool SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const; + bool SatisfyQuestBreadcrumbQuest(Quest const* qInfo, bool msg) const; + bool SatisfyQuestDependentBreadcrumbQuests(Quest const* qInfo, bool msg) const; bool SatisfyQuestClass(Quest const* qInfo, bool msg) const; bool SatisfyQuestRace(Quest const* qInfo, bool msg) const; - bool SatisfyQuestReputation(Quest const* qInfo, bool msg); + bool SatisfyQuestReputation(Quest const* qInfo, bool msg) const; bool SatisfyQuestStatus(Quest const* qInfo, bool msg) const; - bool SatisfyQuestConditions(Quest const* qInfo, bool msg); + bool SatisfyQuestConditions(Quest const* qInfo, bool msg) const; bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const; bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const; bool SatisfyQuestDay(Quest const* qInfo, bool msg) const; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 82d02b7e381..2786a5677f7 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -255,9 +255,6 @@ ObjectMgr* ObjectMgr::instance() ObjectMgr::~ObjectMgr() { - for (QuestMap::iterator i = _questTemplates.begin(); i != _questTemplates.end(); ++i) - delete i->second; - for (PetLevelInfoContainer::iterator i = _petInfoStore.begin(); i != _petInfoStore.end(); ++i) delete[] i->second; @@ -4222,9 +4219,6 @@ void ObjectMgr::LoadQuests() { uint32 oldMSTime = getMSTime(); - // For reload case - for (auto itr = _questTemplates.begin(); itr != _questTemplates.end(); ++itr) - delete itr->second; _questTemplates.clear(); _exclusiveQuestGroups.clear(); @@ -4267,6 +4261,8 @@ void ObjectMgr::LoadQuests() return; } + _questTemplates.reserve(result->GetRowCount()); + // create multimap previous quest for each existed quest // some quests can have many previous maps set by NextQuestId in previous quest // for example set of race quests can lead to single not race specific quest @@ -4274,8 +4270,8 @@ void ObjectMgr::LoadQuests() { Field* fields = result->Fetch(); - Quest* newQuest = new Quest(fields); - _questTemplates[newQuest->GetQuestId()] = newQuest; + uint32 questId = fields[0].GetUInt32(); + _questTemplates.emplace(std::piecewise_construct, std::forward_as_tuple(questId), std::forward_as_tuple(fields)); } while (result->NextRow()); std::unordered_map usedMailTemplates; @@ -4301,9 +4297,9 @@ void ObjectMgr::LoadQuests() // 0 1 2 3 4 5 6 7 8 9 { "ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4, RewardText", "quest_offer_reward", "reward emotes", &Quest::LoadQuestOfferReward }, - // 0 1 2 3 4 5 6 7 8 - { "ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay," - // 9 10 11 12 13 14 15 16 + // 0 1 2 3 4 5 6 7 8 9 + { "ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, BreadcrumbForQuestId, RewardMailTemplateID, RewardMailDelay," + // 10 11 12 13 14 15 16 17 " RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, SpecialFlags", "quest_template_addon", "template addons", &Quest::LoadQuestTemplateAddon }, // 0 1 @@ -4325,7 +4321,7 @@ void ObjectMgr::LoadQuests() auto itr = _questTemplates.find(questId); if (itr != _questTemplates.end()) - (itr->second->*loader.LoaderFunction)(fields); + (itr->second.*loader.LoaderFunction)(fields); else TC_LOG_ERROR("server.loading", "Table `%s` has data for quest %u but such quest does not exist", loader.TableName, questId); } while (result->NextRow()); @@ -4333,13 +4329,13 @@ void ObjectMgr::LoadQuests() } // Post processing - for (auto iter = _questTemplates.begin(); iter != _questTemplates.end(); ++iter) + for (auto& questPair : _questTemplates) { // skip post-loading checks for disabled quests - if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, iter->first, nullptr)) + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) continue; - Quest* qinfo = iter->second; + Quest* qinfo = &questPair.second; // additional quest integrity checks (GO, creature_template and item_template must be loaded already) @@ -4838,10 +4834,9 @@ void ObjectMgr::LoadQuests() usedMailTemplates[qinfo->_rewardMailTemplateId] = qinfo->GetQuestId(); } - if (qinfo->_rewardNextQuest) + if (uint32 rewardNextQuest = qinfo->_rewardNextQuest) { - auto qNextItr = _questTemplates.find(qinfo->_rewardNextQuest); - if (qNextItr == _questTemplates.end()) + if (!_questTemplates.count(rewardNextQuest)) { TC_LOG_ERROR("sql.sql", "Quest %u has `RewardNextQuest` = %u but quest %u does not exist, quest chain will not work.", qinfo->GetQuestId(), qinfo->_rewardNextQuest, qinfo->_rewardNextQuest); @@ -4970,23 +4965,39 @@ void ObjectMgr::LoadQuests() } // fill additional data stores - if (qinfo->_prevQuestId) + if (uint32 prevQuestId = std::abs(qinfo->_prevQuestId)) { - if (_questTemplates.find(std::abs(qinfo->GetPrevQuestId())) == _questTemplates.end()) - TC_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId()); + auto prevQuestItr = _questTemplates.find(prevQuestId); + if (prevQuestItr == _questTemplates.end()) + TC_LOG_ERROR("sql.sql", "Quest %u has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->_prevQuestId); + else if (prevQuestItr->second._breadcrumbForQuestId) + TC_LOG_ERROR("sql.sql", "Quest %u should not be unlocked by breadcrumb quest %u", qinfo->_id, prevQuestId); } - if (qinfo->_nextQuestId) + if (uint32 nextQuestId = qinfo->_nextQuestId) { - auto qNextItr = _questTemplates.find(qinfo->_nextQuestId); - if (qNextItr == _questTemplates.end()) + auto nextQuestItr = _questTemplates.find(nextQuestId); + if (nextQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest %u has NextQuestId %u, but no such quest", qinfo->GetQuestId(), qinfo->_nextQuestId); else - qNextItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId()); + nextQuestItr->second.DependentPreviousQuests.push_back(qinfo->GetQuestId()); + } + + if (uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId)) + { + if (_questTemplates.find(breadcrumbForQuestId) == _questTemplates.end()) + { + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb for quest %u, but no such quest exists", qinfo->_id, breadcrumbForQuestId); + qinfo->_breadcrumbForQuestId = 0; + } + if (qinfo->_nextQuestId) + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb, should not unlock quest %u", qinfo->_id, qinfo->_nextQuestId); + if (qinfo->_exclusiveGroup) + TC_LOG_ERROR("sql.sql", "Quest %u is a breadcrumb in exclusive group %i", qinfo->_id, qinfo->_exclusiveGroup); } if (qinfo->_exclusiveGroup) - _exclusiveQuestGroups.insert(std::pair(qinfo->_exclusiveGroup, qinfo->GetQuestId())); + _exclusiveQuestGroups.emplace(qinfo->_exclusiveGroup, qinfo->GetQuestId()); if (qinfo->_timeAllowed) qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED); if (qinfo->_requiredPlayerKills) @@ -5013,6 +5024,38 @@ void ObjectMgr::LoadQuests() } } + // Disallow any breadcrumb loops and inform quests of their breadcrumbs + for (auto& questPair : _questTemplates) + { + // skip post-loading checks for disabled quests + if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) + continue; + + Quest* qinfo = &questPair.second; + uint32 qid = qinfo->GetQuestId(); + uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId); + std::set questSet; + + while (breadcrumbForQuestId) + { + //a previously visited quest was found as a breadcrumb quest + //breadcrumb loop found! + if (!questSet.insert(qinfo->_id).second) + { + TC_LOG_ERROR("sql.sql", "Breadcrumb quests %u and %u are in a loop", qid, breadcrumbForQuestId); + qinfo->_breadcrumbForQuestId = 0; + break; + } + + qinfo = const_cast(sObjectMgr->GetQuestTemplate(breadcrumbForQuestId)); + + //every quest has a list of every breadcrumb towards it + qinfo->DependentBreadcrumbQuests.push_back(qid); + + breadcrumbForQuestId = qinfo->GetBreadcrumbForQuestId(); + } + } + // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i) { @@ -6513,6 +6556,11 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt return mount_id; } +Quest const* ObjectMgr::GetQuestTemplate(uint32 quest_id) const +{ + return Trinity::Containers::MapGetValuePtr(_questTemplates, quest_id); +} + void ObjectMgr::LoadGraveyardZones() { uint32 oldMSTime = getMSTime(); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index bb14ce710e3..a0ab1575546 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -915,7 +915,7 @@ class TC_GAME_API ObjectMgr static ObjectMgr* instance(); - typedef std::unordered_map QuestMap; + typedef std::unordered_map QuestContainer; typedef std::unordered_map AreaTriggerContainer; @@ -989,13 +989,9 @@ class TC_GAME_API ObjectMgr void GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost); uint32 GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team = false); - Quest const* GetQuestTemplate(uint32 quest_id) const - { - QuestMap::const_iterator itr = _questTemplates.find(quest_id); - return itr != _questTemplates.end() ? itr->second : nullptr; - } + Quest const* GetQuestTemplate(uint32 quest_id) const; - QuestMap const& GetQuestTemplates() const { return _questTemplates; } + QuestContainer const& GetQuestTemplates() const { return _questTemplates; } uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const { @@ -1592,7 +1588,7 @@ class TC_GAME_API ObjectMgr } std::map> _guidGenerators; - QuestMap _questTemplates; + QuestContainer _questTemplates; typedef std::unordered_map GossipTextContainer; typedef std::unordered_map QuestAreaTriggerContainer; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 6ce7ace1a3a..d8e693f9f58 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -2169,16 +2169,15 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptrGetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = questTemplates.begin(); iter != questTemplates.end(); ++iter) + ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates(); + for (auto const& questTemplatePair : questTemplates) { - Quest const* quest = iter->second; uint32 newRaceMask = (newTeam == ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; - if (!(quest->GetAllowableRaces() & newRaceMask)) + if (!(questTemplatePair.second.GetAllowableRaces() & newRaceMask)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST); stmt->setUInt32(0, lowGuid); - stmt->setUInt32(1, quest->GetQuestId()); + stmt->setUInt32(1, questTemplatePair.first); trans->Append(stmt); } } diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 43438a156f4..6c213c88a7c 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -216,16 +216,17 @@ void Quest::LoadQuestTemplateAddon(Field* fields) _prevQuestId = fields[4].GetInt32(); _nextQuestId = fields[5].GetUInt32(); _exclusiveGroup = fields[6].GetInt32(); - _rewardMailTemplateId = fields[7].GetUInt32(); - _rewardMailDelay = fields[8].GetUInt32(); - _requiredSkillId = fields[9].GetUInt16(); - _requiredSkillPoints = fields[10].GetUInt16(); - _requiredMinRepFaction = fields[11].GetUInt16(); - _requiredMaxRepFaction = fields[12].GetUInt16(); - _requiredMinRepValue = fields[13].GetInt32(); - _requiredMaxRepValue = fields[14].GetInt32(); - _startItemCount = fields[15].GetUInt8(); - _specialFlags = fields[16].GetUInt8(); + _breadcrumbForQuestId = fields[7].GetInt32(); + _rewardMailTemplateId = fields[8].GetUInt32(); + _rewardMailDelay = fields[9].GetUInt32(); + _requiredSkillId = fields[10].GetUInt16(); + _requiredSkillPoints = fields[11].GetUInt16(); + _requiredMinRepFaction = fields[12].GetUInt16(); + _requiredMaxRepFaction = fields[13].GetUInt16(); + _requiredMinRepValue = fields[14].GetInt32(); + _requiredMaxRepValue = fields[15].GetInt32(); + _startItemCount = fields[16].GetUInt8(); + _specialFlags = fields[17].GetUInt8(); if (_specialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT) _flags |= QUEST_FLAGS_AUTO_ACCEPT; diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index eceb5f4eeea..8bfdb44475d 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -270,6 +270,7 @@ class TC_GAME_API Quest int32 GetPrevQuestId() const { return _prevQuestId; } uint32 GetNextQuestId() const { return _nextQuestId; } int32 GetExclusiveGroup() const { return _exclusiveGroup; } + int32 GetBreadcrumbForQuestId() const { return _breadcrumbForQuestId; } uint32 GetNextQuestInChain() const { return _rewardNextQuest; } uint32 GetCharTitleId() const { return _rewardTitleId; } uint32 GetPlayersSlain() const { return _requiredPlayerKills; } @@ -370,6 +371,7 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const; std::vector DependentPreviousQuests; + std::vector DependentBreadcrumbQuests; // cached data private: @@ -447,6 +449,7 @@ class TC_GAME_API Quest int32 _prevQuestId = 0; uint32 _nextQuestId = 0; int32 _exclusiveGroup = 0; + int32 _breadcrumbForQuestId = 0; uint32 _rewardMailTemplateId = 0; uint32 _rewardMailDelay = 0; uint32 _requiredSkillId = 0; diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 72dba94077a..b545bf0af69 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -585,20 +585,18 @@ public: uint32 count = 0; uint32 maxResults = sWorld->getIntConfig(CONFIG_MAX_RESULTS_LOOKUP_COMMANDS); - ObjectMgr::QuestMap const& qTemplates = sObjectMgr->GetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) + ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates(); + for (auto const& questTemplatePair : questTemplates) { - Quest* qInfo = iter->second; - - int localeIndex = handler->GetSessionDbLocaleIndex(); + uint8 localeIndex = handler->GetSessionDbLocaleIndex(); if (localeIndex >= 0) { uint8 ulocaleIndex = uint8(localeIndex); - if (QuestLocale const* questLocale = sObjectMgr->GetQuestLocale(qInfo->GetQuestId())) + if (QuestLocale const* questLocale = sObjectMgr->GetQuestLocale(questTemplatePair.first)) { if (questLocale->Title.size() > ulocaleIndex && !questLocale->Title[ulocaleIndex].empty()) { - std::string title = questLocale->Title[ulocaleIndex]; + std::string const& title = questLocale->Title[ulocaleIndex]; if (Utf8FitTo(title, wNamePart)) { @@ -612,9 +610,7 @@ public: if (target) { - QuestStatus status = target->GetQuestStatus(qInfo->GetQuestId()); - - switch (status) + switch (target->GetQuestStatus(questTemplatePair.first)) { case QUEST_STATUS_COMPLETE: statusStr = handler->GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); @@ -631,9 +627,9 @@ public: } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, qInfo->GetQuestId(), qInfo->GetQuestId(), qInfo->GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); else - handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, qInfo->GetQuestId(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); if (!found) found = true; @@ -644,7 +640,7 @@ public: } } - std::string title = qInfo->GetTitle(); + std::string const& title = questTemplatePair.second.GetTitle(); if (title.empty()) continue; @@ -660,9 +656,7 @@ public: if (target) { - QuestStatus status = target->GetQuestStatus(qInfo->GetQuestId()); - - switch (status) + switch (target->GetQuestStatus(questTemplatePair.first)) { case QUEST_STATUS_COMPLETE: statusStr = handler->GetTrinityString(LANG_COMMAND_QUEST_COMPLETE); @@ -679,9 +673,9 @@ public: } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, qInfo->GetQuestId(), qInfo->GetQuestId(), qInfo->GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); else - handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, qInfo->GetQuestId(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); if (!found) found = true;