Core/Quests: fixed exclusivegroup interaction with prevquestId and nextQuestId.

- They should work as documented by wiki now.
- Add some consts to Player methods
- Fixed negative PrevQuestID to mean only active quest (ie not rewarded/complete, as those quests are required to complete another)

Closes #19300
This commit is contained in:
ariel- authored and Ovahlord committed 2020-02-20 01:39:08 +01:00
1 parent d78ad034d0
commit a7484837a8
4 files changed
+93 -97

No files matched your search

+83 -87
View File
@@ -14666,7 +14666,7 @@ bool Player::CanSeeStartQuest(Quest const* quest)
{
if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) &&
SatisfyQuestDependentQuests(quest, false) && SatisfyQuestNextChain(quest, false) &&
SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false))
{
@@ -14682,7 +14682,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg)
&& SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg)
&& SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg)
&& SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg)
&& SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg)
&& SatisfyQuestDependentQuests(quest, msg) && SatisfyQuestTimed(quest, msg)
&& SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg)
&& SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
&& SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg)
@@ -15436,95 +15436,91 @@ bool Player::SatisfyQuestLog(bool msg) const
return false;
}
bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg)
bool Player::SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const
{
return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg);
}
bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
{
// No previous quest (might be first quest in a series)
if (qInfo->PrevQuests.empty())
if (!qInfo->GetPrevQuestId())
return true;
for (auto iter = qInfo->PrevQuests.begin(); iter != qInfo->PrevQuests.end(); ++iter)
{
uint32 prevId = abs(*iter);
uint32 prevId = std::abs(qInfo->GetPrevQuestId());
// If positive previous quest rewarded, return true
if (qInfo->GetPrevQuestId() > 0 && m_RewardedQuests.count(prevId) > 0)
return true;
Quest const* qPrevInfo = sObjectMgr->GetQuestTemplate(prevId);
// If negative previous quest active, return true
if (qInfo->GetPrevQuestId() < 0 && GetQuestStatus(prevId) == QUEST_STATUS_INCOMPLETE)
return true;
if (qPrevInfo)
{
// If any of the positive previous quests completed, return true
if (*iter > 0 && m_RewardedQuests.find(prevId) != m_RewardedQuests.end())
{
// skip one-from-all exclusive group
if (qPrevInfo->GetExclusiveGroup() >= 0)
return true;
// each-from-all exclusive group (< 0)
// can be start if only all quests in prev quest exclusive group completed and rewarded
auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(qPrevInfo->GetExclusiveGroup());
for (auto itr = bounds.first; itr != bounds.second; ++itr)
{
uint32 exclude_Id = itr->second;
// skip checked quest id, only state of other quests in group is interesting
if (exclude_Id == prevId)
continue;
// alternative quest from group also must be completed and rewarded (reported)
if (m_RewardedQuests.find(exclude_Id) == m_RewardedQuests.end())
{
if (msg)
{
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required quest (1).",
qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
}
return false;
}
}
return true;
}
// If any of the negative previous quests active, return true
if (*iter < 0 && GetQuestStatus(prevId) != QUEST_STATUS_NONE)
{
// skip one-from-all exclusive group
if (qPrevInfo->GetExclusiveGroup() >= 0)
return true;
// each-from-all exclusive group (< 0)
// can be start if only all quests in prev quest exclusive group active
auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(qPrevInfo->GetExclusiveGroup());
for (auto itr = bounds.first; itr != bounds.second; ++itr)
{
uint32 exclude_Id = itr->second;
// skip checked quest id, only state of other quests in group is interesting
if (exclude_Id == prevId)
continue;
// alternative quest from group also must be active
if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE)
{
if (msg)
{
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required quest (2).",
qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
}
return false;
}
}
return true;
}
}
}
// Has only positive prev. quests in non-rewarded state
// and negative prev. quests in non-active state
// Has positive prev. quest in non-rewarded state
// and negative prev. quest in non-active state
if (msg)
{
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have required quest (3).",
TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have required quest %u.",
qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str(), prevId);
}
return false;
}
bool Player::SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const
{
// No previous quest (might be first quest in a series)
if (qInfo->DependentPreviousQuests.empty())
return true;
for (uint32 prevId : qInfo->DependentPreviousQuests)
{
// checked in startup
Quest const* questInfo = sObjectMgr->GetQuestTemplate(prevId);
ASSERT(questInfo);
// If any of the previous quests completed, return true
if (IsQuestRewarded(prevId))
{
// skip one-from-all exclusive group
if (questInfo->GetExclusiveGroup() >= 0)
return true;
// each-from-all exclusive group (< 0)
// can be start if only all quests in prev quest exclusive group completed and rewarded
auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(questInfo->GetExclusiveGroup());
for (auto itr = bounds.first; itr != bounds.second; ++itr)
{
// skip checked quest id, only state of other quests in group is interesting
uint32 exclusiveQuestId = itr->second;
if (exclusiveQuestId == prevId)
continue;
// alternative quest from group also must be completed and rewarded (reported)
if (!IsQuestRewarded(exclusiveQuestId))
{
if (msg)
{
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have the required quest (1).",
qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
}
return false;
}
}
return true;
}
}
// Has only prev. quests in non-rewarded state
if (msg)
{
SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: %u) because player '%s' (%s) doesn't have required quest (2).",
qInfo->GetQuestId(), GetName().c_str(), GetGUID().ToString().c_str());
}
@@ -15671,7 +15667,7 @@ bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg) const
return true;
}
bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg)
bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const
{
// non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed
if (qInfo->GetExclusiveGroup() <= 0)
@@ -15746,9 +15742,9 @@ bool Player::SatisfyQuestPrevChain(Quest const* qInfo, bool msg)
if (qInfo->PrevChainQuests.empty())
return true;
for (auto iter = qInfo->PrevChainQuests.begin(); iter != qInfo->PrevChainQuests.end(); ++iter)
for (uint32 prevQuestId : qInfo->PrevChainQuests)
{
QuestStatusMap::const_iterator itr = m_QuestStatus.find(*iter);
auto itr = m_QuestStatus.find(prevQuestId);
// If any of the previous quests in chain active, return false
if (itr != m_QuestStatus.end() && itr->second.Status != QUEST_STATUS_NONE)
@@ -15801,7 +15797,7 @@ bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) const
return true;
}
bool Player::SatisfyQuestWeek(Quest const* qInfo, bool /*msg*/)
bool Player::SatisfyQuestWeek(Quest const* qInfo, bool /*msg*/) const
{
if (!qInfo->IsWeekly() || m_weeklyquests.empty())
return true;
@@ -15823,7 +15819,7 @@ bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/) const
return itr->second.find(qInfo->GetQuestId()) == itr->second.end();
}
bool Player::SatisfyQuestMonth(Quest const* qInfo, bool /*msg*/)
bool Player::SatisfyQuestMonth(Quest const* qInfo, bool /*msg*/) const
{
if (!qInfo->IsMonthly() || m_monthlyquests.empty())
return true;
+6 -4
View File
@@ -1366,19 +1366,21 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
bool SatisfyQuestLevel(Quest const* qInfo, bool msg) const;
bool SatisfyQuestLog(bool msg) const;
bool SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg);
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 SatisfyQuestClass(Quest const* qInfo, bool msg) const;
bool SatisfyQuestRace(Quest const* qInfo, bool msg) const;
bool SatisfyQuestReputation(Quest const* qInfo, bool msg);
bool SatisfyQuestStatus(Quest const* qInfo, bool msg) const;
bool SatisfyQuestConditions(Quest const* qInfo, bool msg);
bool SatisfyQuestTimed(Quest const* qInfo, bool msg) const;
bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg);
bool SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const;
bool SatisfyQuestNextChain(Quest const* qInfo, bool msg) const;
bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg);
bool SatisfyQuestDay(Quest const* qInfo, bool msg) const;
bool SatisfyQuestWeek(Quest const* qInfo, bool msg);
bool SatisfyQuestMonth(Quest const* qInfo, bool msg);
bool SatisfyQuestWeek(Quest const* qInfo, bool msg) const;
bool SatisfyQuestMonth(Quest const* qInfo, bool msg) const;
bool SatisfyQuestSeasonal(Quest const* qInfo, bool msg) const;
bool GiveQuestSourceItem(Quest const* quest);
bool TakeQuestSourceItem(uint32 questId, bool msg);
+3 -5
View File
@@ -4223,7 +4223,7 @@ void ObjectMgr::LoadQuests()
uint32 oldMSTime = getMSTime();
// For reload case
for (QuestMap::const_iterator itr=_questTemplates.begin(); itr != _questTemplates.end(); ++itr)
for (auto itr = _questTemplates.begin(); itr != _questTemplates.end(); ++itr)
delete itr->second;
_questTemplates.clear();
@@ -4312,7 +4312,7 @@ void ObjectMgr::LoadQuests()
for (QuestLoaderHelper const& loader : QuestLoaderHelpers)
{
QueryResult result = WorldDatabase.Query(Trinity::StringFormat("SELECT %s FROM %s", loader.QueryFields, loader.TableName).c_str());
QueryResult result = WorldDatabase.PQuery("SELECT %s FROM %s", loader.QueryFields, loader.TableName);
if (!result)
TC_LOG_ERROR("server.loading", ">> Loaded 0 quest %s. DB table `%s` is empty.", loader.TableDesc, loader.TableName);
@@ -4976,8 +4976,6 @@ void ObjectMgr::LoadQuests()
{
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());
else
qinfo->PrevQuests.push_back(qinfo->_prevQuestId);
}
if (qinfo->_nextQuestId)
@@ -4986,7 +4984,7 @@ void ObjectMgr::LoadQuests()
if (qNextItr == _questTemplates.end())
TC_LOG_ERROR("sql.sql", "Quest %u has NextQuestId %u, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
else
qNextItr->second->PrevQuests.push_back(static_cast<int32>(qinfo->GetQuestId()));
qNextItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId());
}
if (qinfo->_exclusiveGroup)
+1 -1
View File
@@ -367,7 +367,7 @@ class TC_GAME_API Quest
void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const;
std::vector<int32> PrevQuests;
std::vector<uint32> DependentPreviousQuests;
std::vector<uint32> PrevChainQuests;
// cached data