Core/Quests: Fixed QuestScript::OnQuestStatusChange incorrectly triggering with QUEST_STATUS_INCOMPLETE when removing items from quest objectives on rewarding quest

Closes #31181
This commit is contained in:
Shauren
2025-07-30 18:35:39 +02:00
parent e203a3bad7
commit 2c9b67f00b
4 changed files with 53 additions and 75 deletions

View File

@@ -15093,6 +15093,30 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
uint32 quest_id = quest->GetQuestId();
QuestStatus oldStatus = GetQuestStatus(quest_id);
if (quest->IsDaily() || quest->IsDFQuest())
{
SetDailyQuestStatus(quest_id);
if (quest->IsDaily())
{
StartCriteria(CriteriaStartEvent::CompleteDailyQuest, 0);
UpdateCriteria(CriteriaType::CompleteDailyQuest, quest_id);
UpdateCriteria(CriteriaType::CompleteAnyDailyQuestPerDay, quest_id);
}
}
else if (quest->IsWeekly())
SetWeeklyQuestStatus(quest_id);
else if (quest->IsMonthly())
SetMonthlyQuestStatus(quest_id);
else if (quest->IsSeasonal())
SetSeasonalQuestStatus(quest_id);
RemoveTimedQuest(quest_id);
RemoveActiveQuest(quest_id, false);
if (quest->CanIncreaseRewardedQuestCounters())
SetRewardedQuest(quest_id);
SetQuestCompletedBit(quest_id, true);
for (QuestObjective const& obj : quest->GetObjectives())
{
switch (obj.Type)
@@ -15125,8 +15149,6 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
}
}
RemoveTimedQuest(quest_id);
if (quest->GetRewItemsCount() > 0)
{
for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i)
@@ -15213,10 +15235,6 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
if (uint32 skill = quest->GetRewardSkillId())
UpdateSkillPro(skill, 1000, quest->GetRewardSkillPoints());
uint16 log_slot = FindQuestSlot(quest_id);
if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot, 0);
uint32 XP = GetQuestXPReward(quest);
int32 moneyRew = 0;
@@ -15260,27 +15278,6 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
CharacterDatabase.CommitTransaction(trans);
}
if (quest->IsDaily() || quest->IsDFQuest())
{
SetDailyQuestStatus(quest_id);
if (quest->IsDaily())
{
StartCriteria(CriteriaStartEvent::CompleteDailyQuest, 0);
UpdateCriteria(CriteriaType::CompleteDailyQuest, quest_id);
UpdateCriteria(CriteriaType::CompleteAnyDailyQuestPerDay, quest_id);
}
}
else if (quest->IsWeekly())
SetWeeklyQuestStatus(quest_id);
else if (quest->IsMonthly())
SetMonthlyQuestStatus(quest_id);
else if (quest->IsSeasonal())
SetSeasonalQuestStatus(quest_id);
RemoveActiveQuest(quest_id, false);
if (quest->CanIncreaseRewardedQuestCounters())
SetRewardedQuest(quest_id);
SendQuestReward(quest, questGiver ? questGiver->ToCreature() : nullptr, XP, !announce);
RewardReputation(quest);
@@ -15320,8 +15317,6 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew
// make full db save
SaveToDB(false);
SetQuestCompletedBit(quest_id, true);
if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
{
pvpInfo.IsHostile = pvpInfo.IsInHostileArea || HasPvPForcingQuest();
@@ -16037,6 +16032,8 @@ void Player::RemoveActiveQuest(uint32 questId, bool update /*= true*/)
QuestStatusMap::iterator itr = m_QuestStatus.find(questId);
if (itr != m_QuestStatus.end())
{
SetQuestSlot(itr->second.Slot, 0);
for (auto objectiveItr = m_questObjectiveStatus.begin(); objectiveItr != m_questObjectiveStatus.end(); )
{
if (objectiveItr->second.QuestStatusItr == itr)
@@ -16295,11 +16292,13 @@ void Player::SkipQuests(std::vector<uint32> const& questIds)
if (!quest)
return;
uint16 questSlot = FindQuestSlot(questId);
QuestStatus oldStatus = GetQuestStatus(questSlot);
QuestStatus oldStatus = GetQuestStatus(questId);
if (questSlot != MAX_QUEST_LOG_SIZE)
if (oldStatus != QUEST_STATUS_NONE && oldStatus != QUEST_STATUS_REWARDED)
{
RemoveActiveQuest(questId);
TakeQuestSourceItem(questId, true); // remove quest src item from player
AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
if (quest->GetLimitTime())
RemoveTimedQuest(questId);
@@ -16308,11 +16307,6 @@ void Player::SkipQuests(std::vector<uint32> const& questIds)
pvpInfo.IsHostile = pvpInfo.IsInHostileArea || HasPvPForcingQuest();
UpdatePvPState();
}
SetQuestSlot(questSlot, 0);
TakeQuestSourceItem(questId, true); // remove quest src item from player
AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
RemoveActiveQuest(questId);
}
SetRewardedQuest(questId);
@@ -19606,10 +19600,6 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
}
while (result->NextRow());
}
// clear quest log tail
for (uint16 i = slot; i < MAX_QUEST_LOG_SIZE; ++i)
SetQuestSlot(i, 0);
}
void Player::_LoadQuestStatusObjectives(PreparedQueryResult result)
@@ -25474,9 +25464,8 @@ void Player::DailyReset()
if (!quest || !quest->IsDaily() || !quest->HasFlagEx(QUEST_FLAGS_EX_REMOVE_ON_PERIODIC_RESET))
continue;
SetQuestSlot(slot, 0);
AbandonQuest(questId);
RemoveActiveQuest(questId);
AbandonQuest(questId);
DespawnPersonalSummonsForQuest(questId);
if (quest->GetLimitTime())
@@ -25513,9 +25502,8 @@ void Player::ResetWeeklyQuestStatus()
if (!quest || !quest->IsWeekly() || !quest->HasFlagEx(QUEST_FLAGS_EX_REMOVE_ON_PERIODIC_RESET))
continue;
SetQuestSlot(slot, 0);
AbandonQuest(questId);
RemoveActiveQuest(questId);
AbandonQuest(questId);
DespawnPersonalSummonsForQuest(questId);
if (quest->GetLimitTime())

