diff options
19 files changed, 218 insertions, 57 deletions
diff --git a/sql/updates/hotfixes/master/2020_12_11_00_hotfixes.sql b/sql/updates/hotfixes/master/2020_12_11_00_hotfixes.sql new file mode 100644 index 00000000000..8fb38de49d1 --- /dev/null +++ b/sql/updates/hotfixes/master/2020_12_11_00_hotfixes.sql @@ -0,0 +1,62 @@ +-- +-- Table structure for table `quest_info` +-- + +DROP TABLE IF EXISTS `quest_info`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `quest_info` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `InfoName` text, + `Type` tinyint(4) NOT NULL DEFAULT '0', + `Modifiers` tinyint(3) unsigned NOT NULL DEFAULT '0', + `Profession` smallint(5) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `quest_info` +-- + +LOCK TABLES `quest_info` WRITE; +/*!40000 ALTER TABLE `quest_info` DISABLE KEYS */; +/*!40000 ALTER TABLE `quest_info` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `quest_info_locale` +-- + +DROP TABLE IF EXISTS `quest_info_locale`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `quest_info_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `InfoName_lang` text, + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci +/*!50500 PARTITION BY LIST COLUMNS(locale) +(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB, + PARTITION esES VALUES IN ('esES') ENGINE = InnoDB, + PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB, + PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB, + PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB, + PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB, + PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB, + PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB, + PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB, + PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB) */; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `quest_info_locale` +-- + +LOCK TABLES `quest_info_locale` WRITE; +/*!40000 ALTER TABLE `quest_info_locale` DISABLE KEYS */; +/*!40000 ALTER TABLE `quest_info_locale` ENABLE KEYS */; +UNLOCK TABLES; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 8f4930262cc..89cb1191e4c 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -1067,6 +1067,11 @@ void HotfixDatabaseConnection::DoPrepareStatements() "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_faction_reward WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_QUEST_FACTION_REWARD, "SELECT MAX(ID) + 1 FROM quest_faction_reward", CONNECTION_SYNCH); + // QuestInfo.db2 + PrepareStatement(HOTFIX_SEL_QUEST_INFO, "SELECT ID, InfoName, Type, Modifiers, Profession FROM quest_info WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_QUEST_INFO, "SELECT MAX(ID) + 1 FROM quest_info", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_QUEST_INFO, "SELECT ID, InfoName_lang FROM quest_info_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH); + // QuestMoneyReward.db2 PrepareStatement(HOTFIX_SEL_QUEST_MONEY_REWARD, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_money_reward WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 37b6dc165c7..820b11720f5 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -615,6 +615,10 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_QUEST_FACTION_REWARD, HOTFIX_SEL_QUEST_FACTION_REWARD_MAX_ID, + HOTFIX_SEL_QUEST_INFO, + HOTFIX_SEL_QUEST_INFO_MAX_ID, + HOTFIX_SEL_QUEST_INFO_LOCALE, + HOTFIX_SEL_QUEST_MONEY_REWARD, HOTFIX_SEL_QUEST_MONEY_REWARD_MAX_ID, diff --git a/src/server/game/AI/CoreAI/GameObjectAI.cpp b/src/server/game/AI/CoreAI/GameObjectAI.cpp index e9ac3f67e6b..f65be59edbc 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.cpp +++ b/src/server/game/AI/CoreAI/GameObjectAI.cpp @@ -31,9 +31,9 @@ void GameObjectAI::QuestReward(Player* player, Quest const* quest, uint32 opt) QuestReward(player, quest, LootItemType::Item, opt); } -uint32 GameObjectAI::GetDialogStatus(Player* /*player*/) +QuestGiverStatus GameObjectAI::GetDialogStatus(Player* /*player*/) { - return DIALOG_STATUS_SCRIPTED_NO_STATUS; + return QuestGiverStatus::ScriptedDefault; } NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) { } diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 3299e0d66d7..fa2c83fdb43 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -27,6 +27,7 @@ class Quest; class SpellInfo; class Unit; enum class LootItemType : uint8; +enum class QuestGiverStatus : uint32; class TC_GAME_API GameObjectAI { @@ -66,7 +67,7 @@ class TC_GAME_API GameObjectAI virtual void QuestReward(Player* /*player*/, Quest const* /*quest*/, LootItemType /*type*/, uint32 /*opt*/) { } // Called when the dialog status between a player and the gameobject is requested. - virtual uint32 GetDialogStatus(Player* player); + virtual QuestGiverStatus GetDialogStatus(Player* player); // Called when a Player clicks a GameObject, before GossipHello // prevents achievement tracking if returning true diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index a7204104e9f..318c7c29583 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -318,9 +318,9 @@ void UnitAI::QuestReward(Player* player, Quest const* quest, uint32 opt) QuestReward(player, quest, LootItemType::Item, opt); } -uint32 UnitAI::GetDialogStatus(Player* /*player*/) +QuestGiverStatus UnitAI::GetDialogStatus(Player* /*player*/) { - return DIALOG_STATUS_SCRIPTED_NO_STATUS; + return QuestGiverStatus::ScriptedDefault; } ThreatManager& UnitAI::GetThreatManager() diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 870b460f662..498fd736a41 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -45,6 +45,7 @@ enum DamageEffectType : uint8; enum Difficulty : uint8; enum SpellEffIndex : uint8; enum class LootItemType : uint8; +enum class QuestGiverStatus : uint32; //Selection method used by SelectTarget enum SelectAggroTarget @@ -330,7 +331,7 @@ class TC_GAME_API UnitAI virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) { } // Called when the dialog status between a player and the creature is requested. - virtual uint32 GetDialogStatus(Player* player); + virtual QuestGiverStatus GetDialogStatus(Player* player); virtual void WaypointStarted(uint32 /*nodeId*/, uint32 /*pathId*/) { } virtual void WaypointReached(uint32 /*nodeId*/, uint32 /*pathId*/) { } diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index dde5b4fa2ba..d50b7548174 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -4133,6 +4133,23 @@ struct QuestFactionRewardLoadInfo } }; +struct QuestInfoLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_STRING, "InfoName" }, + { true, FT_BYTE, "Type" }, + { false, FT_BYTE, "Modifiers" }, + { false, FT_SHORT, "Profession" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, QuestInfoMeta::Instance(), HOTFIX_SEL_QUEST_INFO); + return &loadInfo; + } +}; + struct QuestMoneyRewardLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 90ec65c3b30..70d54661a19 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -220,6 +220,7 @@ DB2Storage<PvpTalentEntry> sPvpTalentStore("PvpTalent.db2", DB2Storage<PvpTalentCategoryEntry> sPvpTalentCategoryStore("PvpTalentCategory.db2", PvpTalentCategoryLoadInfo::Instance()); DB2Storage<PvpTalentSlotUnlockEntry> sPvpTalentSlotUnlockStore("PvpTalentSlotUnlock.db2", PvpTalentSlotUnlockLoadInfo::Instance()); DB2Storage<QuestFactionRewardEntry> sQuestFactionRewardStore("QuestFactionReward.db2", QuestFactionRewardLoadInfo::Instance()); +DB2Storage<QuestInfoEntry> sQuestInfoStore("QuestInfo.db2", QuestInfoLoadInfo::Instance()); DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardLoadInfo::Instance()); DB2Storage<QuestPackageItemEntry> sQuestPackageItemStore("QuestPackageItem.db2", QuestPackageItemLoadInfo::Instance()); DB2Storage<QuestSortEntry> sQuestSortStore("QuestSort.db2", QuestSortLoadInfo::Instance()); @@ -745,6 +746,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sPvpTalentCategoryStore); LOAD_DB2(sPvpTalentSlotUnlockStore); LOAD_DB2(sQuestFactionRewardStore); + LOAD_DB2(sQuestInfoStore); LOAD_DB2(sQuestMoneyRewardStore); LOAD_DB2(sQuestPackageItemStore); LOAD_DB2(sQuestSortStore); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index b0dfb56f9cc..d20c58b9dd1 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -162,6 +162,7 @@ TC_GAME_API extern DB2Storage<PvpTalentEntry> sPvpTalentSt TC_GAME_API extern DB2Storage<PvpTalentCategoryEntry> sPvpTalentCategoryStore; TC_GAME_API extern DB2Storage<PvpTalentSlotUnlockEntry> sPvpTalentSlotUnlockStore; TC_GAME_API extern DB2Storage<QuestFactionRewardEntry> sQuestFactionRewardStore; +TC_GAME_API extern DB2Storage<QuestInfoEntry> sQuestInfoStore; TC_GAME_API extern DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore; TC_GAME_API extern DB2Storage<QuestSortEntry> sQuestSortStore; TC_GAME_API extern DB2Storage<QuestXPEntry> sQuestXPStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 36f315edb80..8cb0995e121 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -2526,6 +2526,15 @@ struct QuestFactionRewardEntry int16 Difficulty[10]; }; +struct QuestInfoEntry +{ + uint32 ID; + LocalizedString InfoName; + int8 Type; + uint8 Modifiers; + uint16 Profession; +}; + struct QuestMoneyRewardEntry { uint32 ID; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 0fd96f36f82..12926a2dbc1 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -27,6 +27,7 @@ #include "QuestPackets.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "Util.h" #include "World.h" #include "WorldSession.h" @@ -387,14 +388,14 @@ void PlayerMenu::SendQuestGiverQuestListMessage(Object* questgiver) TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_GIVER_QUEST_LIST_MESSAGE NPC=%s", guid.ToString().c_str()); } -void PlayerMenu::SendQuestGiverStatus(uint32 questStatus, ObjectGuid npcGUID) const +void PlayerMenu::SendQuestGiverStatus(QuestGiverStatus questStatus, ObjectGuid npcGUID) const { WorldPackets::Quest::QuestGiverStatus packet; packet.QuestGiver.Guid = npcGUID; packet.QuestGiver.Status = questStatus; _session->SendPacket(packet.Write()); - TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC=%s, status=%u", npcGUID.ToString().c_str(), questStatus); + TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_STATUS NPC=%s, status=%u", npcGUID.ToString().c_str(), AsUnderlyingType(questStatus)); } void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGUID, bool autoLaunched, bool displayPopup) const diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index cd4ec97ae76..96209804af7 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -26,6 +26,7 @@ class Object; class Quest; class WorldSession; +enum class QuestGiverStatus : uint32; #define GOSSIP_MAX_MENU_ITEMS 32 #define DEFAULT_GOSSIP_MESSAGE 0xffffff @@ -288,7 +289,7 @@ class TC_GAME_API PlayerMenu /*********************************************************/ /*** QUEST SYSTEM ***/ /*********************************************************/ - void SendQuestGiverStatus(uint32 questStatus, ObjectGuid npcGUID) const; + void SendQuestGiverStatus(QuestGiverStatus questStatus, ObjectGuid npcGUID) const; void SendQuestGiverQuestListMessage(Object* questgiver); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 9247c0eb731..4f2a19a2d72 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1333,7 +1333,7 @@ bool GameObject::ActivateToQuest(Player const* target) const { GameObject* go = const_cast<GameObject*>(this); QuestGiverStatus questStatus = const_cast<Player*>(target)->GetQuestDialogStatus(go); - if (questStatus > DIALOG_STATUS_UNAVAILABLE) + if (questStatus != QuestGiverStatus::None && questStatus != QuestGiverStatus::Future) return true; break; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 2fd5fefc983..860933b7c39 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -16575,8 +16575,8 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) { case TYPEID_GAMEOBJECT: { - QuestGiverStatus questStatus = QuestGiverStatus(questgiver->ToGameObject()->AI()->GetDialogStatus(this)); - if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) + QuestGiverStatus questStatus = questgiver->ToGameObject()->AI()->GetDialogStatus(this); + if (questStatus != QuestGiverStatus::ScriptedDefault) return questStatus; qr = sObjectMgr->GetGOQuestRelationBounds(questgiver->GetEntry()); qir = sObjectMgr->GetGOQuestInvolvedRelationBounds(questgiver->GetEntry()); @@ -16584,8 +16584,8 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) } case TYPEID_UNIT: { - QuestGiverStatus questStatus = QuestGiverStatus(questgiver->ToCreature()->AI()->GetDialogStatus(this)); - if (questStatus != DIALOG_STATUS_SCRIPTED_NO_STATUS) + QuestGiverStatus questStatus = questgiver->ToCreature()->AI()->GetDialogStatus(this); + if (questStatus != QuestGiverStatus::ScriptedDefault) return questStatus; qr = sObjectMgr->GetCreatureQuestRelationBounds(questgiver->GetEntry()); qir = sObjectMgr->GetCreatureQuestInvolvedRelationBounds(questgiver->GetEntry()); @@ -16595,35 +16595,49 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) // it's impossible, but check TC_LOG_ERROR("entities.player.quest", "Player::GetQuestDialogStatus: Called with unexpected type (Entry: %u, Type: %u) by player '%s' (%s)", questgiver->GetEntry(), questgiver->GetTypeId(), GetName().c_str(), GetGUID().ToString().c_str()); - return DIALOG_STATUS_NONE; + return QuestGiverStatus::None; } - QuestGiverStatus result = DIALOG_STATUS_NONE; + QuestGiverStatus result = QuestGiverStatus::None; for (QuestRelations::const_iterator i = qir.first; i != qir.second; ++i) { - QuestGiverStatus result2 = DIALOG_STATUS_NONE; uint32 questId = i->second; Quest const* quest = sObjectMgr->GetQuestTemplate(questId); if (!quest) continue; - QuestStatus status = GetQuestStatus(questId); - if (status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus(questId)) - result2 = DIALOG_STATUS_REWARD; - else if (status == QUEST_STATUS_INCOMPLETE) - result2 = DIALOG_STATUS_INCOMPLETE; + switch (GetQuestStatus(questId)) + { + case QUEST_STATUS_COMPLETE: + if (quest->GetQuestTag() == QuestTagType::CovenantCalling) + result |= quest->HasFlag(QUEST_FLAGS_HIDE_REWARD_POI) ? QuestGiverStatus::CovenantCallingRewardCompleteNoPOI : QuestGiverStatus::CovenantCallingRewardCompletePOI; + else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY_QUEST)) + result |= quest->HasFlag(QUEST_FLAGS_HIDE_REWARD_POI) ? QuestGiverStatus::LegendaryRewardCompleteNoPOI : QuestGiverStatus::LegendaryRewardCompletePOI; + else + result |= quest->HasFlag(QUEST_FLAGS_HIDE_REWARD_POI) ? QuestGiverStatus::RewardCompleteNoPOI : QuestGiverStatus::RewardCompletePOI; + break; + case QUEST_STATUS_INCOMPLETE: + if (quest->GetQuestTag() == QuestTagType::CovenantCalling) + result |= QuestGiverStatus::CovenantCallingReward; + else + result |= QuestGiverStatus::Reward; + break; + default: + break; + } if (quest->IsAutoComplete() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly()) - result2 = DIALOG_STATUS_REWARD_REP; - - if (result2 > result) - result = result2; + { + if (getLevel() <= (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) + result |= QuestGiverStatus::RepeatableTurnin; + else + result |= QuestGiverStatus::TrivialRepeatableTurnin; + } } for (QuestRelations::const_iterator i = qr.first; i != qr.second; ++i) { - QuestGiverStatus result2 = DIALOG_STATUS_NONE; uint32 questId = i->second; Quest const* quest = sObjectMgr->GetQuestTemplate(questId); if (!quest) @@ -16632,8 +16646,7 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, quest->GetQuestId(), this)) continue; - QuestStatus status = GetQuestStatus(questId); - if (status == QUEST_STATUS_NONE) + if (GetQuestStatus(questId) == QUEST_STATUS_NONE) { if (CanSeeStartQuest(quest)) { @@ -16641,21 +16654,24 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) { if (getLevel() <= (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF))) { - if (quest->IsDaily()) - result2 = DIALOG_STATUS_AVAILABLE_REP; + if (quest->GetQuestTag() == QuestTagType::CovenantCalling) + result |= QuestGiverStatus::CovenantCallingQuest; + else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY_QUEST)) + result |= QuestGiverStatus::LegendaryQuest; + else if (quest->IsDaily()) + result |= QuestGiverStatus::DailyQuest; else - result2 = DIALOG_STATUS_AVAILABLE; + result |= QuestGiverStatus::Quest; } + else if (quest->IsDaily()) + result |= QuestGiverStatus::TrivialDailyQuest; else - result2 = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; + result |= QuestGiverStatus::Trivial; } else - result2 = DIALOG_STATUS_UNAVAILABLE; + result |= QuestGiverStatus::Future; } } - - if (result2 > result) - result = result2; } return result; diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index c26aa694795..417abf4cb98 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -39,7 +39,7 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet) { - uint32 questStatus = DIALOG_STATUS_NONE; + QuestGiverStatus questStatus = QuestGiverStatus::None; Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT); if (!questGiver) diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index a1d8520c8dd..5caea515380 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -314,6 +314,14 @@ uint32 Quest::MoneyValue(Player const* player) const return 0; } +Optional<QuestTagType> Quest::GetQuestTag() const +{ + if (QuestInfoEntry const* questInfo = sQuestInfoStore.LookupEntry(GetQuestInfoID())) + return static_cast<QuestTagType>(questInfo->Type); + + return {}; +} + void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const { rewards.ChoiceItemCount = GetRewChoiceItemsCount(); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 1a2e5fe6c50..f08513881a7 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -21,6 +21,7 @@ #include "Common.h" #include "DBCEnums.h" #include "DatabaseEnvFwd.h" +#include "Optional.h" #include "RaceMask.h" #include "SharedDefines.h" #include "WorldPacket.h" @@ -115,25 +116,36 @@ enum QuestStatus : uint8 MAX_QUEST_STATUS }; -enum QuestGiverStatus +enum class QuestGiverStatus : uint32 { - DIALOG_STATUS_NONE = 0x000, - DIALOG_STATUS_UNK = 0x001, - DIALOG_STATUS_UNAVAILABLE = 0x002, - DIALOG_STATUS_LOW_LEVEL_AVAILABLE = 0x004, - DIALOG_STATUS_LOW_LEVEL_REWARD_REP = 0x008, - DIALOG_STATUS_LOW_LEVEL_AVAILABLE_REP = 0x010, - DIALOG_STATUS_INCOMPLETE = 0x020, - DIALOG_STATUS_REWARD_REP = 0x040, - DIALOG_STATUS_AVAILABLE_REP = 0x080, - DIALOG_STATUS_AVAILABLE = 0x100, - DIALOG_STATUS_REWARD2 = 0x200, // no yellow dot on minimap - DIALOG_STATUS_REWARD = 0x400, // yellow dot on minimap - - // Custom value meaning that script call did not return any valid quest status - DIALOG_STATUS_SCRIPTED_NO_STATUS = 0x1000 + None = 0x000000, + Future = 0x000002, + Trivial = 0x000004, + TrivialRepeatableTurnin = 0x000008, + TrivialDailyQuest = 0x000010, + Reward = 0x000020, + JourneyReward = 0x000040, + CovenantCallingReward = 0x000080, + RepeatableTurnin = 0x000100, + DailyQuest = 0x000200, + Quest = 0x000400, + RewardCompleteNoPOI = 0x000800, + RewardCompletePOI = 0x001000, + LegendaryQuest = 0x002000, + LegendaryRewardCompleteNoPOI = 0x004000, + LegendaryRewardCompletePOI = 0x008000, + JourneyQuest = 0x010000, + JourneyRewardCompleteNoPOI = 0x020000, + JourneyRewardCompletePOI = 0x040000, + CovenantCallingQuest = 0x080000, + CovenantCallingRewardCompleteNoPOI = 0x100000, + CovenantCallingRewardCompletePOI = 0x200000, + + ScriptedDefault = 0x80000000 }; +DEFINE_ENUM_FLAG(QuestGiverStatus) + enum QuestFlags : uint32 { QUEST_FLAGS_NONE = 0x00000000, @@ -251,6 +263,26 @@ enum QuestSpecialFlags QUEST_SPECIAL_FLAGS_COMPLETED_AT_START = 0x1000 // Internal flag computed only }; +enum class QuestTagType +{ + Tag, + Profession, + Normal, + Pvp, + PetBattle, + Bounty, + Dungeon, + Invasion, + Raid, + Contribution, + RatedRreward, + InvasionWrapper, + FactionAssault, + Islands, + Threat, + CovenantCalling +}; + enum QuestObjectiveType { QUEST_OBJECTIVE_MONSTER = 0, @@ -362,7 +394,7 @@ struct QuestObjective } }; -typedef std::vector<QuestObjective> QuestObjectives; +using QuestObjectives = std::vector<QuestObjective>; struct QuestRewardDisplaySpell { @@ -396,6 +428,7 @@ class TC_GAME_API Quest uint32 XPValue(Player const* player) const; uint32 MoneyValue(Player const* player) const; + Optional<QuestTagType> GetQuestTag() const; bool HasFlag(QuestFlags flag) const { return (_flags & uint32(flag)) != 0; } bool HasFlagEx(QuestFlagsEx flag) const { return (_flagsEx & uint32(flag)) != 0; } diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index 8c738fdcebe..84a4f7f3b79 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -53,11 +53,11 @@ namespace WorldPackets struct QuestGiverInfo { QuestGiverInfo() { } - QuestGiverInfo(ObjectGuid const& guid, uint32 status) + QuestGiverInfo(ObjectGuid const& guid, ::QuestGiverStatus status) : Guid(guid), Status(status) { } ObjectGuid Guid; - uint32 Status = DIALOG_STATUS_NONE; + ::QuestGiverStatus Status = ::QuestGiverStatus::None; }; class QuestGiverStatus final : public ServerPacket |