From 0c414a05be8f5fc1ea556fd246150f8688e00bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB?= Date: Wed, 15 Mar 2017 22:58:23 +0300 Subject: [PATCH] Core/Quest: Fixed display of quests. Closes https://github.com/azerothcore/azerothcore-wotlk/issues/420 --- src/game/Entities/Creature/GossipDef.cpp | 201 ++++++++++++++--------- src/game/Entities/Creature/GossipDef.h | 6 +- src/game/Globals/ObjectMgr.h | 6 + 3 files changed, 134 insertions(+), 79 deletions(-) diff --git a/src/game/Entities/Creature/GossipDef.cpp b/src/game/Entities/Creature/GossipDef.cpp index 6f249cfb3..93d295c21 100644 --- a/src/game/Entities/Creature/GossipDef.cpp +++ b/src/game/Entities/Creature/GossipDef.cpp @@ -15,6 +15,7 @@ GossipMenu::GossipMenu() { _menuId = 0; + _locale = DEFAULT_LOCALE; } GossipMenu::~GossipMenu() @@ -54,6 +55,48 @@ void GossipMenu::AddMenuItem(int32 menuItemId, uint8 icon, std::string const& me menuItem.BoxMoney = boxMoney; } +/** + * @name AddMenuItem + * @brief Adds a localized gossip menu item from db by menu id and menu item id. + * @param menuId Gossip menu id. + * @param menuItemId Gossip menu item id. + * @param sender Identifier of the current menu. + * @param action Custom action given to OnGossipHello. + */ +void GossipMenu::AddMenuItem(uint32 menuId, uint32 menuItemId, uint32 sender, uint32 action) +{ + /// Find items for given menu id. + GossipMenuItemsMapBounds bounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId); + /// Return if there are none. + if (bounds.first == bounds.second) + return; + + /// Iterate over each of them. + for (GossipMenuItemsContainer::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + /// Find the one with the given menu item id. + if (itr->second.OptionIndex != menuItemId) + continue; + + /// Store texts for localization. + std::string strOptionText = itr->second.OptionText; + std::string strBoxText = itr->second.BoxText; + + /// Check need of localization. + if (GetLocale() != DEFAULT_LOCALE) + /// Find localizations from database. + if (GossipMenuItemsLocale const* no = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuItemId))) + { + /// Translate texts if there are any. + ObjectMgr::GetLocaleString(no->OptionText, GetLocale(), strOptionText); + ObjectMgr::GetLocaleString(no->BoxText, GetLocale(), strBoxText); + } + + /// Add menu item with existing method. Menu item id -1 is also used in ADD_GOSSIP_ITEM macro. + AddMenuItem(-1, itr->second.OptionIcon, strOptionText, sender, action, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded); + } +} + void GossipMenu::AddGossipMenuItemData(uint32 menuItemId, uint32 gossipActionMenuId, uint32 gossipActionPoi) { //TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, GetLock()); @@ -137,27 +180,30 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const data << item.BoxMessage; // accept text (related to money) pop up box, 2.0.3 } + size_t count_pos = data.wpos(); data << uint32(_questMenu.GetMenuItemCount()); // max count 0x20 - + uint32 count = 0; + for (uint32 iI = 0; iI < _questMenu.GetMenuItemCount(); ++iI) { + ++count; QuestMenuItem const& item = _questMenu.GetItem(iI); uint32 questID = item.QuestId; - Quest const* quest = sObjectMgr->GetQuestTemplate(questID); + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID)) + { + data << uint32(questID); + data << uint32(item.QuestIcon); + data << int32(quest->GetQuestLevel()); + data << uint32(quest->GetFlags()); // 3.3.3 quest flags + data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation + std::string title = quest->GetTitle(); - data << uint32(questID); - data << uint32(item.QuestIcon); - data << int32(quest->GetQuestLevel()); - data << uint32(quest->GetFlags()); // 3.3.3 quest flags - data << uint8(0); // 3.3.3 changes icon: blue question or yellow exclamation - std::string title = quest->GetTitle(); //we need to load it from db - - int32 locale = _session->GetSessionDbLocaleIndex(); - if (locale >= 0) - if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) - ObjectMgr::GetLocaleString(localeData->Title, locale, title); - - data << title; + int32 locale = _session->GetSessionDbLocaleIndex(); + if (locale >= 0) + if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) + ObjectMgr::GetLocaleString(localeData->Title, locale, title); + data << title; + } } _session->SendPacket(&data); @@ -253,21 +299,22 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string size_t count_pos = data.wpos(); data << uint8 (_questMenu.GetMenuItemCount()); uint32 count = 0; - for (; count < _questMenu.GetMenuItemCount(); ++count) + for (uint32 iI = 0; iI < _questMenu.GetMenuItemCount(); ++iI) { - QuestMenuItem const& qmi = _questMenu.GetItem(count); + QuestMenuItem const& qmi = _questMenu.GetItem(iI); uint32 questID = qmi.QuestId; if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID)) { - //load locales from db ++count; std::string title = quest->GetTitle(); + int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) ObjectMgr::GetLocaleString(localeData->Title, locale, title); + data << uint32(questID); data << uint32(qmi.QuestIcon); data << int32(quest->GetQuestLevel()); @@ -294,7 +341,6 @@ void PlayerMenu::SendQuestGiverStatus(uint8 questStatus, uint64 npcGUID) const void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, bool activateAccept) const { - //db load again std::string questTitle = quest->GetTitle(); std::string questDetails = quest->GetDetails(); std::string questObjectives = quest->GetObjectives(); @@ -303,15 +349,15 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) { - if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) - { - ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); - ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails); - ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); - ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); - } + if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) + { + ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); + ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails); + ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives); + ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText); + } } - + WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 500); // guess size data << uint64(npcGUID); data << uint64(_session->GetPlayer()->GetDivider()); @@ -426,44 +472,45 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const } } - WorldPacket data(SMSG_QUEST_QUERY_RESPONSE, 100); + WorldPacket data(SMSG_QUEST_QUERY_RESPONSE, 100); // guess size - data << uint32(quest->GetQuestId()); - data << uint32(quest->GetQuestMethod()); - data << uint32(quest->GetQuestLevel()); - data << uint32(quest->GetMinLevel()); - data << uint32(quest->GetZoneOrSort()); + data << uint32(quest->GetQuestId()); // quest id + data << uint32(quest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details) + data << uint32(quest->GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client) + data << uint32(quest->GetMinLevel()); // min level + data << uint32(quest->GetZoneOrSort()); // zone or sort to display in quest log - data << uint32(quest->GetType()); - data << uint32(quest->GetSuggestedPlayers()); + data << uint32(quest->GetType()); // quest type + data << uint32(quest->GetSuggestedPlayers()); // suggested players count - data << uint32(quest->GetRepObjectiveFaction()); - data << uint32(quest->GetRepObjectiveValue()); + data << uint32(quest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective + data << uint32(quest->GetRepObjectiveValue()); // shown in quest log as part of quest objective - data << uint32(quest->GetRepObjectiveFaction2()); - data << uint32(quest->GetRepObjectiveValue2()); + data << uint32(quest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPPOSITE faction + data << uint32(quest->GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction - data << uint32(quest->GetNextQuestInChain()); - data << uint32(quest->GetXPId()); + data << uint32(quest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0 + data << uint32(quest->GetXPId()); // used for calculating rewarded experience if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) - data << uint32(0); + data << uint32(0); // Hide money rewarded else - data << uint32(quest->GetRewOrReqMoney()); + data << uint32(quest->GetRewOrReqMoney()); // reward money (below max lvl) - data << uint32(quest->GetRewMoneyMaxLevel()); - data << uint32(quest->GetRewSpell()); - data << int32(quest->GetRewSpellCast()); + data << uint32(quest->GetRewMoneyMaxLevel()); // used in XP calculation at client + data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0) + data << int32(quest->GetRewSpellCast()); // cast spell + // rewarded honor points data << uint32(quest->GetRewHonorAddition()); data << float(quest->GetRewHonorMultiplier()); - data << uint32(quest->GetSrcItemId()); - data << uint32(quest->GetFlags() & 0xFFFF); - data << uint32(quest->GetCharTitleId()); - data << uint32(quest->GetPlayersSlain()); - data << uint32(quest->GetBonusTalents()); - data << uint32(quest->GetRewArenaPoints()); - data << uint32(0); + data << uint32(quest->GetSrcItemId()); // source item id + data << uint32(quest->GetFlags() & 0xFFFF); // quest flags + data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) + data << uint32(quest->GetPlayersSlain()); // players slain + data << uint32(quest->GetBonusTalents()); // bonus talents + data << uint32(quest->GetRewArenaPoints()); // bonus arena points + data << uint32(0); // review rep show mask if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) { @@ -486,13 +533,13 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const } } - for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids data << uint32(quest->RewardFactionId[i]); - for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc? data << int32(quest->RewardFactionValueId[i]); - for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) + for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0) data << int32(quest->RewardFactionValueIdOverride[i]); data << uint32(quest->GetPointMapId()); @@ -504,25 +551,25 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << questObjectives; data << questDetails; data << questEndText; - data << questCompletedText; + data << questCompletedText; // display in quest objectives window once all objectives are completed for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) { if (quest->RequiredNpcOrGo[i] < 0) - data << uint32((quest->RequiredNpcOrGo[i] * (-1)) | 0x80000000); + data << uint32((quest->RequiredNpcOrGo[i] * (-1)) | 0x80000000); // client expects gameobject template id in form (id|0x80000000) else data << uint32(quest->RequiredNpcOrGo[i]); data << uint32(quest->RequiredNpcOrGoCount[i]); data << uint32(quest->RequiredSourceItemId[i]); - data << uint32(0); + data << uint32(0); // req source count? } - for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) - { - data << uint32(quest->RequiredItemId[i]); - data << uint32(quest->RequiredItemCount[i]); - } + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + { + data << uint32(quest->RequiredItemId[i]); + data << uint32(quest->RequiredItemCount[i]); + } for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) data << questObjectiveText[i]; @@ -533,20 +580,19 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const { - //load from db why sunwell remove it ?? std::string questTitle = quest->GetTitle(); std::string questOfferRewardText = quest->GetOfferRewardText(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) { - if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) - { - ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); - ObjectMgr::GetLocaleString(localeData->OfferRewardText, locale, questOfferRewardText); - } + if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) + { + ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); + ObjectMgr::GetLocaleString(localeData->OfferRewardText, locale, questOfferRewardText); + } } - + WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 400); // guess size data << uint64(npcGUID); data << uint32(quest->GetQuestId()); @@ -627,19 +673,18 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, { // We can always call to RequestItems, but this packet only goes out if there are actually // items. Otherwise, we'll skip straight to the OfferReward - - //again db load + std::string questTitle = quest->GetTitle(); std::string requestItemsText = quest->GetRequestItemsText(); int32 locale = _session->GetSessionDbLocaleIndex(); if (locale >= 0) { - if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) - { - ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); - ObjectMgr::GetLocaleString(localeData->RequestItemsText, locale, requestItemsText); - } + if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId())) + { + ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle); + ObjectMgr::GetLocaleString(localeData->RequestItemsText, locale, requestItemsText); + } } if (!quest->GetReqItemsCount() && canComplete) diff --git a/src/game/Entities/Creature/GossipDef.h b/src/game/Entities/Creature/GossipDef.h index eb6e8f318..683f6388e 100644 --- a/src/game/Entities/Creature/GossipDef.h +++ b/src/game/Entities/Creature/GossipDef.h @@ -151,9 +151,12 @@ class GossipMenu ~GossipMenu(); void AddMenuItem(int32 menuItemId, uint8 icon, std::string const& message, uint32 sender, uint32 action, std::string const& boxMessage, uint32 boxMoney, bool coded = false); - + void AddMenuItem(uint32 menuId, uint32 menuItemId, uint32 sender, uint32 action); + void SetMenuId(uint32 menu_id) { _menuId = menu_id; } uint32 GetMenuId() const { return _menuId; } + void SetLocale(LocaleConstant locale) { _locale = locale; } + LocaleConstant GetLocale() const { return _locale; } void AddGossipMenuItemData(uint32 menuItemId, uint32 gossipActionMenuId, uint32 gossipActionPoi); @@ -207,6 +210,7 @@ class GossipMenu GossipMenuItemContainer _menuItems; GossipMenuItemDataContainer _menuItemData; uint32 _menuId; + LocaleConstant _locale; }; class QuestMenu diff --git a/src/game/Globals/ObjectMgr.h b/src/game/Globals/ObjectMgr.h index 2b787bfb6..06689df0e 100644 --- a/src/game/Globals/ObjectMgr.h +++ b/src/game/Globals/ObjectMgr.h @@ -1158,6 +1158,12 @@ class ObjectMgr if (itr == _questLocaleStore.end()) return NULL; return &itr->second; } + GossipMenuItemsLocale const* GetGossipMenuItemsLocale(uint32 entry) const + { + GossipMenuItemsLocaleContainer::const_iterator itr = _gossipMenuItemsLocaleStore.find(entry); + if (itr == _gossipMenuItemsLocaleStore.end()) return NULL; + return &itr->second; + } PointOfInterestLocale const* GetPointOfInterestLocale(uint32 poi_id) const { PointOfInterestLocaleContainer::const_iterator itr = _pointOfInterestLocaleStore.find(poi_id);