diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index a97a3fc52..dd64c90df 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -26,6 +26,14 @@ namespace Framework.Database "Points, Flags, UiOrder, IconFileID, RewardItemID, CriteriaTree, SharesCriteria, CovenantID FROM achievement"); PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_LOCALE, "SELECT ID, Description_lang, Title_lang, Reward_lang FROM achievement_locale WHERE locale = ?"); + // AdventureJournal.db2 + PrepareStatement(HotfixStatements.SEL_ADVENTURE_JOURNAL, "SELECT ID, Name, Description, ButtonText, RewardDescription, ContinueDescription, Type, " + + "PlayerConditionId, Flags, ButtonActionType, TextureFileDataId, LfgDungeonId, QuestId, BattleMasterListId, PriorityMin, PriorityMax, ItemId, " + + "ItemQuantity, CurrencyType, CurrencyQuantity, UiMapId, BonusPlayerConditionId1, BonusPlayerConditionId2, BonusValue1, BonusValue2" + + " FROM adventure_journal"); + PrepareStatement(HotfixStatements.SEL_ADVENTURE_JOURNAL_LOCALE, "SELECT ID, Name_lang, Description_lang, ButtonText_lang, RewardDescription_lang, " + + "ContinueDescription_lang FROM adventure_journal_locale WHERE locale = ?"); + // AnimationData.db2 PrepareStatement(HotfixStatements.SEL_ANIMATION_DATA, "SELECT ID, BehaviorID, BehaviorTier, Fallback, Flags1, Flags2 FROM animation_data"); @@ -1142,6 +1150,9 @@ namespace Framework.Database SEL_ACHIEVEMENT, SEL_ACHIEVEMENT_LOCALE, + SEL_ADVENTURE_JOURNAL, + SEL_ADVENTURE_JOURNAL_LOCALE, + SEL_ANIMATION_DATA, SEL_ANIM_KIT, diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index 9c17183d9..e9093f8cd 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -51,6 +51,7 @@ namespace Game.DataStorage } AchievementStorage = ReadDB2("Achievement.db2", HotfixStatements.SEL_ACHIEVEMENT, HotfixStatements.SEL_ACHIEVEMENT_LOCALE); + AdventureJournalStorage = ReadDB2("AdventureJournal.db2", HotfixStatements.SEL_ADVENTURE_JOURNAL, HotfixStatements.SEL_ADVENTURE_JOURNAL_LOCALE); AnimationDataStorage = ReadDB2("AnimationData.db2", HotfixStatements.SEL_ANIMATION_DATA); AnimKitStorage = ReadDB2("AnimKit.db2", HotfixStatements.SEL_ANIM_KIT); AreaGroupMemberStorage = ReadDB2("AreaGroupMember.db2", HotfixStatements.SEL_AREA_GROUP_MEMBER); @@ -408,6 +409,7 @@ namespace Game.DataStorage #region Main Collections public static DB6Storage AchievementStorage; + public static DB6Storage AdventureJournalStorage; public static DB6Storage AnimationDataStorage; public static DB6Storage AnimKitStorage; public static DB6Storage AreaGroupMemberStorage; diff --git a/Source/Game/DataStorage/Structs/A_Records.cs b/Source/Game/DataStorage/Structs/A_Records.cs index 97711571f..6593285e3 100644 --- a/Source/Game/DataStorage/Structs/A_Records.cs +++ b/Source/Game/DataStorage/Structs/A_Records.cs @@ -42,6 +42,33 @@ namespace Game.DataStorage public int CovenantID; } + public sealed class AdventureJournalRecord + { + public uint Id; + public LocalizedString Name; + public LocalizedString Description; + public LocalizedString ButtonText; + public LocalizedString RewardDescription; + public LocalizedString ContinueDescription; + public byte Type; + public uint PlayerConditionID; + public byte Flags; + public byte ButtonActionType; + public int TextureFileDataID; + public ushort LfgDungeonID; + public uint QuestID; + public ushort BattleMasterListID; + public byte PriorityMin; + public byte PriorityMax; + public int ItemID; + public uint ItemQuantity; + public ushort CurrencyType; + public uint CurrencyQuantity; + public ushort UiMapID; + public int[] BonusPlayerConditionID = new int[2]; + public byte[] BonusValue = new byte[2]; + } + public sealed class AnimationDataRecord { public uint Id; diff --git a/Source/Game/Handlers/MiscHandler.cs b/Source/Game/Handlers/MiscHandler.cs index e20b25258..9d87960ea 100644 --- a/Source/Game/Handlers/MiscHandler.cs +++ b/Source/Game/Handlers/MiscHandler.cs @@ -23,6 +23,7 @@ using Game.Entities; using Game.Groups; using Game.Guilds; using Game.Maps; +using Game.Misc; using Game.Networking; using Game.Networking.Packets; using Game.PvP; @@ -135,14 +136,14 @@ namespace Game [WorldPacketHandler(ClientOpcodes.CompleteCinematic)] void HandleCompleteCinematic(CompleteCinematic packet) - { + { // If player has sight bound to visual waypoint NPC we should remove it GetPlayer().GetCinematicMgr().EndCinematic(); } [WorldPacketHandler(ClientOpcodes.NextCinematicCamera)] void HandleNextCinematicCamera(NextCinematicCamera packet) - { + { // Sent by client when cinematic actually begun. So we begin the server side process GetPlayer().GetCinematicMgr().NextCinematicCamera(); } @@ -738,7 +739,7 @@ namespace Game if (_warden == null || packet.Data.GetSize() == 0) return; - _warden.DecryptData(packet.Data.GetData()); + _warden.DecryptData(packet.Data.GetData()); WardenOpcodes opcode = (WardenOpcodes)packet.Data.ReadUInt8(); switch (opcode) @@ -767,5 +768,74 @@ namespace Game break; } } + + [WorldPacketHandler(ClientOpcodes.AdventureJournalOpenQuest)] + void HandleAdventureJournalOpenQuest(AdventureJournalOpenQuest adventureJournalOpenQuest) + { + var adventureJournalEntry = CliDB.AdventureJournalStorage.LookupByKey(adventureJournalOpenQuest.AdventureJournalID); + if (adventureJournalEntry == null) + return; + + Quest quest = Global.ObjectMgr.GetQuestTemplate(adventureJournalEntry.QuestID); + if (quest == null) + return; + + if (_player.CanTakeQuest(quest, true)) + { + PlayerMenu menu = new PlayerMenu(_player.GetSession()); + menu.SendQuestGiverQuestDetails(quest, _player.GetGUID(), true, false); + } + } + + [WorldPacketHandler(ClientOpcodes.AdventureJournalStartQuest)] + void HandleAdventureJournalStartQuest(AdventureJournalStartQuest adventureJournalStartQuest) + { + Quest quest = Global.ObjectMgr.GetQuestTemplate(adventureJournalStartQuest.QuestID); + if (quest == null) + return; + + AdventureJournalRecord adventureJournalEntry = null; + foreach (var adventureJournal in CliDB.AdventureJournalStorage.Values) + { + if (quest.Id == adventureJournal.QuestID) + { + adventureJournalEntry = adventureJournal; + break; + } + } + + if (adventureJournalEntry == null) + return; + + if (_player.MeetPlayerCondition(adventureJournalEntry.PlayerConditionID) && _player.CanTakeQuest(quest, true)) + _player.AddQuestAndCheckCompletion(quest, null); + } + + [WorldPacketHandler(ClientOpcodes.AdventureJournalUpdateSuggestions)] + void HandleAdventureJournalUpdateSuggestions(AdventureJournalUpdateSuggestions adventureJournalUpdateSuggestions) + { + if (adventureJournalUpdateSuggestions.OnLevelUp && _player.GetLevel() < 10) + return; + + AdventureJournalDataResponse response = new AdventureJournalDataResponse(); + response.OnLevelUp = adventureJournalUpdateSuggestions.OnLevelUp; + int count = 0; + foreach (var adventureJournal in CliDB.AdventureJournalStorage.Values) + { + if (count >= 7) + break; + + if (_player.MeetPlayerCondition(adventureJournal.PlayerConditionID)) + { + AdventureJournalDataInfo dataInfo; + dataInfo.AdventureJournalID = (int)adventureJournal.Id; + dataInfo.Priority = (int)adventureJournal.PriorityMax; + response.AdventureJournalDatas.Add(dataInfo); + count++; + } + } + + SendPacket(response); + } } } diff --git a/Source/Game/Networking/Packets/MiscPackets.cs b/Source/Game/Networking/Packets/MiscPackets.cs index 4c73bda14..b77ae2724 100644 --- a/Source/Game/Networking/Packets/MiscPackets.cs +++ b/Source/Game/Networking/Packets/MiscPackets.cs @@ -1321,6 +1321,62 @@ namespace Game.Networking.Packets public ObjectGuid SourceGuid; } + class AdventureJournalOpenQuest : ClientPacket + { + public AdventureJournalOpenQuest(WorldPacket packet) : base(packet) { } + + public override void Read() + { + AdventureJournalID = _worldPacket.ReadUInt32(); + } + + public uint AdventureJournalID; + } + + class AdventureJournalStartQuest : ClientPacket + { + public AdventureJournalStartQuest(WorldPacket packet) : base(packet) { } + + public override void Read() + { + QuestID = _worldPacket.ReadUInt32(); + } + + public uint QuestID; + } + + class AdventureJournalUpdateSuggestions : ClientPacket + { + public AdventureJournalUpdateSuggestions(WorldPacket packet) : base(packet) { } + + public override void Read() + { + OnLevelUp = _worldPacket.HasBit(); + } + + public bool OnLevelUp; + } + + class AdventureJournalDataResponse : ServerPacket + { + public AdventureJournalDataResponse() : base(ServerOpcodes.AdventureJournalDataResponse) { } + + public override void Write() + { + _worldPacket.WriteBit(OnLevelUp); + _worldPacket.FlushBits(); + _worldPacket.WriteInt32(AdventureJournalDatas.Count); + foreach (var dataInfo in AdventureJournalDatas) + { + _worldPacket.WriteInt32(dataInfo.AdventureJournalID); + _worldPacket.WriteInt32(dataInfo.Priority); + } + } + + public bool OnLevelUp; + public List AdventureJournalDatas; + } + //Structs struct PhaseShiftDataPhase { @@ -1355,4 +1411,10 @@ namespace Game.Networking.Packets public List Phases = new List(); public ObjectGuid PersonalGUID; } + + struct AdventureJournalDataInfo + { + public int AdventureJournalID; + public int Priority; + } } diff --git a/sql/updates/hotfixes/master/2021_02_06_00_hotfixes.sql b/sql/updates/hotfixes/master/2021_02_06_00_hotfixes.sql new file mode 100644 index 000000000..5575ff335 --- /dev/null +++ b/sql/updates/hotfixes/master/2021_02_06_00_hotfixes.sql @@ -0,0 +1,66 @@ +-- +-- Table structure for table `adventure_journal` +-- +DROP TABLE IF EXISTS `adventure_journal`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `adventure_journal` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Name` text DEFAULT NULL, + `Description` text DEFAULT NULL, + `ButtonText` text DEFAULT NULL, + `RewardDescription` text DEFAULT NULL, + `ContinueDescription` text DEFAULT NULL, + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0', + `PlayerConditionId` int(10) unsigned NOT NULL DEFAULT '0', + `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0', + `ButtonActionType` tinyint(3) unsigned NOT NULL DEFAULT '0', + `TextureFileDataId` int(11) NOT NULL DEFAULT '0', + `LfgDungeonId` smallint(5) unsigned NOT NULL DEFAULT '0', + `QuestId` smallint(5) unsigned NOT NULL DEFAULT '0', + `BattleMasterListId` smallint(5) unsigned NOT NULL DEFAULT '0', + `PriorityMin` tinyint(3) unsigned NOT NULL DEFAULT '0', + `PriorityMax` tinyint(3) unsigned NOT NULL DEFAULT '0', + `ItemId` int(11) NOT NULL DEFAULT '0', + `ItemQuantity` int(10) unsigned NOT NULL DEFAULT '0', + `CurrencyType` smallint(5) unsigned NOT NULL DEFAULT '0', + `CurrencyQuantity` tinyint(3) unsigned NOT NULL DEFAULT '0', + `UiMapId` smallint(5) unsigned NOT NULL DEFAULT '0', + `BonusPlayerConditionId1` int(11) NOT NULL DEFAULT '0', + `BonusPlayerConditionId2` int(11) NOT NULL DEFAULT '0', + `BonusValue1` tinyint(3) unsigned NOT NULL DEFAULT '0', + `BonusValue2` tinyint(3) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `adventure_journal_locale` +-- +DROP TABLE IF EXISTS `adventure_journal_locale`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `adventure_journal_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `Name_lang` text DEFAULT NULL, + `Description_lang` text DEFAULT NULL, + `ButtonText_lang` text DEFAULT NULL, + `RewardDescription_lang` text DEFAULT NULL, + `ContinueDescription_lang` text DEFAULT NULL, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`) +) 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 */; \ No newline at end of file