View File

@@ -416,6 +416,8 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
QuestStatus oldStatus = _player->GetQuestStatus(questId);
_player->RemoveActiveQuest(questId);
if (quest)
{
if (quest->HasFlagEx(QUEST_FLAGS_EX_NO_ABANDON_ONCE_BEGUN))
@@ -434,10 +436,8 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove
}
_player->SendForceSpawnTrackingUpdate(questId);
_player->SetQuestSlot(packet.Entry, 0);
_player->TakeQuestSourceItem(questId, true); // remove quest src item from player
_player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
_player->RemoveActiveQuest(questId);
_player->DespawnPersonalSummonsForQuest(questId);
TC_LOG_INFO("network", "Player {} abandoned quest {}", _player->GetGUID().ToString(), questId);

View File

@@ -4068,26 +4068,21 @@ void Spell::EffectQuestClear()
if (oldStatus == QUEST_STATUS_NONE)
return;
player->RemoveActiveQuest(quest_id, false);
// remove all quest entries for 'entry' from quest log
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
if (oldStatus != QUEST_STATUS_REWARDED)
{
uint32 logQuest = player->GetQuestSlotQuestId(slot);
if (logQuest == quest_id)
// we ignore unequippable quest items in this case, it's still be equipped
player->TakeQuestSourceItem(quest_id, false);
if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
{
player->SetQuestSlot(slot, 0);
// we ignore unequippable quest items in this case, it's still be equipped
player->TakeQuestSourceItem(logQuest, false);
if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
{
player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
player->UpdatePvPState();
}
player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
player->UpdatePvPState();
}
}
player->RemoveActiveQuest(quest_id, false);
player->RemoveRewardedQuest(quest_id);
player->DespawnPersonalSummonsForQuest(quest_id);

View File

@@ -117,25 +117,20 @@ public:
if (oldStatus != QUEST_STATUS_NONE)
{
player->RemoveActiveQuest(quest->GetQuestId(), false);
// remove all quest entries for 'entry' from quest log
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
if (oldStatus != QUEST_STATUS_REWARDED)
{
uint32 logQuest = player->GetQuestSlotQuestId(slot);
if (logQuest == quest->GetQuestId())
// we ignore unequippable quest items in this case, its' still be equipped
player->TakeQuestSourceItem(quest->GetQuestId(), false);
if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
{
player->SetQuestSlot(slot, 0);
// we ignore unequippable quest items in this case, its' still be equipped
player->TakeQuestSourceItem(logQuest, false);
if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
{
player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
player->UpdatePvPState();
}
player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
player->UpdatePvPState();
}
}
player->RemoveActiveQuest(quest->GetQuestId(), false);
player->RemoveRewardedQuest(quest->GetQuestId());
player->DespawnPersonalSummonsForQuest(quest->GetQuestId());