diff options
author | Aqua Deus <95978183+aquadeus@users.noreply.github.com> | 2022-10-11 22:16:02 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-11 22:16:02 +0200 |
commit | 4772c4817f1b34553f1c697e2aedc0372af9aea2 (patch) | |
tree | 9f7ed43aba6c4be3460e2de5097204ea0fbccf82 /src | |
parent | 8262d6be23811eddfd280b7d9341e2cac01a6e83 (diff) |
Core/Garrisons: Implement SMSG_GARRISON_OPEN_TALENT_NPC opcode (#28256)
Co-authored-by: ModoX <moardox@gmail.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 7 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 4 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2LoadInfo.h | 25 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 2 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 17 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/GossipDef.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 17 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 40 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 17 | ||||
-rw-r--r-- | src/server/game/Server/Packets/GarrisonPackets.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Server/Packets/GarrisonPackets.h | 12 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 7 |
15 files changed, 158 insertions, 6 deletions
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 4e2fce8cec3..3af206c0644 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -688,6 +688,13 @@ void HotfixDatabaseConnection::DoPrepareStatements() " FROM garr_site_level_plot_inst WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, "SELECT MAX(ID) + 1 FROM garr_site_level_plot_inst", CONNECTION_SYNCH); + // GarrTalentTree.db2 + PrepareStatement(HOTFIX_SEL_GARR_TALENT_TREE, "SELECT ID, Name, GarrTypeID, ClassID, MaxTiers, UiOrder, Flags, UiTextureKitID, " + "GarrTalentTreeType, PlayerConditionID, FeatureTypeIndex, FeatureSubtypeIndex, CurrencyID FROM garr_talent_tree" + " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_GARR_TALENT_TREE, "SELECT MAX(ID) + 1 FROM garr_talent_tree", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_TALENT_TREE, "SELECT ID, Name_lang FROM garr_talent_tree_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH); + // GemProperties.db2 PrepareStatement(HOTFIX_SEL_GEM_PROPERTIES, "SELECT ID, EnchantId, Type FROM gem_properties WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_GEM_PROPERTIES, "SELECT MAX(ID) + 1 FROM gem_properties", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index befc2fbfbd5..2bc899c79c7 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -393,6 +393,10 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST_MAX_ID, + HOTFIX_SEL_GARR_TALENT_TREE, + HOTFIX_SEL_GARR_TALENT_TREE_MAX_ID, + HOTFIX_SEL_GARR_TALENT_TREE_LOCALE, + HOTFIX_SEL_GEM_PROPERTIES, HOTFIX_SEL_GEM_PROPERTIES_MAX_ID, diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 211c620922a..c85f469e7b3 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -2456,6 +2456,31 @@ struct GarrSiteLevelPlotInstLoadInfo } }; +struct GarrTalentTreeLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static constexpr DB2FieldMeta fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_STRING, "Name" }, + { false, FT_BYTE, "GarrTypeID" }, + { true, FT_INT, "ClassID" }, + { true, FT_BYTE, "MaxTiers" }, + { true, FT_BYTE, "UiOrder" }, + { true, FT_INT, "Flags" }, + { false, FT_SHORT, "UiTextureKitID" }, + { true, FT_INT, "GarrTalentTreeType" }, + { true, FT_INT, "PlayerConditionID" }, + { true, FT_BYTE, "FeatureTypeIndex" }, + { true, FT_BYTE, "FeatureSubtypeIndex" }, + { true, FT_INT, "CurrencyID" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::size(fields), GarrTalentTreeMeta::Instance(), HOTFIX_SEL_GARR_TALENT_TREE); + return &loadInfo; + } +}; + struct GemPropertiesLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 4751b6c1177..3f78e9371b4 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -148,6 +148,7 @@ DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore("GarrPlot DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore("GarrPlotInstance.db2", GarrPlotInstanceLoadInfo::Instance()); DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore("GarrSiteLevel.db2", GarrSiteLevelLoadInfo::Instance()); DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore("GarrSiteLevelPlotInst.db2", GarrSiteLevelPlotInstLoadInfo::Instance()); +DB2Storage<GarrTalentTreeEntry> sGarrTalentTreeStore("GarrTalentTree.db2", GarrTalentTreeLoadInfo::Instance()); DB2Storage<GemPropertiesEntry> sGemPropertiesStore("GemProperties.db2", GemPropertiesLoadInfo::Instance()); DB2Storage<GlobalCurveEntry> sGlobalCurveStore("GlobalCurve.db2", GlobalCurveLoadInfo::Instance()); DB2Storage<GlyphBindableSpellEntry> sGlyphBindableSpellStore("GlyphBindableSpell.db2", GlyphBindableSpellLoadInfo::Instance()); @@ -722,6 +723,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sGarrPlotInstanceStore); LOAD_DB2(sGarrSiteLevelStore); LOAD_DB2(sGarrSiteLevelPlotInstStore); + LOAD_DB2(sGarrTalentTreeStore); LOAD_DB2(sGemPropertiesStore); LOAD_DB2(sGlobalCurveStore); LOAD_DB2(sGlyphBindableSpellStore); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 3fba87f73b6..49b2f551f5a 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -117,6 +117,7 @@ TC_GAME_API extern DB2Storage<GarrPlotBuildingEntry> sGarrPlotBui TC_GAME_API extern DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore; TC_GAME_API extern DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore; TC_GAME_API extern DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore; +TC_GAME_API extern DB2Storage<GarrTalentTreeEntry> sGarrTalentTreeStore; TC_GAME_API extern DB2Storage<GemPropertiesEntry> sGemPropertiesStore; TC_GAME_API extern DB2Storage<GlyphPropertiesEntry> sGlyphPropertiesStore; TC_GAME_API extern DB2Storage<GuildColorBackgroundEntry> sGuildColorBackgroundStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 9e08a04866d..e52a14eaa30 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1759,6 +1759,23 @@ struct GarrSiteLevelPlotInstEntry uint8 UiMarkerSize; }; +struct GarrTalentTreeEntry +{ + uint32 ID; + LocalizedString Name; + uint8 GarrTypeID; + int32 ClassID; + int8 MaxTiers; + int8 UiOrder; + int32 Flags; + uint16 UiTextureKitID; + int32 GarrTalentTreeType; + int32 PlayerConditionID; + int8 FeatureTypeIndex; + int8 FeatureSubtypeIndex; + int32 CurrencyID; +}; + struct GemPropertiesEntry { uint32 ID; diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index 3a77d0f2a7f..25da6049f1c 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -64,7 +64,7 @@ enum class GossipOptionNpc : uint8 GarrisonTradeskill = 29, /*NYI*/ // White chat bubble GarrisonRecruitment = 30, /*NYI*/ // White chat bubble AdventureMap = 31, /*NYI*/ // White chat bubble - GarrisonTalent = 32, /*NYI*/ // White chat bubble + GarrisonTalent = 32, // White chat bubble ContributionCollector = 33, /*NYI*/ // White chat bubble Transmogrify = 34, // Purple helm AzeriteRespec = 35, /*NYI*/ // White chat bubble diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9d7ff5c40a2..037ae501aae 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -56,6 +56,7 @@ #include "GameEventMgr.h" #include "GameObjectAI.h" #include "Garrison.h" +#include "GarrisonMgr.h" #include "GitRevision.h" #include "GossipDef.h" #include "GridNotifiers.h" @@ -13937,6 +13938,13 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men PlayerTalkClass->SendCloseGossip(); SendRespecWipeConfirm(guid, 0, SPEC_RESET_GLYPHS); break; + case GossipOptionNpc::GarrisonTalent: + { + GossipMenuAddon const* addon = sObjectMgr->GetGossipMenuAddon(menuId); + GossipMenuItemAddon const* itemAddon = sObjectMgr->GetGossipMenuItemAddon(menuId, gossipListId); + SendGarrisonOpenTalentNpc(guid, itemAddon ? itemAddon->GarrTalentTreeID.value_or(0) : 0, addon ? addon->FriendshipFactionID : 0); + break; + } case GossipOptionNpc::Transmogrify: GetSession()->SendOpenTransmogrifier(guid); break; @@ -28156,3 +28164,12 @@ void Player::SendDisplayToast(uint32 entry, DisplayToastType type, bool isBonusR SendDirectMessage(displayToast.Write()); } + +void Player::SendGarrisonOpenTalentNpc(ObjectGuid guid, int32 garrTalentTreeId, int32 friendshipFactionId) +{ + WorldPackets::Garrison::GarrisonOpenTalentNpc openTalentNpc; + openTalentNpc.NpcGUID = guid; + openTalentNpc.GarrTalentTreeID = garrTalentTreeId; + openTalentNpc.FriendshipFactionID = friendshipFactionId; + SendDirectMessage(openTalentNpc.Write()); +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 67cb3f97b22..cbbacf92c49 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2772,6 +2772,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool CanEnableWarModeInArea() const; void UpdateWarModeAuras(); + void SendGarrisonOpenTalentNpc(ObjectGuid guid, int32 garrTalentTreeId, int32 friendshipFactionId); + std::string GetDebugInfo() const override; UF::UpdateField<UF::PlayerData, 0, TYPEID_PLAYER> m_playerData; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 96db3bfa064..08763fe8aeb 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -9701,7 +9701,7 @@ void ObjectMgr::LoadGossipMenuItems() TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " gossip_menu_option entries in %u ms", _gossipMenuItemsStore.size(), GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadGossipMenuFriendshipFactions() +void ObjectMgr::LoadGossipMenuAddon() { uint32 oldMSTime = getMSTime(); @@ -9744,6 +9744,44 @@ void ObjectMgr::LoadGossipMenuFriendshipFactions() TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_addon IDs in %u ms", uint32(_gossipMenuAddonStore.size()), GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadGossipMenuItemAddon() +{ + uint32 oldMSTime = getMSTime(); + + _gossipMenuItemAddonStore.clear(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT MenuID, OptionId, GarrTalentTreeID FROM gossip_menu_option_addon"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 gossip_menu_option_addon IDs. DB table `gossip_menu_option_addon` is empty!"); + return; + } + + do + { + Field* fields = result->Fetch(); + + uint32 menuId = fields[0].GetUInt32(); + uint32 optionId = fields[1].GetUInt32(); + GossipMenuItemAddon& addon = _gossipMenuItemAddonStore[{ menuId, optionId }]; + if (!fields[2].IsNull()) + { + addon.GarrTalentTreeID = fields[2].GetInt32(); + + if (!sGarrTalentTreeStore.LookupEntry(*addon.GarrTalentTreeID)) + { + TC_LOG_ERROR("sql.sql", "Table gossip_menu_option_addon: MenuID %u OptionID %u is using non-existing GarrTalentTree %d", + menuId, optionId, *addon.GarrTalentTreeID); + addon.GarrTalentTreeID.reset(); + } + } + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option_addon IDs in %u ms", uint32(_gossipMenuItemAddonStore.size()), GetMSTimeDiffToNow(oldMSTime)); +} + Trainer::Trainer const* ObjectMgr::GetTrainer(uint32 trainerId) const { return Trinity::Containers::MapGetValuePtr(_trainers, trainerId); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 6919992f228..e898b5a9e42 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -757,6 +757,11 @@ struct GossipMenuItems ConditionContainer Conditions; }; +struct GossipMenuItemAddon +{ + Optional<int32> GarrTalentTreeID; +}; + struct GossipMenus { uint32 MenuID; @@ -774,6 +779,7 @@ typedef std::pair<GossipMenusContainer::const_iterator, GossipMenusContainer::co typedef std::pair<GossipMenusContainer::iterator, GossipMenusContainer::iterator> GossipMenusMapBoundsNonConst; typedef std::multimap<uint32, GossipMenuItems> GossipMenuItemsContainer; typedef std::unordered_map<uint32, GossipMenuAddon> GossipMenuAddonContainer; +typedef std::unordered_map<std::pair<uint32, uint32>, GossipMenuItemAddon> GossipMenuItemAddonContainer; struct QuestPOIBlobPoint { @@ -1394,7 +1400,8 @@ class TC_GAME_API ObjectMgr void LoadGossipMenu(); void LoadGossipMenuItems(); - void LoadGossipMenuFriendshipFactions(); + void LoadGossipMenuAddon(); + void LoadGossipMenuItemAddon(); void LoadVendors(); void LoadTrainers(); @@ -1697,6 +1704,13 @@ class TC_GAME_API ObjectMgr return &itr->second; return nullptr; } + GossipMenuItemAddon const* GetGossipMenuItemAddon(uint32 menuId, uint32 optionId) const + { + auto itr = _gossipMenuItemAddonStore.find({ menuId, optionId }); + if (itr != _gossipMenuItemAddonStore.end()) + return &itr->second; + return nullptr; + } // for wintergrasp only GraveyardContainer GraveyardStore; @@ -1831,6 +1845,7 @@ class TC_GAME_API ObjectMgr GossipMenusContainer _gossipMenusStore; GossipMenuItemsContainer _gossipMenuItemsStore; GossipMenuAddonContainer _gossipMenuAddonStore; + GossipMenuItemAddonContainer _gossipMenuItemAddonStore; PointOfInterestContainer _pointsOfInterestStore; QuestPOIContainer _questPOIStore; diff --git a/src/server/game/Server/Packets/GarrisonPackets.cpp b/src/server/game/Server/Packets/GarrisonPackets.cpp index 0796748d877..234ce345462 100644 --- a/src/server/game/Server/Packets/GarrisonPackets.cpp +++ b/src/server/game/Server/Packets/GarrisonPackets.cpp @@ -481,4 +481,13 @@ WorldPacket const* GarrisonBuildingActivated::Write() return &_worldPacket; } + +WorldPacket const* GarrisonOpenTalentNpc::Write() +{ + _worldPacket << NpcGUID; + _worldPacket << int32(GarrTalentTreeID); + _worldPacket << int32(FriendshipFactionID); + + return &_worldPacket; +} } diff --git a/src/server/game/Server/Packets/GarrisonPackets.h b/src/server/game/Server/Packets/GarrisonPackets.h index 983982842f8..9b1367a5819 100644 --- a/src/server/game/Server/Packets/GarrisonPackets.h +++ b/src/server/game/Server/Packets/GarrisonPackets.h @@ -437,6 +437,18 @@ namespace WorldPackets uint32 GarrPlotInstanceID = 0; }; + + class GarrisonOpenTalentNpc final : public ServerPacket + { + public: + GarrisonOpenTalentNpc() : ServerPacket(SMSG_GARRISON_OPEN_TALENT_NPC, 16 + 4 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid NpcGUID; + int32 GarrTalentTreeID = 0; + int32 FriendshipFactionID = 0; // Always 0 except on The Deaths of Chromie Scenario + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 9782e06dc85..3c3226e16e8 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1330,7 +1330,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_CRAFTER, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_RECRUITMENT_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TALENT_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TALENT_NPC, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 0a9f1a144e3..13259d7a258 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2250,8 +2250,11 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Gossip menu options..."); sObjectMgr->LoadGossipMenuItems(); - TC_LOG_INFO("server.loading", "Loading Gossip menu friendship factions..."); - sObjectMgr->LoadGossipMenuFriendshipFactions(); + TC_LOG_INFO("server.loading", "Loading Gossip menu addon..."); + sObjectMgr->LoadGossipMenuAddon(); + + TC_LOG_INFO("server.loading", "Loading Gossip menu item addon..."); + sObjectMgr->LoadGossipMenuItemAddon(); TC_LOG_INFO("server.loading", "Loading Creature trainers..."); sObjectMgr->LoadCreatureTrainers(); // must be after LoadGossipMenuItems |