From d213a4ef93c4843d8de881b2c304301eb0f626e8 Mon Sep 17 00:00:00 2001 From: poszer Date: Mon, 7 Jan 2019 18:13:47 +0100 Subject: [PATCH] Core/Quests: Abandon&Finish quest items Destroy quest items on quest failure/abandon. Failing/abandoning a quest should not unconditionally remove required items, non-quest specific items such as crafting reagents should remain in inventory. Delete all quest bound items on quest reward, failure or abandoning. Only delete all quest bound items from inventory on turn in if the quest is not repeatable --- src/server/game/Entities/Player/Player.cpp | 69 +++++++++++++++------- src/server/game/Entities/Player/Player.h | 3 +- src/server/game/Handlers/QuestHandler.cpp | 1 + 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ea18fe43e..1c468edf5 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15746,15 +15746,23 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, uint32 quest_id = quest->GetQuestId(); for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - if (quest->RequiredItemId[i]) - DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true); - + { + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) + { + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->RequiredItemId[i], quest_id, true)) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); + else + DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true); + } + } for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { - if (quest->ItemDrop[i]) + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) { - uint32 count = quest->ItemDropQuantity[i]; - DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true); + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM && !quest->IsRepeatable() && !HasQuestForItem(quest->ItemDrop[i], quest_id)) + DestroyItemCount(quest->ItemDrop[i], 9999, true); + else + DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true); } } @@ -15985,14 +15993,32 @@ void Player::FailQuest(uint32 questId) SendQuestFailed(questId); // Destroy quest items on quest failure. - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - if (quest->RequiredItemId[i] > 0 && quest->RequiredItemCount[i] > 0) - // Destroy items received on starting the quest. - DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true); + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); + for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - if (quest->ItemDrop[i] > 0 && quest->ItemDropQuantity[i] > 0) - // Destroy items received during the quest. - DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true); + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->ItemDrop[i], 9999, true); + } +} + +void Player::AbandonQuest(uint32 questId) +{ + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) + { + // It will Destroy quest items on quests abandons. + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i])) + if (quest->RequiredItemCount[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->RequiredItemId[i], 9999, true); + + for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) + if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) + if (quest->ItemDropQuantity[i] > 0 && itemTemplate->Bonding == BIND_QUEST_ITEM) + DestroyItemCount(quest->ItemDrop[i], 9999, true); } } @@ -17220,12 +17246,12 @@ void Player::ReputationChanged2(FactionEntry const* factionEntry) } } -bool Player::HasQuestForItem(uint32 itemid) const +bool Player::HasQuestForItem(uint32 itemid, uint32 excludeQuestId /* 0 */, bool turnIn /* false */) const { for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) { uint32 questid = GetQuestSlotQuestId(i); - if (questid == 0) + if (questid == 0 || questid == excludeQuestId) continue; QuestStatusMap::const_iterator qs_itr = m_QuestStatus.find(questid); @@ -17234,7 +17260,7 @@ bool Player::HasQuestForItem(uint32 itemid) const QuestStatusData const& q_status = qs_itr->second; - if (q_status.Status == QUEST_STATUS_INCOMPLETE) + if ((q_status.Status == QUEST_STATUS_INCOMPLETE) || (turnIn && q_status.Status == QUEST_STATUS_COMPLETE)) { Quest const* qinfo = sObjectMgr->GetQuestTemplate(questid); if (!qinfo) @@ -17249,7 +17275,7 @@ bool Player::HasQuestForItem(uint32 itemid) const // This part for ReqItem drop for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { - if (itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j]) + if ((itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j]) || (turnIn && q_status.ItemCount[j] >= qinfo->RequiredItemCount[j])) return true; } // This part - for ReqSource @@ -17259,17 +17285,18 @@ bool Player::HasQuestForItem(uint32 itemid) const if (qinfo->ItemDrop[j] == itemid) { ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid); - + uint32 ownedCount = GetItemCount(itemid, true); // 'unique' item - if (pProto->MaxCount && int32(GetItemCount(itemid, true)) < pProto->MaxCount) + if ((pProto->MaxCount && int32(ownedCount) < pProto->MaxCount) || (turnIn && int32(ownedCount) >= pProto->MaxCount)) return true; // allows custom amount drop when not 0 if (qinfo->ItemDropQuantity[j]) { - if (GetItemCount(itemid, true) < qinfo->ItemDropQuantity[j]) + if ((ownedCount < qinfo->ItemDropQuantity[j]) || (turnIn && ownedCount >= qinfo->ItemDropQuantity[j])) return true; - } else if (GetItemCount(itemid, true) < pProto->GetMaxStackSize()) + } + else if (ownedCount < pProto->GetMaxStackSize()) return true; } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 73a57b509..3cc02b1f5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1399,6 +1399,7 @@ class Player : public Unit, public GridObject bool CanRewardQuest(Quest const* quest, uint32 reward, bool msg); void AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver); void AddQuest(Quest const* quest, Object* questGiver); + void AbandonQuest(uint32 quest_id); void CompleteQuest(uint32 quest_id); void IncompleteQuest(uint32 quest_id); void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true); @@ -1486,7 +1487,7 @@ class Player : public Unit, public GridObject void MoneyChanged(uint32 value); void ReputationChanged(FactionEntry const* factionEntry); void ReputationChanged2(FactionEntry const* factionEntry); - bool HasQuestForItem(uint32 itemid) const; + bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false) const; bool HasQuestForGO(int32 GOId) const; void UpdateForQuestWorldObjects(); bool CanShareQuest(uint32 quest_id) const; diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 1be8665ed..862b636b2 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -418,6 +418,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recvData) } _player->TakeQuestSourceItem(questId, true); // remove quest src item from player + _player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. _player->RemoveActiveQuest(questId); _player->RemoveTimedAchievement(ACHIEVEMENT_TIMED_TYPE_QUEST, questId); #ifdef ELUNA