diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index 47e58cf8..9d753fea 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -12684,6 +12684,7 @@ void Player::RewardQuest(Quest const* pQuest, uint32 reward, Object* questGiver, { itr->second->ApplyOrRemoveSpellIfCan(this, zone, area, false); } } +// TODO be more specific at callers about quest fail reason. Also, quest "fails" when either picking up or giving out is unsuccessful. void Player::FailQuest(uint32 questId) { if (Quest const* pQuest = sObjectMgr.GetQuestTemplate(questId)) @@ -13702,12 +13703,16 @@ void Player::SendQuestReward(Quest const* pQuest, uint32 XP) GetSession()->SendPacket(&data); } -void Player::SendQuestFailed(uint32 quest_id) +/// Sent when a quest is failed to be given off at questtaker. Specifically handled reasons: +/// INVALIDREASON_QUEST_FAILED_INVENTORY_FULL=4 (or 50) +/// INVALIDREASON_QUEST_FAILED_DUPLICATE_ITEM=17 +void Player::SendQuestFailed(uint32 quest_id, uint32 reason) { if (quest_id) { - WorldPacket data(SMSG_QUESTGIVER_QUEST_FAILED, 4); + WorldPacket data(SMSG_QUESTGIVER_QUEST_FAILED, 8); data << uint32(quest_id); + data << uint32(reason); GetSession()->SendPacket(&data); DEBUG_LOG("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); } diff --git a/src/game/Object/Player.h b/src/game/Object/Player.h index 90cf016d..51c5fe12 100644 --- a/src/game/Object/Player.h +++ b/src/game/Object/Player.h @@ -1410,7 +1410,7 @@ class Player : public Unit void SendQuestCompleteEvent(uint32 quest_id); void SendQuestReward(Quest const* pQuest, uint32 XP); - void SendQuestFailed(uint32 quest_id); + void SendQuestFailed(uint32 quest_id, uint32 reason = INVALIDREASON_DONT_HAVE_REQ); void SendQuestTimerFailed(uint32 quest_id); void SendCanTakeQuestResponse(uint32 msg) const; void SendQuestConfirmAccept(Quest const* pQuest, Player* pReceiver); diff --git a/src/game/Server/Opcodes.cpp b/src/game/Server/Opcodes.cpp index 76271184..ccb16bc5 100644 --- a/src/game/Server/Opcodes.cpp +++ b/src/game/Server/Opcodes.cpp @@ -455,14 +455,14 @@ void Opcodes::BuildOpcodeList() /*0x188*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_DETAILS, "SMSG_QUESTGIVER_QUEST_DETAILS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); /*[-ZERO] Need check */ /*0x189*/ StoreOpcode(CMSG_QUESTGIVER_ACCEPT_QUEST, "CMSG_QUESTGIVER_ACCEPT_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverAcceptQuestOpcode); /*[-ZERO] Need check */ /*0x18A*/ StoreOpcode(CMSG_QUESTGIVER_COMPLETE_QUEST, "CMSG_QUESTGIVER_COMPLETE_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCompleteQuest); - /*[-ZERO] Need check */ /*0x18B*/ StoreOpcode(SMSG_QUESTGIVER_REQUEST_ITEMS, "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); + /*0x18B*/ StoreOpcode(SMSG_QUESTGIVER_REQUEST_ITEMS, "SMSG_QUESTGIVER_REQUEST_ITEMS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); /*[-ZERO] Need check */ /*0x18C*/ StoreOpcode(CMSG_QUESTGIVER_REQUEST_REWARD, "CMSG_QUESTGIVER_REQUEST_REWARD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverRequestRewardOpcode); - /*[-ZERO] Need check */ /*0x18D*/ StoreOpcode(SMSG_QUESTGIVER_OFFER_REWARD, "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); + /*0x18D*/ StoreOpcode(SMSG_QUESTGIVER_OFFER_REWARD, "SMSG_QUESTGIVER_OFFER_REWARD", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); /*[-ZERO] Need check */ /*0x18E*/ StoreOpcode(CMSG_QUESTGIVER_CHOOSE_REWARD, "CMSG_QUESTGIVER_CHOOSE_REWARD", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverChooseRewardOpcode); - /*[-ZERO] Need check */ /*0x18F*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_INVALID, "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); + /*0x18F*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_INVALID, "SMSG_QUESTGIVER_QUEST_INVALID", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); /*[-ZERO] Need check */ /*0x190*/ StoreOpcode(CMSG_QUESTGIVER_CANCEL, "CMSG_QUESTGIVER_CANCEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCancel); - /*[-ZERO] Need check */ /*0x191*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_COMPLETE, "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); - /*[-ZERO] Need check */ /*0x192*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_FAILED, "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); + /*0x191*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_COMPLETE, "SMSG_QUESTGIVER_QUEST_COMPLETE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); + /*0x192*/ StoreOpcode(SMSG_QUESTGIVER_QUEST_FAILED, "SMSG_QUESTGIVER_QUEST_FAILED", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); /*[-ZERO] Need check */ /*0x193*/ StoreOpcode(CMSG_QUESTLOG_SWAP_QUEST, "CMSG_QUESTLOG_SWAP_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogSwapQuest); /*[-ZERO] Need check */ /*0x194*/ StoreOpcode(CMSG_QUESTLOG_REMOVE_QUEST, "CMSG_QUESTLOG_REMOVE_QUEST", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestLogRemoveQuest); /*[-ZERO] Need check */ /*0x195*/ StoreOpcode(SMSG_QUESTLOG_FULL, "SMSG_QUESTLOG_FULL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide); diff --git a/src/game/WorldHandlers/GossipDef.cpp b/src/game/WorldHandlers/GossipDef.cpp index 0c868bfe..926d60dd 100644 --- a/src/game/WorldHandlers/GossipDef.cpp +++ b/src/game/WorldHandlers/GossipDef.cpp @@ -662,6 +662,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* pQuest, ObjectGuid npcGU } data << EmoteCount; // Emote Count + // TODO unify cycle constructions: the previous one allows non-sequential data placing, while the next one does not for (uint32 i = 0; i < EmoteCount; ++i) { data << uint32(pQuest->OfferRewardEmoteDelay[i]); // Delay Emote diff --git a/src/game/WorldHandlers/QuestDef.h b/src/game/WorldHandlers/QuestDef.h index 65734e9c..b39cc8e9 100644 --- a/src/game/WorldHandlers/QuestDef.h +++ b/src/game/WorldHandlers/QuestDef.h @@ -45,18 +45,19 @@ class ObjectMgr; #define QUEST_REPUTATIONS_COUNT 5 #define QUEST_EMOTE_COUNT 4 -// [-ZERO] need update enum QuestFailedReasons { INVALIDREASON_DONT_HAVE_REQ = 0, // this is default case INVALIDREASON_QUEST_FAILED_LOW_LEVEL = 1, // You are not high enough level for that quest. + INVALIDREASON_QUEST_FAILED_REQS = 2, // You don't meet the requirements for that quest. + INVALIDREASON_QUEST_FAILED_INVENTORY_FULL = 4, // Inventory is full. (Also 50. From SMSG_QUESTGIVER_QUEST_FAILED) INVALIDREASON_QUEST_FAILED_WRONG_RACE = 6, // That quest is not available to your race. - INVALIDREASON_QUEST_ALREADY_DONE = 7, // You have completed that quest. INVALIDREASON_QUEST_ONLY_ONE_TIMED = 12, // You can only be on one timed quest at a time. INVALIDREASON_QUEST_ALREADY_ON = 13, // You are already on that quest. - INVALIDREASON_QUEST_ALREADY_ON2 = 18, // You are already on that quest. - INVALIDREASON_QUEST_FAILED_MISSING_ITEMS = 21, // You don't have the required items with you. Check storage. - INVALIDREASON_QUEST_FAILED_NOT_ENOUGH_MONEY = 23 // You don't have enough money for that quest. + INVALIDREASON_QUEST_FAILED_DUPLICATE_ITEM = 17, // Duplicate item found. (From SMSG_QUESTGIVER_QUEST_FAILED) + INVALIDREASON_QUEST_FAILED_MISSING_ITEMS = 20, // You don't have the required items with you. Check storage. + INVALIDREASON_QUEST_FAILED_NOT_ENOUGH_MONEY = 22 // You don't have enough money for that quest. + // INVALIDREASON_QUEST_FAILED_REQS = 3,4,5,7-11,14-19,21 }; enum QuestShareMessages