From 56d007da4cd38075177fed21c108ec0b30a25237 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 14 Dec 2020 14:01:25 -0500 Subject: [PATCH] Core/Quests: Fixed questgiver icons Port From (https://github.com/TrinityCore/TrinityCore/commit/5f3a2d2abf296d1eaf9788244100c91de8b7a619) --- Source/Framework/Constants/QuestConst.cs | 59 ++++++++++++----- .../Database/Databases/HotfixDatabase.cs | 8 +++ Source/Game/AI/CoreAI/GameObjectAI.cs | 2 +- Source/Game/AI/CoreAI/UnitAI.cs | 2 +- Source/Game/AI/SmartScripts/SmartAI.cs | 5 -- Source/Game/DataStorage/CliDB.cs | 2 + Source/Game/DataStorage/Structs/Q_Records.cs | 9 +++ Source/Game/Entities/GameObject/GameObject.cs | 2 +- Source/Game/Entities/Player/Player.Quest.cs | 66 ++++++++++++------- Source/Game/Quest/Quest.cs | 9 +++ .../master/2020_12_11_00_hotfixes.sql | 62 +++++++++++++++++ 11 files changed, 178 insertions(+), 48 deletions(-) create mode 100644 sql/updates/hotfixes/master/2020_12_11_00_hotfixes.sql diff --git a/Source/Framework/Constants/QuestConst.cs b/Source/Framework/Constants/QuestConst.cs index 36faeaa04..bd02b1b96 100644 --- a/Source/Framework/Constants/QuestConst.cs +++ b/Source/Framework/Constants/QuestConst.cs @@ -230,23 +230,32 @@ namespace Framework.Constants Max } - public enum QuestGiverStatus + public enum QuestGiverStatus : uint { - None = 0x000, - Unk = 0x001, - Unavailable = 0x002, - LowLevelAvailable = 0x004, - LowLevelRewardRep = 0x008, - LowLevelAvailableRep = 0x010, - Incomplete = 0x020, - RewardRep = 0x040, - AvailableRep = 0x080, - Available = 0x100, - Reward2 = 0x200, // No Yellow Dot On Minimap - Reward = 0x400, // Yellow Dot On Minimap + None = 0x00, + Future = 0x02, + Trivial = 0x04, + TrivialRepeatableTurnin = 0x08, + TrivialDailyQuest = 0x10, + Reward = 0x20, + JourneyReward = 0x40, + CovenantCallingReward = 0x80, + RepeatableTurnin = 0x100, + DailyQuest = 0x200, + Quest = 0x400, + RewardCompleteNoPOI = 0x800, + RewardCompletePOI = 0x1000, + LegendaryQuest = 0x2000, + LegendaryRewardCompleteNoPOI = 0x4000, + LegendaryRewardCompletePOI = 0x8000, + JourneyQuest = 0x10000, + JourneyRewardCompleteNoPOI = 0x20000, + JourneyRewardCompletePOI = 0x40000, + CovenantCallingQuest = 0x80000, + CovenantCallingRewardCompleteNoPOI = 0x100000, + CovenantCallingRewardCompletePOI = 0x200000, - // Custom value meaning that script call did not return any valid quest status - ScriptedNoStatus = 0x1000 + ScriptedDefault = 0x80000000 } [Flags] @@ -373,4 +382,24 @@ namespace Framework.Constants Delete, ForceDelete } + + public enum QuestTagType + { + Tag, + Profession, + Normal, + Pvp, + PetBattle, + Bounty, + Dungeon, + Invasion, + Raid, + Contribution, + RatedRreward, + InvasionWrapper, + FactionAssault, + Islands, + Threat, + CovenantCalling + } } diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index 59e01b052..9605c49ed 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -790,6 +790,11 @@ namespace Framework.Database PrepareStatement(HotfixStatements.SEL_QUEST_FACTION_REWARD, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_faction_reward"); + // QuestInfo.db2 + PrepareStatement(HotfixStatements.SEL_QUEST_INFO, "SELECT ID, InfoName, Type, Modifiers, Profession FROM quest_info"); + PrepareStatement(HotfixStatements.SEL_QUEST_INFO_LOCALE, "SELECT ID, InfoName_lang FROM quest_info_locale WHERE locale = ?"); + + // QuestMoneyReward.db2 PrepareStatement(HotfixStatements.SEL_QUEST_MONEY_REWARD, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_money_reward"); @@ -1534,6 +1539,9 @@ namespace Framework.Database SEL_QUEST_FACTION_REWARD, + SEL_QUEST_INFO, + SEL_QUEST_INFO_LOCALE, + SEL_QUEST_MONEY_REWARD, SEL_QUEST_PACKAGE_ITEM, diff --git a/Source/Game/AI/CoreAI/GameObjectAI.cs b/Source/Game/AI/CoreAI/GameObjectAI.cs index 521702298..c1111f3cb 100644 --- a/Source/Game/AI/CoreAI/GameObjectAI.cs +++ b/Source/Game/AI/CoreAI/GameObjectAI.cs @@ -74,7 +74,7 @@ namespace Game.AI /// /// Called when the dialog status between a player and the gameobject is requested. /// - public virtual uint GetDialogStatus(Player player) { return 100; } + public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedDefault; } // Called when a Player clicks a GameObject, before GossipHello // prevents achievement tracking if returning true diff --git a/Source/Game/AI/CoreAI/UnitAI.cs b/Source/Game/AI/CoreAI/UnitAI.cs index 803963593..df3882096 100644 --- a/Source/Game/AI/CoreAI/UnitAI.cs +++ b/Source/Game/AI/CoreAI/UnitAI.cs @@ -529,7 +529,7 @@ namespace Game.AI public virtual void OnGameEvent(bool start, ushort eventId) { } // Called when the dialog status between a player and the creature is requested. - public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedNoStatus; } + public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedDefault; } public virtual void WaypointStarted(uint nodeId, uint pathId) { } diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index 9dcf3c9f7..bf773c7e5 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -1079,11 +1079,6 @@ namespace Game.AI GetScript().ProcessEventsFor(SmartEvents.RewardQuest, player, quest.Id, opt, false, null, me); } - public override uint GetDialogStatus(Player player) - { - return 100; - } - public override void Destroyed(Player player, uint eventId) { GetScript().ProcessEventsFor(SmartEvents.Death, player, eventId, 0, false, null, me); diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index 34fd03dee..28cfa29f3 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -229,6 +229,7 @@ namespace Game.DataStorage PvpTalentCategoryStorage = ReadDB2("PvpTalentCategory.db2", HotfixStatements.SEL_PVP_TALENT_CATEGORY); PvpTalentSlotUnlockStorage = ReadDB2("PvpTalentSlotUnlock.db2", HotfixStatements.SEL_PVP_TALENT_SLOT_UNLOCK); QuestFactionRewardStorage = ReadDB2("QuestFactionReward.db2", HotfixStatements.SEL_QUEST_FACTION_REWARD); + QuestInfoStorage = ReadDB2("QuestInfo.db2", HotfixStatements.SEL_QUEST_INFO, HotfixStatements.SEL_QUEST_INFO_LOCALE); QuestMoneyRewardStorage = ReadDB2("QuestMoneyReward.db2", HotfixStatements.SEL_QUEST_MONEY_REWARD); QuestPackageItemStorage = ReadDB2("QuestPackageItem.db2", HotfixStatements.SEL_QUEST_PACKAGE_ITEM); QuestSortStorage = ReadDB2("QuestSort.db2", HotfixStatements.SEL_QUEST_SORT, HotfixStatements.SEL_QUEST_SORT_LOCALE); @@ -584,6 +585,7 @@ namespace Game.DataStorage public static DB6Storage PvpTalentCategoryStorage; public static DB6Storage PvpTalentSlotUnlockStorage; public static DB6Storage QuestFactionRewardStorage; + public static DB6Storage QuestInfoStorage; public static DB6Storage QuestMoneyRewardStorage; public static DB6Storage QuestPackageItemStorage; public static DB6Storage QuestSortStorage; diff --git a/Source/Game/DataStorage/Structs/Q_Records.cs b/Source/Game/DataStorage/Structs/Q_Records.cs index fcd45091e..30a27ac58 100644 --- a/Source/Game/DataStorage/Structs/Q_Records.cs +++ b/Source/Game/DataStorage/Structs/Q_Records.cs @@ -25,6 +25,15 @@ namespace Game.DataStorage public short[] Difficulty = new short[10]; } + public sealed class QuestInfoRecord + { + public uint Id; + public LocalizedString InfoName; + public sbyte Type; + public byte Modifiers; + public ushort Profession; + } + public sealed class QuestMoneyRewardRecord { public uint Id; diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index cf44db25b..3edeead2b 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -1217,7 +1217,7 @@ namespace Game.Entities { case GameObjectTypes.QuestGiver: QuestGiverStatus questStatus = target.GetQuestDialogStatus(this); - if (questStatus > QuestGiverStatus.Unavailable) + if (questStatus != QuestGiverStatus.None && questStatus != QuestGiverStatus.Future) return true; break; // scan GO chest with loot including quest items diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index f487750f4..98cf9dc44 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -1860,8 +1860,8 @@ namespace Game.Entities { case TypeId.GameObject: { - QuestGiverStatus questStatus = (QuestGiverStatus)questgiver.ToGameObject().GetAI().GetDialogStatus(this); - if (questStatus != QuestGiverStatus.ScriptedNoStatus) + QuestGiverStatus questStatus = questgiver.ToGameObject().GetAI().GetDialogStatus(this); + if (questStatus != QuestGiverStatus.ScriptedDefault) return questStatus; qr = Global.ObjectMgr.GetGOQuestRelationBounds(questgiver.GetEntry()); qir = Global.ObjectMgr.GetGOQuestInvolvedRelationBounds(questgiver.GetEntry()); @@ -1869,8 +1869,8 @@ namespace Game.Entities } case TypeId.Unit: { - QuestGiverStatus questStatus = (QuestGiverStatus)questgiver.ToCreature().GetAI().GetDialogStatus(this); - if (questStatus != QuestGiverStatus.ScriptedNoStatus) + QuestGiverStatus questStatus = questgiver.ToCreature().GetAI().GetDialogStatus(this); + if (questStatus != QuestGiverStatus.ScriptedDefault) return questStatus; qr = Global.ObjectMgr.GetCreatureQuestRelationBounds(questgiver.GetEntry()); qir = Global.ObjectMgr.GetCreatureQuestInvolvedRelationBounds(questgiver.GetEntry()); @@ -1886,27 +1886,41 @@ namespace Game.Entities foreach (var questId in qir) { - QuestGiverStatus result2 = QuestGiverStatus.None; Quest quest = Global.ObjectMgr.GetQuestTemplate(questId); if (quest == null) continue; - QuestStatus status = GetQuestStatus(questId); - if (status == QuestStatus.Complete && !GetQuestRewardStatus(questId)) - result2 = QuestGiverStatus.Reward; - else if (status == QuestStatus.Incomplete) - result2 = QuestGiverStatus.Incomplete; + switch (GetQuestStatus(questId)) + { + case QuestStatus.Complete: + if (quest.GetQuestTag() == QuestTagType.CovenantCalling) + result |= quest.HasFlag(QuestFlags.HideRewardPoi) ? QuestGiverStatus.CovenantCallingRewardCompleteNoPOI : QuestGiverStatus.CovenantCallingRewardCompletePOI; + else if (quest.HasFlagEx(QuestFlagsEx.LegendaryQuest)) + result |= quest.HasFlag(QuestFlags.HideRewardPoi) ? QuestGiverStatus.LegendaryRewardCompleteNoPOI : QuestGiverStatus.LegendaryRewardCompletePOI; + else + result |= quest.HasFlag(QuestFlags.HideRewardPoi) ? QuestGiverStatus.RewardCompleteNoPOI : QuestGiverStatus.RewardCompletePOI; + break; + case QuestStatus.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 = QuestGiverStatus.RewardRep; - - if (result2 > result) - result = result2; + { + if (GetLevel() <= (GetQuestLevel(quest) + WorldConfig.GetIntValue(WorldCfg.QuestLowLevelHideDiff))) + result |= QuestGiverStatus.RepeatableTurnin; + else + result |= QuestGiverStatus.TrivialRepeatableTurnin; + } } foreach (var questId in qr) { - QuestGiverStatus result2 = QuestGiverStatus.None; Quest quest = Global.ObjectMgr.GetQuestTemplate(questId); if (quest == null) continue; @@ -1914,8 +1928,7 @@ namespace Game.Entities if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.QuestAvailable, quest.Id, this)) continue; - QuestStatus status = GetQuestStatus(questId); - if (status == QuestStatus.None) + if (GetQuestStatus(questId) == QuestStatus.None) { if (CanSeeStartQuest(quest)) { @@ -1923,21 +1936,24 @@ namespace Game.Entities { if (GetLevel() <= (GetQuestLevel(quest) + WorldConfig.GetIntValue(WorldCfg.QuestLowLevelHideDiff))) { - if (quest.IsDaily()) - result2 = QuestGiverStatus.AvailableRep; + if (quest.GetQuestTag() == QuestTagType.CovenantCalling) + result |= QuestGiverStatus.CovenantCallingQuest; + else if (quest.HasFlagEx(QuestFlagsEx.LegendaryQuest)) + result |= QuestGiverStatus.LegendaryQuest; + else if (quest.IsDaily()) + result |= QuestGiverStatus.DailyQuest; else - result2 = QuestGiverStatus.Available; + result |= QuestGiverStatus.Quest; } + else if (quest.IsDaily()) + result |= QuestGiverStatus.TrivialDailyQuest; else - result2 = QuestGiverStatus.LowLevelAvailable; + result |= QuestGiverStatus.Trivial; } else - result2 = QuestGiverStatus.Unavailable; + result |= QuestGiverStatus.Future; } } - - if (result2 > result) - result = result2; } return result; diff --git a/Source/Game/Quest/Quest.cs b/Source/Game/Quest/Quest.cs index fabd95391..ce0e052b9 100644 --- a/Source/Game/Quest/Quest.cs +++ b/Source/Game/Quest/Quest.cs @@ -318,6 +318,15 @@ namespace Game return 0; } + public QuestTagType? GetQuestTag() + { + QuestInfoRecord questInfo = CliDB.QuestInfoStorage.LookupByKey(QuestInfoID); + if (questInfo != null) + return (QuestTagType)questInfo.Type; + + return null; + } + public void BuildQuestRewards(QuestRewards rewards, Player player) { rewards.ChoiceItemCount = GetRewChoiceItemsCount(); 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 000000000..8fb38de49 --- /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;