diff options
| author | Shauren <shauren.trinity@gmail.com> | 2022-12-04 15:13:20 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2022-12-04 15:13:20 +0100 |
| commit | e98e1283ea0034baf6be9aa2ffb386eb5582801b (patch) | |
| tree | b1dd854d88e6e049d26b208bb259cdc7d31f29f8 /src/server/game/Entities | |
| parent | de7c03c8385780f05530c2b3cf952a712d5f8f00 (diff) | |
Core: Updated to 10.0.2
Diffstat (limited to 'src/server/game/Entities')
22 files changed, 2232 insertions, 1127 deletions
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 518cad8b3a1..15b175f5c19 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -108,7 +108,7 @@ void Corpse::SaveToDB() DeleteFromDB(trans); std::ostringstream items; - for (uint16 index = 0; index < EQUIPMENT_SLOT_END; ++index) + for (size_t index = 0; index < m_corpseData->Items.size(); ++index) items << m_corpseData->Items[index] << ' '; uint16 index = 0; @@ -194,8 +194,8 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetObjectScale(1.0f); SetDisplayId(fields[5].GetUInt32()); std::vector<std::string_view> items = Trinity::Tokenize(fields[6].GetStringView(), ' ', false); - if (items.size() == EQUIPMENT_SLOT_END) - for (uint32 index = 0; index < EQUIPMENT_SLOT_END; ++index) + if (items.size() == m_corpseData->Items.size()) + for (size_t index = 0; index < m_corpseData->Items.size(); ++index) SetItem(index, Trinity::StringTo<uint32>(items[index]).value_or(0)); SetRace(fields[7].GetUInt8()); diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 16f54b7c9a4..2cf5aaa47e2 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -38,53 +38,66 @@ GossipMenu::GossipMenu() _locale = DEFAULT_LOCALE; } -GossipMenu::~GossipMenu() -{ - ClearMenu(); -} +GossipMenu::~GossipMenu() = default; -uint32 GossipMenu::AddMenuItem(int32 menuItemId, GossipOptionNpc optionNpc, std::string const& message, uint32 sender, uint32 action, std::string const& boxMessage, uint32 boxMoney, bool coded /*= false*/) +uint32 GossipMenu::AddMenuItem(int32 gossipOptionId, int32 orderIndex, GossipOptionNpc optionNpc, std::string optionText, uint32 language, + GossipOptionFlags flags, Optional<int32> gossipNpcOptionId, bool boxCoded, uint32 boxMoney, std::string boxText, Optional<int32> spellId, + Optional<int32> overrideIconId, uint32 sender, uint32 action) { ASSERT(_menuItems.size() <= GOSSIP_MAX_MENU_ITEMS); // Find a free new id - script case - if (menuItemId == -1) + if (orderIndex == -1) { - menuItemId = 0; + orderIndex = 0; if (_menuId) { - // set baseline menuItemId as higher than whatever exists in db + // set baseline orderIndex as higher than whatever exists in db Trinity::IteratorPair bounds = sObjectMgr->GetGossipMenuItemsMapBounds(_menuId); auto itr = std::max_element(bounds.begin(), bounds.end(), [](GossipMenuItemsContainer::value_type const& a, GossipMenuItemsContainer::value_type const& b) { - return a.second.OptionID < b.second.OptionID; + return a.second.OrderIndex < b.second.OrderIndex; }); if (itr != bounds.end()) - menuItemId = itr->second.OptionID + 1; + orderIndex = itr->second.OrderIndex + 1; } if (!_menuItems.empty()) { for (GossipMenuItemContainer::const_iterator itr = _menuItems.begin(); itr != _menuItems.end(); ++itr) { - if (int32(itr->first) > menuItemId) + if (int32(itr->OrderIndex) > orderIndex) break; - menuItemId = itr->first + 1; + orderIndex = itr->OrderIndex + 1; } } } - GossipMenuItem& menuItem = _menuItems[menuItemId]; + if (!gossipOptionId) + gossipOptionId = -(int32(_menuId) * 100 + orderIndex); + + auto where = std::lower_bound(_menuItems.begin(), _menuItems.end(), orderIndex, [](GossipMenuItem const& item, int32 index) + { + return int32(item.OrderIndex) < index; + }); - menuItem.OptionNpc = optionNpc; - menuItem.Message = message; - menuItem.IsCoded = coded; - menuItem.Sender = sender; - menuItem.Action = action; - menuItem.BoxMessage = boxMessage; - menuItem.BoxMoney = boxMoney; - return menuItemId; + GossipMenuItem& menuItem = *_menuItems.emplace(where); + menuItem.GossipOptionID = gossipOptionId; + menuItem.OrderIndex = orderIndex; + menuItem.OptionNpc = optionNpc; + menuItem.OptionText = std::move(optionText); + menuItem.Language = language; + menuItem.Flags = flags; + menuItem.GossipNpcOptionID = gossipNpcOptionId; + menuItem.BoxCoded = boxCoded; + menuItem.BoxMoney = boxMoney; + menuItem.BoxText = std::move(boxText); + menuItem.SpellID = spellId; + menuItem.OverrideIconID = overrideIconId; + menuItem.Sender = sender; + menuItem.Action = action; + return orderIndex; } /** @@ -103,80 +116,117 @@ void GossipMenu::AddMenuItem(uint32 menuId, uint32 menuItemId, uint32 sender, ui /// Find the one with the given menu item id. auto itr = std::find_if(bounds.begin(), bounds.end(), [menuItemId](std::pair<uint32 const, GossipMenuItems> const& itemPair) { - return itemPair.second.OptionID == menuItemId; + return itemPair.second.OrderIndex == menuItemId; }); if (itr == bounds.end()) return; + AddMenuItem(itr->second, sender, action); +} + +void GossipMenu::AddMenuItem(GossipMenuItems const& menuItem, uint32 sender, uint32 action) +{ /// Store texts for localization. std::string strOptionText, strBoxText; - BroadcastTextEntry const* optionBroadcastText = sBroadcastTextStore.LookupEntry(itr->second.OptionBroadcastTextID); - BroadcastTextEntry const* boxBroadcastText = sBroadcastTextStore.LookupEntry(itr->second.BoxBroadcastTextID); + BroadcastTextEntry const* optionBroadcastText = sBroadcastTextStore.LookupEntry(menuItem.OptionBroadcastTextID); + BroadcastTextEntry const* boxBroadcastText = sBroadcastTextStore.LookupEntry(menuItem.BoxBroadcastTextID); /// OptionText if (optionBroadcastText) strOptionText = DB2Manager::GetBroadcastTextValue(optionBroadcastText, GetLocale()); else - strOptionText = itr->second.OptionText; + { + strOptionText = menuItem.OptionText; + + /// Find localizations from database. + if (GetLocale() != LOCALE_enUS) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(menuItem.MenuID, menuItem.OrderIndex)) + ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, GetLocale(), strBoxText); + } /// BoxText if (boxBroadcastText) strBoxText = DB2Manager::GetBroadcastTextValue(boxBroadcastText, GetLocale()); else - strBoxText = itr->second.BoxText; - - if (!boxBroadcastText) { + strBoxText = menuItem.BoxText; + /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(menuId, menuItemId)) - ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, GetLocale(), strBoxText); + if (GetLocale() != LOCALE_enUS) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(menuItem.MenuID, menuItem.OrderIndex)) + ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, GetLocale(), strBoxText); } - /// Add menu item with existing method. Menu item id -1 is also used in ADD_GOSSIP_ITEM macro. - AddMenuItem(itr->second.OptionID, itr->second.OptionNpc, strOptionText, sender, action, strBoxText, itr->second.BoxMoney, itr->second.BoxCoded); - AddGossipMenuItemData(itr->second.OptionID, itr->second.ActionMenuID, itr->second.ActionPoiID); + AddMenuItem(menuItem.GossipOptionID, menuItem.OrderIndex, menuItem.OptionNpc, std::move(strOptionText), menuItem.Language, menuItem.Flags, + menuItem.GossipNpcOptionID, menuItem.BoxCoded, menuItem.BoxMoney, std::move(strBoxText), menuItem.SpellID, menuItem.OverrideIconID, sender, action); + AddGossipMenuItemData(menuItem.OrderIndex, menuItem.ActionMenuID, menuItem.ActionPoiID); } void GossipMenu::AddGossipMenuItemData(uint32 menuItemId, uint32 gossipActionMenuId, uint32 gossipActionPoi) { - GossipMenuItemData& itemData = _menuItemData[menuItemId]; + GossipMenuItem& menuItem = _menuItems[menuItemId]; - itemData.GossipActionMenuId = gossipActionMenuId; - itemData.GossipActionPoi = gossipActionPoi; + menuItem.ActionMenuID = gossipActionMenuId; + menuItem.ActionPoiID = gossipActionPoi; } -uint32 GossipMenu::GetMenuItemSender(uint32 menuItemId) const +GossipMenuItem const* GossipMenu::GetItem(int32 gossipOptionId) const { - GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId); - if (itr == _menuItems.end()) - return 0; + auto itr = std::find_if(_menuItems.begin(), _menuItems.end(), [gossipOptionId](GossipMenuItem const& item) + { + return item.GossipOptionID == gossipOptionId; + }); - return itr->second.Sender; + if (itr != _menuItems.end()) + return &*itr; + + return nullptr; } -uint32 GossipMenu::GetMenuItemAction(uint32 menuItemId) const +GossipMenuItem const* GossipMenu::GetItemByIndex(uint32 orderIndex) const { - GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId); - if (itr == _menuItems.end()) - return 0; + auto itr = std::find_if(_menuItems.begin(), _menuItems.end(), [orderIndex](GossipMenuItem const& item) + { + return item.OrderIndex == orderIndex; + }); - return itr->second.Action; + if (itr != _menuItems.end()) + return &*itr; + + return nullptr; } -bool GossipMenu::IsMenuItemCoded(uint32 menuItemId) const +uint32 GossipMenu::GetMenuItemSender(uint32 orderIndex) const { - GossipMenuItemContainer::const_iterator itr = _menuItems.find(menuItemId); - if (itr == _menuItems.end()) - return false; + GossipMenuItem const* item = GetItemByIndex(orderIndex); + if (item) + return item->Sender; - return itr->second.IsCoded; + return 0; +} + +uint32 GossipMenu::GetMenuItemAction(uint32 orderIndex) const +{ + GossipMenuItem const* item = GetItemByIndex(orderIndex); + if (item) + return item->Action; + + return 0; +} + +bool GossipMenu::IsMenuItemCoded(uint32 orderIndex) const +{ + GossipMenuItem const* item = GetItemByIndex(orderIndex); + if (item) + return item->BoxCoded; + + return 0; } void GossipMenu::ClearMenu() { _menuItems.clear(); - _menuItemData.clear(); } PlayerMenu::PlayerMenu(WorldSession* session) : _session(session) @@ -185,10 +235,7 @@ PlayerMenu::PlayerMenu(WorldSession* session) : _session(session) _gossipMenu.SetLocale(_session->GetSessionDbLocaleIndex()); } -PlayerMenu::~PlayerMenu() -{ - ClearMenus(); -} +PlayerMenu::~PlayerMenu() = default; void PlayerMenu::ClearMenus() { @@ -210,25 +257,26 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID) if (NpcText const* text = sObjectMgr->GetNpcText(titleTextId)) packet.TextID = Trinity::Containers::SelectRandomWeightedContainerElement(text->Data, [](NpcTextData const& data) { return data.Probability; })->BroadcastTextID; - packet.GossipOptions.resize(_gossipMenu.GetMenuItems().size()); - uint32 count = 0; - for (GossipMenuItemContainer::const_iterator itr = _gossipMenu.GetMenuItems().begin(); itr != _gossipMenu.GetMenuItems().end(); ++itr) + packet.GossipOptions.reserve(_gossipMenu.GetMenuItems().size()); + for (GossipMenuItem const& item : _gossipMenu.GetMenuItems()) { - WorldPackets::NPC::ClientGossipOptions& opt = packet.GossipOptions[count]; - GossipMenuItem const& item = itr->second; - opt.ClientOption = itr->first; + WorldPackets::NPC::ClientGossipOptions& opt = packet.GossipOptions.emplace_back(); + opt.GossipOptionID = item.GossipOptionID; opt.OptionNPC = item.OptionNpc; - opt.OptionFlags = item.IsCoded; // makes pop up box password + opt.OptionFlags = item.BoxCoded; // makes pop up box password opt.OptionCost = item.BoxMoney; // money required to open menu, 2.0.3 opt.OptionLanguage = item.Language; - opt.Text = item.Message; // text for gossip item - opt.Confirm = item.BoxMessage; // accept text (related to money) pop up box, 2.0.3 + opt.Flags = item.Flags; + opt.OrderIndex = item.OrderIndex; + opt.Text = item.OptionText; // text for gossip item + opt.Confirm = item.BoxText; // accept text (related to money) pop up box, 2.0.3 opt.Status = GossipOptionStatus::Available; - ++count; + opt.SpellID = item.SpellID; + opt.OverrideIconID = item.OverrideIconID; } packet.GossipText.resize(_questMenu.GetMenuItemCount()); - count = 0; + uint32 count = 0; for (uint8 i = 0; i < _questMenu.GetMenuItemCount(); ++i) { QuestMenuItem const& item = _questMenu.GetItem(i); @@ -300,13 +348,10 @@ void PlayerMenu::SendPointOfInterest(uint32 id) const QuestMenu::QuestMenu() { - _questMenuItems.reserve(16); // can be set for max from most often sizes to speedup push_back and less memory use + _questMenuItems.reserve(4); // can be set for max from most often sizes to speedup push_back and less memory use } -QuestMenu::~QuestMenu() -{ - ClearMenu(); -} +QuestMenu::~QuestMenu() = default; void QuestMenu::AddMenuItem(uint32 QuestId, uint8 Icon) { @@ -408,6 +453,13 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU packet.PortraitTurnInName = quest->GetPortraitTurnInName(); LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex(); + std::transform(quest->GetConditionalQuestDescription().begin(), quest->GetConditionalQuestDescription().end(), std::back_inserter(packet.ConditionalDescriptionText), [localeConstant](QuestConditionalText const& text) + { + std::string_view content = text.Text[LOCALE_enUS]; + ObjectMgr::GetLocaleString(text.Text, localeConstant, content); + return WorldPackets::Quest::ConditionalQuestText{ text.PlayerConditionId, text.QuestgiverCreatureId, content }; + }); + if (localeConstant != LOCALE_enUS) { if (QuestTemplateLocale const* questTemplateLocale = sObjectMgr->GetQuestLocale(quest->GetQuestId())) @@ -435,6 +487,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU packet.DisplayPopup = displayPopup; packet.QuestFlags[0] = quest->GetFlags() & (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) ? ~QUEST_FLAGS_AUTO_ACCEPT : ~0); packet.QuestFlags[1] = quest->GetFlagsEx(); + packet.QuestFlags[2] = quest->GetFlagsEx2(); packet.SuggestedPartyMembers = quest->GetSuggestedPlayers(); // RewardSpell can teach multiple spells in trigger spell effects. But not all effects must be SPELL_EFFECT_LEARN_SPELL. See example spell 33950 @@ -492,6 +545,13 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI packet.PortraitTurnInName = quest->GetPortraitTurnInName(); LocaleConstant locale = _session->GetSessionDbLocaleIndex(); + std::transform(quest->GetConditionalOfferRewardText().begin(), quest->GetConditionalOfferRewardText().end(), std::back_inserter(packet.ConditionalRewardText), [locale](QuestConditionalText const& text) + { + std::string_view content = text.Text[LOCALE_enUS]; + ObjectMgr::GetLocaleString(text.Text, locale, content); + return WorldPackets::Quest::ConditionalQuestText{ text.PlayerConditionId, text.QuestgiverCreatureId, content }; + }); + if (locale != LOCALE_enUS) { if (QuestTemplateLocale const* questTemplateLocale = sObjectMgr->GetQuestLocale(quest->GetQuestId())) @@ -514,7 +574,10 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI // Is there a better way? what about game objects? if (Creature const* creature = ObjectAccessor::GetCreature(*_session->GetPlayer(), npcGUID)) + { + packet.QuestGiverCreatureID = creature->GetEntry(); offer.QuestGiverCreatureID = creature->GetCreatureTemplate()->Entry; + } offer.QuestID = quest->GetQuestId(); offer.AutoLaunched = autoLaunched; @@ -525,6 +588,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI offer.QuestFlags[0] = quest->GetFlags(); offer.QuestFlags[1] = quest->GetFlagsEx(); + offer.QuestFlags[2] = quest->GetFlagsEx2(); packet.PortraitTurnIn = quest->GetQuestTurnInPortrait(); packet.PortraitGiver = quest->GetQuestGiverPortrait(); @@ -553,6 +617,13 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU packet.CompletionText = quest->GetRequestItemsText(); LocaleConstant locale = _session->GetSessionDbLocaleIndex(); + std::transform(quest->GetConditionalRequestItemsText().begin(), quest->GetConditionalRequestItemsText().end(), std::back_inserter(packet.ConditionalCompletionText), [locale](QuestConditionalText const& text) + { + std::string_view content = text.Text[LOCALE_enUS]; + ObjectMgr::GetLocaleString(text.Text, locale, content); + return WorldPackets::Quest::ConditionalQuestText{ text.PlayerConditionId, text.QuestgiverCreatureId, content }; + }); + if (locale != LOCALE_enUS) { if (QuestTemplateLocale const* questTemplateLocale = sObjectMgr->GetQuestLocale(quest->GetQuestId())) @@ -583,6 +654,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU packet.QuestFlags[0] = quest->GetFlags(); packet.QuestFlags[1] = quest->GetFlagsEx(); + packet.QuestFlags[2] = quest->GetFlagsEx2(); packet.SuggestPartyMembers = quest->GetSuggestedPlayers(); // incomplete: FD diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index 5151bbdafdc..b4f0cd61136 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -20,11 +20,12 @@ #include "Common.h" #include "ObjectGuid.h" -#include <map> +#include "Optional.h" class Object; class Quest; class WorldSession; +struct GossipMenuItems; enum class QuestGiverStatus : uint32; #define GOSSIP_MAX_MENU_ITEMS 32 @@ -34,24 +35,24 @@ enum class GossipOptionNpc : uint8 { None = 0, // White chat bubble. Default Vendor = 1, // Brown bag - TaxiNode = 2, // White wing + Taxinode = 2, // White wing Trainer = 3, // Brown book SpiritHealer = 4, // Golden interaction wheel (with red center) Binder = 5, // Golden interaction wheel Banker = 6, // Brown bag (with gold coin in lower corner) PetitionVendor = 7, // White chat bubble (with "..." inside) TabardVendor = 8, // White tabard - BattleMaster = 9, // Two crossed swords + Battlemaster = 9, // Two crossed swords Auctioneer = 10, // Stack of gold coins TalentMaster = 11, // White chat bubble - StableMaster = 12, // White chat bubble + Stablemaster = 12, // White chat bubble PetSpecializationMaster = 13, /*DEPRECATED*/ // White chat bubble - GuildBanker = 14, /*NYI*/ // White chat bubble - SpellClick = 15, /*NYI*/ // White chat bubble + GuildBanker = 14, // White chat bubble + Spellclick = 15, // White chat bubble DisableXPGain = 16, // White chat bubble EnableXPGain = 17, // White chat bubble Mailbox = 18, // White chat bubble - WorldPVPQueue = 19, /*NYI*/ // White chat bubble + WorldPvPQueue = 19, /*NYI*/ // White chat bubble LFGDungeon = 20, /*NYI*/ // White chat bubble ArtifactRespec = 21, /*NYI*/ // White chat bubble CemeterySelect = 22, /*DEPRECATED*/ // White chat bubble @@ -59,25 +60,33 @@ enum class GossipOptionNpc : uint8 GlyphMaster = 24, /*DEPRECATED*/ // White chat bubble QueueScenario = 25, /*NYI*/ // White chat bubble GarrisonArchitect = 26, /*NYI*/ // White chat bubble - GarrisonMission = 27, /*NYI*/ // White chat bubble + GarrisonMissionNpc = 27, /*NYI*/ // White chat bubble ShipmentCrafter = 28, /*NYI*/ // Brown document - GarrisonTradeskill = 29, /*NYI*/ // White chat bubble + GarrisonTradeskillNpc = 29, /*NYI*/ // White chat bubble GarrisonRecruitment = 30, /*NYI*/ // White chat bubble AdventureMap = 31, /*NYI*/ // White chat bubble GarrisonTalent = 32, // White chat bubble ContributionCollector = 33, /*NYI*/ // White chat bubble Transmogrify = 34, // Purple helm AzeriteRespec = 35, // White chat bubble - IslandsMission = 36, /*NYI*/ // White chat bubble + IslandsMissionNpc = 36, /*NYI*/ // White chat bubble UIItemInteraction = 37, /*NYI*/ // White chat bubble WorldMap = 38, /*NYI*/ // White chat bubble Soulbind = 39, /*NYI*/ // White chat bubble - ChromieTime = 40, /*NYI*/ // White chat bubble - CovenantPreview = 41, /*NYI*/ // White chat bubble + ChromieTimeNpc = 40, /*NYI*/ // White chat bubble + CovenantPreviewNpc = 41, /*NYI*/ // White chat bubble RuneforgeLegendaryCrafting = 42, /*NYI*/ // White chat bubble NewPlayerGuide = 43, /*NYI*/ // White chat bubble RuneforgeLegendaryUpgrade = 44, /*NYI*/ // White chat bubble - CovenantRenown = 45, /*NYI*/ // White chat bubble + CovenantRenownNpc = 45, /*NYI*/ // White chat bubble + BlackMarketAuctionHouse = 46, + PerksProgramVendor = 47, + ProfessionsCraftingOrder = 48, + ProfessionsOpen = 49, + ProfessionsCustomerOrder = 50, + TraitSystem = 51, + BarbersChoice = 52, + MajorFactionRenown = 53, Count }; @@ -96,29 +105,38 @@ enum class GossipOptionRewardType : uint8 Currency = 1 }; -struct GossipMenuItem +enum class GossipOptionFlags : int32 { - GossipOptionNpc OptionNpc; - bool IsCoded; - std::string Message; - uint32 Sender; - uint32 Action; - std::string BoxMessage; - uint32 BoxMoney; - uint32 Language; + None = 0x0, + QuestLabelPrepend = 0x1 }; -// need an ordered container -typedef std::map<uint32, GossipMenuItem> GossipMenuItemContainer; - -struct GossipMenuItemData +struct GossipMenuItem { - uint32 GossipActionMenuId; // MenuId of the gossip triggered by this action - uint32 GossipActionPoi; + int32 GossipOptionID; + uint32 OrderIndex; + GossipOptionNpc OptionNpc; + std::string OptionText; + uint32 Language; + GossipOptionFlags Flags; + Optional<int32> GossipNpcOptionID; + bool BoxCoded; + uint32 BoxMoney; + std::string BoxText; + Optional<int32> SpellID; + Optional<int32> OverrideIconID; + + // action data + uint32 ActionMenuID; + uint32 ActionPoiID; + + // additional scripting identifiers + uint32 Sender; + uint32 Action; }; // need an ordered container -typedef std::map<uint32, GossipMenuItemData> GossipMenuItemDataContainer; +typedef std::vector<GossipMenuItem> GossipMenuItemContainer; struct QuestMenuItem { @@ -132,10 +150,17 @@ class TC_GAME_API GossipMenu { public: GossipMenu(); + GossipMenu(GossipMenu const&) = delete; + GossipMenu(GossipMenu&&) = delete; + GossipMenu& operator=(GossipMenu const&) = delete; + GossipMenu& operator=(GossipMenu&&) = delete; ~GossipMenu(); - uint32 AddMenuItem(int32 menuItemId, GossipOptionNpc optionNpc, std::string const& message, uint32 sender, uint32 action, std::string const& boxMessage, uint32 boxMoney, bool coded = false); + uint32 AddMenuItem(int32 gossipOptionId, int32 orderIndex, GossipOptionNpc optionNpc, std::string optionText, uint32 language, GossipOptionFlags flags, + Optional<int32> gossipNpcOptionId, bool boxCoded, uint32 boxMoney, std::string boxText, Optional<int32> spellId, + Optional<int32> overrideIconId, uint32 sender, uint32 action); void AddMenuItem(uint32 menuId, uint32 menuItemId, uint32 sender, uint32 action); + void AddMenuItem(GossipMenuItems const& menuItem, uint32 sender, uint32 action); void SetMenuId(uint32 menu_id) { _menuId = menu_id; } uint32 GetMenuId() const { return _menuId; } @@ -154,27 +179,12 @@ class TC_GAME_API GossipMenu return _menuItems.empty(); } - GossipMenuItem const* GetItem(uint32 id) const - { - GossipMenuItemContainer::const_iterator itr = _menuItems.find(id); - if (itr != _menuItems.end()) - return &itr->second; - - return nullptr; - } - - GossipMenuItemData const* GetItemData(uint32 indexId) const - { - GossipMenuItemDataContainer::const_iterator itr = _menuItemData.find(indexId); - if (itr != _menuItemData.end()) - return &itr->second; - - return nullptr; - } + GossipMenuItem const* GetItem(int32 gossipOptionId) const; + GossipMenuItem const* GetItemByIndex(uint32 orderIndex) const; - uint32 GetMenuItemSender(uint32 menuItemId) const; - uint32 GetMenuItemAction(uint32 menuItemId) const; - bool IsMenuItemCoded(uint32 menuItemId) const; + uint32 GetMenuItemSender(uint32 orderIndex) const; + uint32 GetMenuItemAction(uint32 orderIndex) const; + bool IsMenuItemCoded(uint32 orderIndex) const; void ClearMenu(); @@ -185,7 +195,6 @@ class TC_GAME_API GossipMenu private: GossipMenuItemContainer _menuItems; - GossipMenuItemDataContainer _menuItemData; uint32 _menuId; LocaleConstant _locale; }; @@ -194,6 +203,10 @@ class TC_GAME_API QuestMenu { public: QuestMenu(); + QuestMenu(QuestMenu const&) = delete; + QuestMenu(QuestMenu&&) = delete; + QuestMenu& operator=(QuestMenu const&) = delete; + QuestMenu& operator=(QuestMenu&&) = delete; ~QuestMenu(); void AddMenuItem(uint32 QuestId, uint8 Icon); @@ -210,8 +223,6 @@ class TC_GAME_API QuestMenu class InteractionData { public: - InteractionData() { Reset(); } - void Reset() { SourceGuid.Clear(); @@ -220,14 +231,18 @@ class InteractionData } ObjectGuid SourceGuid; - uint32 TrainerId; - uint32 PlayerChoiceId; + uint32 TrainerId = 0; + uint32 PlayerChoiceId = 0; }; class TC_GAME_API PlayerMenu { public: explicit PlayerMenu(WorldSession* session); + PlayerMenu(PlayerMenu const&) = delete; + PlayerMenu(PlayerMenu&&) = delete; + PlayerMenu& operator=(PlayerMenu const&) = delete; + PlayerMenu& operator=(PlayerMenu&&) = delete; ~PlayerMenu(); GossipMenu& GetGossipMenu() { return _gossipMenu; } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 70e088a23ea..8b3946d22c5 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2927,8 +2927,9 @@ void GameObject::Use(Unit* user) if (!item) return; - WorldPackets::Azerite::OpenHeartForge openHeartForge; - openHeartForge.ForgeGUID = GetGUID(); + WorldPackets::GameObject::GameObjectInteraction openHeartForge; + openHeartForge.ObjectGUID = GetGUID(); + openHeartForge.InteractionType = PlayerInteractionType::AzeriteForge; player->SendDirectMessage(openHeartForge.Write()); break; } @@ -2943,9 +2944,25 @@ void GameObject::Use(Unit* user) if (!player) return; - WorldPackets::GameObject::GameObjectUILink gameObjectUILink; + WorldPackets::GameObject::GameObjectInteraction gameObjectUILink; gameObjectUILink.ObjectGUID = GetGUID(); - gameObjectUILink.UILink = GetGOInfo()->UILink.UILinkType; + switch (GetGOInfo()->UILink.UILinkType) + { + case 0: + gameObjectUILink.InteractionType = PlayerInteractionType::AdventureJournal; + break; + case 1: + gameObjectUILink.InteractionType = PlayerInteractionType::ObliterumForge; + break; + case 2: + gameObjectUILink.InteractionType = PlayerInteractionType::ScrappingMachine; + break; + case 3: + gameObjectUILink.InteractionType = PlayerInteractionType::ItemInteraction; + break; + default: + break; + } player->SendDirectMessage(gameObjectUILink.Write()); return; } diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 8521e460cd6..0e08bb26fea 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -40,7 +40,7 @@ struct GameObjectTemplate int32 ContentTuningId; union { - // 0 GAMEOBJECT_TYPE_DOOR + // 0 GAMEOBJECT_TYPE_DOOR struct { uint32 startOpen; // 0 startOpen, enum { false, true, }; Default: false @@ -56,6 +56,7 @@ struct GameObjectTemplate uint32 InfiniteAOI; // 10 Infinite AOI, enum { false, true, }; Default: false uint32 NotLOSBlocking; // 11 Not LOS Blocking, enum { false, true, }; Default: false uint32 InteractRadiusOverride; // 12 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0 + uint32 Collisionupdatedelayafteropen; // 13 Collision update delay(ms) after open, int, Min value: 0, Max value: 2147483647, Default value: 0 } door; // 1 GAMEOBJECT_TYPE_BUTTON struct @@ -196,6 +197,13 @@ struct GameObjectTemplate uint32 floatOnWater; // 7 floatOnWater, enum { false, true, }; Default: false uint32 conditionID1; // 8 conditionID1, References: PlayerCondition, NoValue = 0 uint32 InteractRadiusOverride; // 9 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0 + uint32 gossipID; // 10 gossipID, References: Gossip, NoValue = 0 + uint32 spellFocusType2; // 11 spellFocusType 2, References: SpellFocusObject, NoValue = 0 + uint32 spellFocusType3; // 12 spellFocusType 3, References: SpellFocusObject, NoValue = 0 + uint32 spellFocusType4; // 13 spellFocusType 4, References: SpellFocusObject, NoValue = 0 + uint32 Profession; // 14 Profession, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing + uint32 Profession2; // 15 Profession 2, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing + uint32 Profession3; // 16 Profession 3, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing } spellFocus; // 9 GAMEOBJECT_TYPE_TEXT struct @@ -483,7 +491,7 @@ struct GameObjectTemplate // 31 GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY struct { - uint32 InstanceType; // 0 Instance Type, enum { Not Instanced, Party Dungeon, Raid Dungeon, PVP Battlefield, Arena Battlefield, Scenario, }; Default: Party Dungeon + uint32 InstanceType; // 0 Instance Type, enum { Not Instanced, Party Dungeon, Raid Dungeon, PVP Battlefield, Arena Battlefield, Scenario, WoWLabs, }; Default: Party Dungeon uint32 DifficultyNormal; // 1 Difficulty Normal, References: animationdata, NoValue = 0 uint32 DifficultyHeroic; // 2 Difficulty Heroic, References: animationdata, NoValue = 0 uint32 DifficultyEpic; // 3 Difficulty Epic, References: animationdata, NoValue = 0 @@ -503,6 +511,7 @@ struct GameObjectTemplate int32 HeightOffset; // 1 Height Offset (inches), int, Min value: -100, Max value: 100, Default value: 0 uint32 SitAnimKit; // 2 Sit Anim Kit, References: AnimKit, NoValue = 0 uint32 InteractRadiusOverride; // 3 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0 + uint32 CustomizationScope; // 4 Customization Scope, int, Min value: 0, Max value: 2147483647, Default value: 0 } barberChair; // 33 GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING struct @@ -794,6 +803,7 @@ struct GameObjectTemplate uint32 WhenAvailable; // 0 When Available, References: GameObjectDisplayInfo, NoValue = 0 uint32 open; // 1 open, References: Lock_, NoValue = 0 uint32 InteractRadiusOverride; // 2 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0 + uint32 ExpansionLevel; // 3 Expansion Level, int, Min value: 0, Max value: 2147483647, Default value: 0 } weeklyRewardChest; // 60 GAMEOBJECT_TYPE_CLIENT_MODEL struct @@ -803,6 +813,11 @@ struct GameObjectTemplate uint32 InfiniteAOI; // 2 Infinite AOI, enum { false, true, }; Default: false uint32 TrueInfiniteAOI; // 3 True Infinite AOI (programmer only!), enum { false, true, }; Default: false } clientModel; + // 61 GAMEOBJECT_TYPE_CRAFTING_TABLE + struct + { + uint32 Profession; // 0 Profession, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing + } craftingTable; struct { uint32 data[MAX_GAMEOBJECT_DATA]; diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteEmpoweredItem.cpp b/src/server/game/Entities/Item/AzeriteItem/AzeriteEmpoweredItem.cpp index 552e5075603..36a01947955 100644 --- a/src/server/game/Entities/Item/AzeriteItem/AzeriteEmpoweredItem.cpp +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteEmpoweredItem.cpp @@ -142,7 +142,7 @@ void AzeriteEmpoweredItem::ClearSelectedAzeritePowers() SetUpdateFieldValue(m_values.ModifyValue(&AzeriteEmpoweredItem::m_azeriteEmpoweredItemData).ModifyValue(&UF::AzeriteEmpoweredItemData::Selections, i), 0); _bonusData.Initialize(GetTemplate()); - for (int32 bonusListID : *m_itemData->BonusListIDs) + for (int32 bonusListID : GetBonusListIDs()) _bonusData.AddBonusList(bonusListID); } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 96399f9c00f..3a2e55bb412 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -256,6 +256,8 @@ bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto) if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_COOKING_SUPP)) return false; return true; + case ITEM_SUBCLASS_REAGENT_CONTAINER: + return pProto->IsCraftingReagent(); default: return false; } @@ -610,7 +612,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans) stmt->setUInt8(++index, uint8(m_itemData->Context)); std::ostringstream bonusListIDs; - for (int32 bonusListID : *m_itemData->BonusListIDs) + for (int32 bonusListID : GetBonusListIDs()) bonusListIDs << bonusListID << ' '; stmt->setString(++index, bonusListIDs.str()); @@ -1240,7 +1242,8 @@ uint8 Item::GetBagSlot() const bool Item::IsEquipped() const { - return !IsInBag() && m_slot < EQUIPMENT_SLOT_END; + return !IsInBag() && ((m_slot >= EQUIPMENT_SLOT_START && m_slot < EQUIPMENT_SLOT_END) + || (m_slot >= PROFESSION_SLOT_START && m_slot < PROFESSION_SLOT_END)); } bool Item::CanBeTraded(bool mail, bool trade) const @@ -2043,6 +2046,12 @@ int32 const ItemTransmogrificationSlots[MAX_INVTYPE] = EQUIPMENT_SLOT_MAINHAND, // INVTYPE_RANGEDRIGHT -1, // INVTYPE_QUIVER -1 // INVTYPE_RELIC + -1, // INVTYPE_PROFESSION_TOOL + -1, // INVTYPE_PROFESSION_GEAR + -1, // INVTYPE_EQUIPABLE_SPELL_OFFENSIVE + -1, // INVTYPE_EQUIPABLE_SPELL_UTILITY + -1, // INVTYPE_EQUIPABLE_SPELL_DEFENSIVE + -1 // INVTYPE_EQUIPABLE_SPELL_MOBILITY }; bool Item::CanTransmogrifyItemWithItem(Item const* item, ItemModifiedAppearanceEntry const* itemModifiedAppearance) @@ -2501,14 +2510,16 @@ uint16 Item::GetVisibleItemVisual(Player const* owner) const void Item::AddBonuses(uint32 bonusListID) { - if (std::find(m_itemData->BonusListIDs->begin(), m_itemData->BonusListIDs->end(), int32(bonusListID)) != m_itemData->BonusListIDs->end()) + if (std::find(GetBonusListIDs().begin(), GetBonusListIDs().end(), int32(bonusListID)) != GetBonusListIDs().end()) return; if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListID)) { - std::vector<int32> bonusListIDs = m_itemData->BonusListIDs; - bonusListIDs.push_back(bonusListID); - SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::BonusListIDs), std::move(bonusListIDs)); + WorldPackets::Item::ItemBonusKey itemBonusKey; + itemBonusKey.ItemID = GetEntry(); + itemBonusKey.BonusListIDs = GetBonusListIDs(); + itemBonusKey.BonusListIDs.push_back(bonusListID); + SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemBonusKey), std::move(itemBonusKey)); for (ItemBonusEntry const* bonus : *bonuses) _bonusData.AddBonus(bonus->Type, bonus->Value); SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemAppearanceModID), _bonusData.AppearanceModID); @@ -2517,9 +2528,12 @@ void Item::AddBonuses(uint32 bonusListID) void Item::SetBonuses(std::vector<int32> bonusListIDs) { - SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::BonusListIDs), std::move(bonusListIDs)); + WorldPackets::Item::ItemBonusKey itemBonusKey; + itemBonusKey.ItemID = GetEntry(); + itemBonusKey.BonusListIDs = std::move(bonusListIDs); + SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemBonusKey), std::move(itemBonusKey)); - for (int32 bonusListID : *m_itemData->BonusListIDs) + for (int32 bonusListID : GetBonusListIDs()) _bonusData.AddBonusList(bonusListID); SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemAppearanceModID), _bonusData.AppearanceModID); @@ -2527,7 +2541,9 @@ void Item::SetBonuses(std::vector<int32> bonusListIDs) void Item::ClearBonuses() { - SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::BonusListIDs), std::vector<int32>()); + WorldPackets::Item::ItemBonusKey itemBonusKey; + itemBonusKey.ItemID = GetEntry(); + SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemBonusKey), std::move(itemBonusKey)); _bonusData.Initialize(GetTemplate()); SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::ItemAppearanceModID), _bonusData.AppearanceModID); } diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 6a778e0fe65..565c51fd34f 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -226,6 +226,7 @@ class TC_GAME_API Item : public Object void CheckArtifactRelicSlotUnlock(Player const* owner); void AddBonuses(uint32 bonusListID); + std::vector<int32> const& GetBonusListIDs() const { return m_itemData->ItemBonusKey->BonusListIDs; } void SetBonuses(std::vector<int32> bonusListIDs); void ClearBonuses(); diff --git a/src/server/game/Entities/Item/ItemDefines.h b/src/server/game/Entities/Item/ItemDefines.h index d3b65653d1f..318b78c8d00 100644 --- a/src/server/game/Entities/Item/ItemDefines.h +++ b/src/server/game/Entities/Item/ItemDefines.h @@ -136,6 +136,11 @@ enum InventoryResult : uint8 EQUIP_ERR_NOT_IN_NPE = 110,// Not available during the tutorial EQUIP_ERR_ITEM_COOLDOWN = 111,// Item is not ready yet. EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND = 112,// You can't do that in a rated battleground. + EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL = 113, + EQUIP_ERR_CANT_BE_RECRAFTED = 114,// You can't recraft that itemv + EQUIP_ERR_REAGENTBAG_WRONG_SLOT = 115,// Reagent Bags can only be placed in the reagent bag slot. + EQUIP_ERR_SLOT_ONLY_REAGENTBAG = 116,// Only Reagent Bags can be placed in the reagent bag slot. + EQUIP_ERR_REAGENTBAG_ITEM_TYPE = 117,// Only Reagents can be placed in Reagent Bags. }; // EnumUtils: DESCRIBE THIS diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index d2fa2029fa8..842dbe2f4bb 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -402,10 +402,16 @@ enum InventoryType : uint8 INVTYPE_THROWN = 25, INVTYPE_RANGEDRIGHT = 26, INVTYPE_QUIVER = 27, - INVTYPE_RELIC = 28 + INVTYPE_RELIC = 28, + INVTYPE_PROFESSION_TOOL = 29, + INVTYPE_PROFESSION_GEAR = 30, + INVTYPE_EQUIPABLE_SPELL_OFFENSIVE = 31, + INVTYPE_EQUIPABLE_SPELL_UTILITY = 32, + INVTYPE_EQUIPABLE_SPELL_DEFENSIVE = 33, + INVTYPE_EQUIPABLE_SPELL_MOBILITY = 34 }; -#define MAX_INVTYPE 29 +#define MAX_INVTYPE 35 enum ItemClass : uint8 { @@ -427,10 +433,11 @@ enum ItemClass : uint8 ITEM_CLASS_MISCELLANEOUS = 15, ITEM_CLASS_GLYPH = 16, ITEM_CLASS_BATTLE_PETS = 17, - ITEM_CLASS_WOW_TOKEN = 18 + ITEM_CLASS_WOW_TOKEN = 18, + ITEM_CLASS_PROFESSION = 19 }; -#define MAX_ITEM_CLASS 19 +#define MAX_ITEM_CLASS 20 enum ItemSubclassConsumable { @@ -460,10 +467,11 @@ enum ItemSubclassContainer ITEM_SUBCLASS_LEATHERWORKING_CONTAINER = 7, ITEM_SUBCLASS_INSCRIPTION_CONTAINER = 8, ITEM_SUBCLASS_TACKLE_CONTAINER = 9, - ITEM_SUBCLASS_COOKING_CONTAINER = 10 + ITEM_SUBCLASS_COOKING_CONTAINER = 10, + ITEM_SUBCLASS_REAGENT_CONTAINER = 11 }; -#define MAX_ITEM_SUBCLASS_CONTAINER 11 +#define MAX_ITEM_SUBCLASS_CONTAINER 12 enum ItemSubclassWeapon { @@ -535,10 +543,11 @@ enum ItemSubclassArmor enum ItemSubclassReagent { ITEM_SUBCLASS_REAGENT = 0, - ITEM_SUBCLASS_KEYSTONE = 1 + ITEM_SUBCLASS_KEYSTONE = 1, + ITEM_SUBCLASS_CONTEXT_TOKEN = 2 }; -#define MAX_ITEM_SUBCLASS_REAGENT 2 +#define MAX_ITEM_SUBCLASS_REAGENT 3 enum ItemSubclassProjectile { @@ -570,10 +579,12 @@ enum ItemSubclassTradeGoods ITEM_SUBCLASS_ENCHANTMENT = 14, ITEM_SUBCLASS_WEAPON_ENCHANTMENT = 15, ITEM_SUBCLASS_INSCRIPTION = 16, - ITEM_SUBCLASS_EXPLOSIVES_DEVICES = 17 + ITEM_SUBCLASS_EXPLOSIVES_DEVICES = 17, + ITEM_SUBCLASS_OPTIONAL_REAGENT = 18, + ITEM_SUBCLASS_FINISHING_REAGENT = 19, }; -#define MAX_ITEM_SUBCLASS_TRADE_GOODS 18 +#define MAX_ITEM_SUBCLASS_TRADE_GOODS 20 enum ItemSubclassItemEnhancement { @@ -590,10 +601,11 @@ enum ItemSubclassItemEnhancement ITEM_SUBCLASS_ITEM_ENHANCEMENT_FINGER = 10, ITEM_SUBCLASS_ITEM_ENHANCEMENT_WEAPON = 11, ITEM_SUBCLASS_ITEM_ENHANCEMENT_TWO_HANDED_WEAPON = 12, - ITEM_SUBCLASS_ITEM_ENHANCEMENT_SHIELD_OFF_HAND = 13 + ITEM_SUBCLASS_ITEM_ENHANCEMENT_SHIELD_OFF_HAND = 13, + ITEM_SUBCLASS_ITEM_ENHANCEMENT_MISC = 14 }; -#define MAX_ITEM_SUBCLASS_ITEM_ENHANCEMENT 14 +#define MAX_ITEM_SUBCLASS_ITEM_ENHANCEMENT 15 enum ItemSubclassRecipe { @@ -662,9 +674,10 @@ enum ItemSubclassJunk ITEM_SUBCLASS_MISCELLANEOUS_HOLIDAY = 3, ITEM_SUBCLASS_MISCELLANEOUS_OTHER = 4, ITEM_SUBCLASS_MISCELLANEOUS_MOUNT = 5, + ITEM_SUBCLASS_MISCELLANEOUS_MOUNT_EQUIPMENT = 6 }; -#define MAX_ITEM_SUBCLASS_MISCELLANEOUS 6 +#define MAX_ITEM_SUBCLASS_MISCELLANEOUS 7 enum ItemSubclassGlyph { @@ -698,6 +711,26 @@ enum ItemSubclassWowToken #define MAX_ITEM_SUBCLASS_WOW_TOKEN 1 +enum ItemSubclassPorfession +{ + ITEM_SUBCLASS_PROFESSION_BLACKSMITHING = 0, + ITEM_SUBCLASS_PROFESSION_LEATHERWORKING = 1, + ITEM_SUBCLASS_PROFESSION_ALCHEMY = 2, + ITEM_SUBCLASS_PROFESSION_HERBALISM = 3, + ITEM_SUBCLASS_PROFESSION_COOKING = 4, + ITEM_SUBCLASS_PROFESSION_MINING = 5, + ITEM_SUBCLASS_PROFESSION_TAILORING = 6, + ITEM_SUBCLASS_PROFESSION_ENGINEERING = 7, + ITEM_SUBCLASS_PROFESSION_ENCHANTING = 8, + ITEM_SUBCLASS_PROFESSION_FISHING = 9, + ITEM_SUBCLASS_PROFESSION_SKINNING = 10, + ITEM_SUBCLASS_PROFESSION_JEWELCRAFTING = 11, + ITEM_SUBCLASS_PROFESSION_INSCRIPTION = 12, + ITEM_SUBCLASS_PROFESSION_ARCHAEOLOGY = 13 +}; + +#define MAX_ITEM_SUBCLASS_PROFESSION 14 + const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] = { MAX_ITEM_SUBCLASS_CONSUMABLE, @@ -718,7 +751,8 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] = MAX_ITEM_SUBCLASS_MISCELLANEOUS, MAX_ITEM_SUBCLASS_GLYPH, MAX_ITEM_SUBCLASS_BATTLE_PET, - MAX_ITEM_SUBCLASS_WOW_TOKEN + MAX_ITEM_SUBCLASS_WOW_TOKEN, + MAX_ITEM_SUBCLASS_PROFESSION }; #define MAX_ITEM_SUBCLASS_TOTAL 21 diff --git a/src/server/game/Entities/Item/enuminfo_ItemDefines.cpp b/src/server/game/Entities/Item/enuminfo_ItemDefines.cpp index e52b1abcc88..d186091229b 100644 --- a/src/server/game/Entities/Item/enuminfo_ItemDefines.cpp +++ b/src/server/game/Entities/Item/enuminfo_ItemDefines.cpp @@ -144,12 +144,17 @@ TC_API_EXPORT EnumText EnumUtils<InventoryResult>::ToString(InventoryResult valu case EQUIP_ERR_NOT_IN_NPE: return { "EQUIP_ERR_NOT_IN_NPE", "EQUIP_ERR_NOT_IN_NPE", "Not available during the tutorial" }; case EQUIP_ERR_ITEM_COOLDOWN: return { "EQUIP_ERR_ITEM_COOLDOWN", "EQUIP_ERR_ITEM_COOLDOWN", "Item is not ready yet." }; case EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND: return { "EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND", "EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND", "You can't do that in a rated battleground." }; + case EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL: return { "EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL", "EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL", "" }; + case EQUIP_ERR_CANT_BE_RECRAFTED: return { "EQUIP_ERR_CANT_BE_RECRAFTED", "EQUIP_ERR_CANT_BE_RECRAFTED", "You can't recraft that itemv" }; + case EQUIP_ERR_REAGENTBAG_WRONG_SLOT: return { "EQUIP_ERR_REAGENTBAG_WRONG_SLOT", "EQUIP_ERR_REAGENTBAG_WRONG_SLOT", "Reagent Bags can only be placed in the reagent bag slot." }; + case EQUIP_ERR_SLOT_ONLY_REAGENTBAG: return { "EQUIP_ERR_SLOT_ONLY_REAGENTBAG", "EQUIP_ERR_SLOT_ONLY_REAGENTBAG", "Only Reagent Bags can be placed in the reagent bag slot." }; + case EQUIP_ERR_REAGENTBAG_ITEM_TYPE: return { "EQUIP_ERR_REAGENTBAG_ITEM_TYPE", "EQUIP_ERR_REAGENTBAG_ITEM_TYPE", "Only Reagents can be placed in Reagent Bags." }; default: throw std::out_of_range("value"); } } template <> -TC_API_EXPORT size_t EnumUtils<InventoryResult>::Count() { return 113; } +TC_API_EXPORT size_t EnumUtils<InventoryResult>::Count() { return 118; } template <> TC_API_EXPORT InventoryResult EnumUtils<InventoryResult>::FromIndex(size_t index) @@ -269,6 +274,11 @@ TC_API_EXPORT InventoryResult EnumUtils<InventoryResult>::FromIndex(size_t index case 110: return EQUIP_ERR_NOT_IN_NPE; case 111: return EQUIP_ERR_ITEM_COOLDOWN; case 112: return EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND; + case 113: return EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL; + case 114: return EQUIP_ERR_CANT_BE_RECRAFTED; + case 115: return EQUIP_ERR_REAGENTBAG_WRONG_SLOT; + case 116: return EQUIP_ERR_SLOT_ONLY_REAGENTBAG; + case 117: return EQUIP_ERR_REAGENTBAG_ITEM_TYPE; default: throw std::out_of_range("index"); } } @@ -391,6 +401,11 @@ TC_API_EXPORT size_t EnumUtils<InventoryResult>::ToIndex(InventoryResult value) case EQUIP_ERR_NOT_IN_NPE: return 110; case EQUIP_ERR_ITEM_COOLDOWN: return 111; case EQUIP_ERR_NOT_IN_RATED_BATTLEGROUND: return 112; + case EQUIP_ERR_EQUIPABLESPELLS_SLOTS_FULL: return 113; + case EQUIP_ERR_CANT_BE_RECRAFTED: return 114; + case EQUIP_ERR_REAGENTBAG_WRONG_SLOT: return 115; + case EQUIP_ERR_SLOT_ONLY_REAGENTBAG: return 116; + case EQUIP_ERR_REAGENTBAG_ITEM_TYPE: return 117; default: throw std::out_of_range("value"); } } diff --git a/src/server/game/Entities/Object/MovementInfo.h b/src/server/game/Entities/Object/MovementInfo.h index 15b4af8ebfa..9e8c3909b36 100644 --- a/src/server/game/Entities/Object/MovementInfo.h +++ b/src/server/game/Entities/Object/MovementInfo.h @@ -60,9 +60,9 @@ struct MovementInfo struct Inertia { - Inertia() : lifetime(0) { } + Inertia() : id(0), lifetime(0) { } - ObjectGuid guid; + int32 id; Position force; uint32 lifetime; }; @@ -86,6 +86,15 @@ struct MovementInfo float stepUpStartElevation; + // advflying + struct AdvFlying + { + float forwardVelocity; + float upVelocity; + }; + + Optional<AdvFlying> advFlying; + MovementInfo() : flags(0), flags2(0), flags3(0), time(0), pitch(0.0f), stepUpStartElevation(0.0f) { diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 1059e2d7686..cca7c5fe890 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -293,6 +293,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe bool HasFall = HasFallDirection || unit->m_movementInfo.jump.fallTime != 0; bool HasSpline = unit->IsSplineEnabled(); bool HasInertia = unit->m_movementInfo.inertia.has_value(); + bool HasAdvFlying = unit->m_movementInfo.advFlying.has_value(); *data << GetGUID(); // MoverGUID @@ -321,17 +322,24 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe data->WriteBit(false); // HeightChangeFailed data->WriteBit(false); // RemoteTimeValid data->WriteBit(HasInertia); // HasInertia + data->WriteBit(HasAdvFlying); // HasAdvFlying if (!unit->m_movementInfo.transport.guid.IsEmpty()) *data << unit->m_movementInfo.transport; if (HasInertia) { - *data << unit->m_movementInfo.inertia->guid; + *data << unit->m_movementInfo.inertia->id; *data << unit->m_movementInfo.inertia->force.PositionXYZStream(); *data << uint32(unit->m_movementInfo.inertia->lifetime); } + if (HasAdvFlying) + { + *data << float(unit->m_movementInfo.advFlying->forwardVelocity); + *data << float(unit->m_movementInfo.advFlying->upVelocity); + } + if (HasFall) { *data << uint32(unit->m_movementInfo.jump.fallTime); // Time @@ -366,6 +374,24 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe *data << float(1.0f); // MovementForcesModMagnitude } + *data << float(2.0f); // advFlyingAirFriction + *data << float(65.0f); // advFlyingMaxVel + *data << float(1.0f); // advFlyingLiftCoefficient + *data << float(3.0f); // advFlyingDoubleJumpVelMod + *data << float(10.0f); // advFlyingGlideStartMinHeight + *data << float(100.0f); // advFlyingAddImpulseMaxSpeed + *data << float(90.0f); // advFlyingMinBankingRate + *data << float(140.0f); // advFlyingMaxBankingRate + *data << float(180.0f); // advFlyingMinPitchingRateDown + *data << float(360.0f); // advFlyingMaxPitchingRateDown + *data << float(90.0f); // advFlyingMinPitchingRateUp + *data << float(270.0f); // advFlyingMaxPitchingRateUp + *data << float(30.0f); // advFlyingMinTurnVelocityThreshold + *data << float(80.0f); // advFlyingMaxTurnVelocityThreshold + *data << float(2.75f); // advFlyingSurfaceFriction + *data << float(7.0f); // advFlyingOverMaxDeceleration + *data << float(0.4f); // advFlyingLaunchSpeedCoefficient + data->WriteBit(HasSpline); data->FlushBits(); @@ -438,6 +464,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe bool hasFaceMovementDir = areaTriggerTemplate && areaTrigger->GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_FACE_MOVEMENT_DIR); bool hasFollowsTerrain = areaTriggerTemplate && areaTrigger->GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_FOLLOWS_TERRAIN); bool hasUnk1 = areaTriggerTemplate && areaTrigger->GetTemplate()->HasFlag(AREATRIGGER_FLAG_UNK1); + bool hasUnk2 = false; bool hasTargetRollPitchYaw = areaTriggerTemplate && areaTrigger->GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_TARGET_ROLL_PITCH_YAW); bool hasScaleCurveID = createProperties && createProperties->ScaleCurveId != 0; bool hasMorphCurveID = createProperties && createProperties->MorphCurveId != 0; @@ -448,6 +475,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe bool hasAreaTriggerPolygon = createProperties && shape.IsPolygon(); bool hasAreaTriggerCylinder = shape.IsCylinder(); bool hasDisk = shape.IsDisk(); + bool hasBoundedPlane = shape.IsBoudedPlane(); bool hasAreaTriggerSpline = areaTrigger->HasSplines(); bool hasOrbit = areaTrigger->HasOrbit(); bool hasMovementScript = false; @@ -458,6 +486,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe data->WriteBit(hasFaceMovementDir); data->WriteBit(hasFollowsTerrain); data->WriteBit(hasUnk1); + data->WriteBit(hasUnk2); data->WriteBit(hasTargetRollPitchYaw); data->WriteBit(hasScaleCurveID); data->WriteBit(hasMorphCurveID); @@ -468,6 +497,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe data->WriteBit(hasAreaTriggerPolygon); data->WriteBit(hasAreaTriggerCylinder); data->WriteBit(hasDisk); + data->WriteBit(hasBoundedPlane); data->WriteBit(hasAreaTriggerSpline); data->WriteBit(hasOrbit); data->WriteBit(hasMovementScript); @@ -549,6 +579,14 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe *data << float(shape.DiskDatas.LocationZOffsetTarget); } + if (hasBoundedPlane) + { + *data << float(shape.BoundedPlaneDatas.Extents[0]); + *data << float(shape.BoundedPlaneDatas.Extents[1]); + *data << float(shape.BoundedPlaneDatas.ExtentsTarget[0]); + *data << float(shape.BoundedPlaneDatas.ExtentsTarget[1]); + } + //if (hasMovementScript) // *data << *areaTrigger->GetMovementScript(); // AreaTriggerMovementScriptInfo @@ -2300,10 +2338,10 @@ int32 WorldObject::ModSpellDuration(SpellInfo const* spellInfo, WorldObject cons if (!positive) { - int32 mechanicMask = spellInfo->GetSpellMechanicMaskByEffectMask(effectMask); + uint64 mechanicMask = spellInfo->GetSpellMechanicMaskByEffectMask(effectMask); auto mechanicCheck = [mechanicMask](AuraEffect const* aurEff) -> bool { - if (mechanicMask & (1 << aurEff->GetMiscValue())) + if (mechanicMask & (UI64LIT(1) << aurEff->GetMiscValue())) return true; return false; }; diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index c38670e91ff..1b7632da868 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -268,11 +268,6 @@ void SocketedGem::ClearChangesMask() void ItemData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const { - data << uint32(BonusListIDs->size()); - for (uint32 i = 0; i < BonusListIDs->size(); ++i) - { - data << int32((*BonusListIDs)[i]); - } data << Owner; data << ContainedIn; data << Creator; @@ -309,6 +304,10 @@ void ItemData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) { data << uint32(DynamicFlags2); + } + data << ItemBonusKey; + if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) + { data << uint16(DEBUGItemLevel); } for (uint32 i = 0; i < ArtifactPowers.size(); ++i) @@ -324,7 +323,7 @@ void ItemData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi void ItemData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const { - Mask allowedMaskForTarget({ 0xF804E4FFu, 0x000001FFu }); + Mask allowedMaskForTarget({ 0xF80A727Fu, 0x000001FFu }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); WriteUpdate(data, _changesMask & allowedMaskForTarget, false, owner, receiver); } @@ -332,12 +331,12 @@ void ItemData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi void ItemData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) - allowedMaskForTarget |= { 0x07FB1B00u, 0x00000000u }; + allowedMaskForTarget |= { 0x07F58D80u, 0x00000000u }; } void ItemData::FilterDisallowedFieldsMaskForFlag(Mask& changesMask, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { - Mask allowedMaskForTarget({ 0xF804E4FFu, 0x000001FFu }); + Mask allowedMaskForTarget({ 0xF80A727Fu, 0x000001FFu }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); changesMask &= allowedMaskForTarget; } @@ -353,24 +352,12 @@ void ItemData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor { if (changesMask[1]) { - data.WriteBits(BonusListIDs->size(), 32); - for (uint32 i = 0; i < BonusListIDs->size(); ++i) - { - data << int32((*BonusListIDs)[i]); - } - } - } - data.FlushBits(); - if (changesMask[0]) - { - if (changesMask[2]) - { if (!ignoreNestedChangesMask) ArtifactPowers.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ArtifactPowers.size(), data); } - if (changesMask[3]) + if (changesMask[2]) { if (!ignoreNestedChangesMask) Gems.WriteUpdateMask(data); @@ -381,7 +368,7 @@ void ItemData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor data.FlushBits(); if (changesMask[0]) { - if (changesMask[2]) + if (changesMask[1]) { for (uint32 i = 0; i < ArtifactPowers.size(); ++i) { @@ -391,7 +378,7 @@ void ItemData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor } } } - if (changesMask[3]) + if (changesMask[2]) { for (uint32 i = 0; i < Gems.size(); ++i) { @@ -401,71 +388,75 @@ void ItemData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor } } } - if (changesMask[4]) + if (changesMask[3]) { data << Owner; } - if (changesMask[5]) + if (changesMask[4]) { data << ContainedIn; } - if (changesMask[6]) + if (changesMask[5]) { data << Creator; } - if (changesMask[7]) + if (changesMask[6]) { data << GiftCreator; } - if (changesMask[8]) + if (changesMask[7]) { data << uint32(StackCount); } - if (changesMask[9]) + if (changesMask[8]) { data << uint32(Expiration); } - if (changesMask[10]) + if (changesMask[9]) { data << uint32(DynamicFlags); } - if (changesMask[11]) + if (changesMask[10]) { data << uint32(Durability); } - if (changesMask[12]) + if (changesMask[11]) { data << uint32(MaxDurability); } - if (changesMask[13]) + if (changesMask[12]) { data << uint32(CreatePlayedTime); } - if (changesMask[14]) + if (changesMask[13]) { data << int32(Context); } - if (changesMask[15]) + if (changesMask[14]) { data << int64(CreateTime); } - if (changesMask[16]) + if (changesMask[15]) { data << uint64(ArtifactXP); } - if (changesMask[17]) + if (changesMask[16]) { data << uint8(ItemAppearanceModID); } - if (changesMask[19]) + if (changesMask[18]) { data << uint32(DynamicFlags2); } + if (changesMask[19]) + { + data << ItemBonusKey; + } if (changesMask[20]) { data << uint16(DEBUGItemLevel); } - if (changesMask[18]) + if (changesMask[17]) { Modifiers->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } @@ -494,7 +485,6 @@ void ItemData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor void ItemData::ClearChangesMask() { - Base::ClearChangesMask(BonusListIDs); Base::ClearChangesMask(ArtifactPowers); Base::ClearChangesMask(Gems); Base::ClearChangesMask(Owner); @@ -513,6 +503,7 @@ void ItemData::ClearChangesMask() Base::ClearChangesMask(ItemAppearanceModID); Base::ClearChangesMask(Modifiers); Base::ClearChangesMask(DynamicFlags2); + Base::ClearChangesMask(ItemBonusKey); Base::ClearChangesMask(DEBUGItemLevel); Base::ClearChangesMask(SpellCharges); Base::ClearChangesMask(Enchantment); @@ -968,6 +959,7 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi data << BattlePetCompanionGUID; data << uint64(BattlePetDBID); ChannelData->WriteCreate(data, owner, receiver); + data << int8(SpellEmpowerStage); data << uint32(SummonedByHomeRealm); data << uint8(Race); data << uint8(ClassId); @@ -1120,6 +1112,7 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi data << uint32(PassiveSpells.size()); data << uint32(WorldEffects.size()); data << uint32(ChannelObjects.size()); + data << int32(FlightCapabilityID); data << uint32(SilencedSchoolMask); data << NameplateAttachToGUID; for (uint32 i = 0; i < PassiveSpells.size(); ++i) @@ -1138,7 +1131,7 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi void UnitData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const { - Mask allowedMaskForTarget({ 0xFFFFDFFFu, 0xE1FF7FFFu, 0x001EFFFFu, 0xFFFFFF81u, 0x7F0003FFu, 0x00000000u, 0x00000000u }); + Mask allowedMaskForTarget({ 0xFFFFDFFFu, 0xC3FEFFFFu, 0x003DFFFFu, 0xFFFFFF01u, 0xFC000FFFu, 0x00000001u, 0x00000000u }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); WriteUpdate(data, _changesMask & allowedMaskForTarget, false, owner, receiver); } @@ -1146,16 +1139,16 @@ void UnitData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi void UnitData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) - allowedMaskForTarget |= { 0x00002000u, 0x1E008000u, 0xFFE10000u, 0x0800007Eu, 0x80FFFC00u, 0xFFFFFFFFu, 0x00000003u }; + allowedMaskForTarget |= { 0x00002000u, 0x3C010000u, 0xFFC20000u, 0x200000FEu, 0x03FFF000u, 0xFFFFFFFEu, 0x0000000Fu }; if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::UnitAll)) - allowedMaskForTarget |= { 0x00000000u, 0x00000000u, 0x00000000u, 0x08000000u, 0x00FFFC00u, 0x00000000u, 0x00000000u }; + allowedMaskForTarget |= { 0x00000000u, 0x00000000u, 0x00000000u, 0x20000000u, 0x03FFF000u, 0x00000000u, 0x00000000u }; if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Empath)) - allowedMaskForTarget |= { 0x00000000u, 0x1E000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x000FF000u, 0x00000000u }; + allowedMaskForTarget |= { 0x00000000u, 0x3C000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x003FC000u, 0x00000000u }; } void UnitData::FilterDisallowedFieldsMaskForFlag(Mask& changesMask, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { - Mask allowedMaskForTarget({ 0xFFFFDFFFu, 0xE1FF7FFFu, 0x001EFFFFu, 0xFFFFFF81u, 0x7F0003FFu, 0x00000000u, 0x00000000u }); + Mask allowedMaskForTarget({ 0xFFFFDFFFu, 0xC3FEFFFFu, 0x003DFFFFu, 0xFFFFFF01u, 0xFC000FFFu, 0x00000001u, 0x00000000u }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); changesMask &= allowedMaskForTarget; } @@ -1310,473 +1303,481 @@ void UnitData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor } if (changesMask[23]) { - data << uint32(SummonedByHomeRealm); + data << int8(SpellEmpowerStage); } if (changesMask[24]) { - data << uint8(Race); + data << uint32(SummonedByHomeRealm); } if (changesMask[25]) { - data << uint8(ClassId); + data << uint8(Race); } if (changesMask[26]) { - data << uint8(PlayerClassId); + data << uint8(ClassId); } if (changesMask[27]) { - data << uint8(Sex); + data << uint8(PlayerClassId); } if (changesMask[28]) { - data << uint8(DisplayPower); + data << uint8(Sex); } if (changesMask[29]) { - data << uint32(OverrideDisplayPowerID); + data << uint8(DisplayPower); } if (changesMask[30]) { - data << int64(Health); + data << uint32(OverrideDisplayPowerID); } if (changesMask[31]) { - data << int64(MaxHealth); + data << int64(Health); } } if (changesMask[32]) { if (changesMask[33]) { - data << int32(Level); + data << int64(MaxHealth); } if (changesMask[34]) { - data << int32(EffectiveLevel); + data << int32(Level); } if (changesMask[35]) { - data << int32(ContentTuningID); + data << int32(EffectiveLevel); } if (changesMask[36]) { - data << int32(ScalingLevelMin); + data << int32(ContentTuningID); } if (changesMask[37]) { - data << int32(ScalingLevelMax); + data << int32(ScalingLevelMin); } if (changesMask[38]) { - data << int32(ScalingLevelDelta); + data << int32(ScalingLevelMax); } if (changesMask[39]) { - data << int32(ScalingFactionGroup); + data << int32(ScalingLevelDelta); } if (changesMask[40]) { - data << int32(ScalingHealthItemLevelCurveID); + data << int32(ScalingFactionGroup); } if (changesMask[41]) { - data << int32(ScalingDamageItemLevelCurveID); + data << int32(ScalingHealthItemLevelCurveID); } if (changesMask[42]) { - data << int32(ViewerDependentValue<FactionTemplateTag>::GetValue(this, owner, receiver)); + data << int32(ScalingDamageItemLevelCurveID); } if (changesMask[43]) { - data << uint32(ViewerDependentValue<FlagsTag>::GetValue(this, owner, receiver)); + data << int32(ViewerDependentValue<FactionTemplateTag>::GetValue(this, owner, receiver)); } if (changesMask[44]) { - data << uint32(Flags2); + data << uint32(ViewerDependentValue<FlagsTag>::GetValue(this, owner, receiver)); } if (changesMask[45]) { - data << uint32(ViewerDependentValue<Flags3Tag>::GetValue(this, owner, receiver)); + data << uint32(Flags2); } if (changesMask[46]) { - data << uint32(ViewerDependentValue<AuraStateTag>::GetValue(this, owner, receiver)); + data << uint32(ViewerDependentValue<Flags3Tag>::GetValue(this, owner, receiver)); } if (changesMask[47]) { - data << uint32(RangedAttackRoundBaseTime); + data << uint32(ViewerDependentValue<AuraStateTag>::GetValue(this, owner, receiver)); } if (changesMask[48]) { - data << float(BoundingRadius); + data << uint32(RangedAttackRoundBaseTime); } if (changesMask[49]) { - data << float(CombatReach); + data << float(BoundingRadius); } if (changesMask[50]) { - data << float(DisplayScale); + data << float(CombatReach); } if (changesMask[51]) { - data << int32(CreatureFamily); + data << float(DisplayScale); } if (changesMask[52]) { - data << int32(CreatureType); + data << int32(CreatureFamily); } if (changesMask[53]) { - data << int32(NativeDisplayID); + data << int32(CreatureType); } if (changesMask[54]) { - data << float(NativeXDisplayScale); + data << int32(NativeDisplayID); } if (changesMask[55]) { - data << int32(MountDisplayID); + data << float(NativeXDisplayScale); } if (changesMask[56]) { - data << int32(CosmeticMountDisplayID); + data << int32(MountDisplayID); } if (changesMask[57]) { - data << float(MinDamage); + data << int32(CosmeticMountDisplayID); } if (changesMask[58]) { - data << float(MaxDamage); + data << float(MinDamage); } if (changesMask[59]) { - data << float(MinOffHandDamage); + data << float(MaxDamage); } if (changesMask[60]) { - data << float(MaxOffHandDamage); + data << float(MinOffHandDamage); } if (changesMask[61]) { - data << uint8(StandState); + data << float(MaxOffHandDamage); } if (changesMask[62]) { - data << uint8(PetTalentPoints); + data << uint8(StandState); } if (changesMask[63]) { - data << uint8(VisFlags); + data << uint8(PetTalentPoints); } } if (changesMask[64]) { if (changesMask[65]) { - data << uint8(AnimTier); + data << uint8(VisFlags); } if (changesMask[66]) { - data << uint32(PetNumber); + data << uint8(AnimTier); } if (changesMask[67]) { - data << uint32(PetNameTimestamp); + data << uint32(PetNumber); } if (changesMask[68]) { - data << uint32(PetExperience); + data << uint32(PetNameTimestamp); } if (changesMask[69]) { - data << uint32(PetNextLevelExperience); + data << uint32(PetExperience); } if (changesMask[70]) { - data << float(ModCastingSpeed); + data << uint32(PetNextLevelExperience); } if (changesMask[71]) { - data << float(ModCastingSpeedNeg); + data << float(ModCastingSpeed); } if (changesMask[72]) { - data << float(ModSpellHaste); + data << float(ModCastingSpeedNeg); } if (changesMask[73]) { - data << float(ModHaste); + data << float(ModSpellHaste); } if (changesMask[74]) { - data << float(ModRangedHaste); + data << float(ModHaste); } if (changesMask[75]) { - data << float(ModHasteRegen); + data << float(ModRangedHaste); } if (changesMask[76]) { - data << float(ModTimeRate); + data << float(ModHasteRegen); } if (changesMask[77]) { - data << int32(CreatedBySpell); + data << float(ModTimeRate); } if (changesMask[78]) { - data << int32(EmoteState); + data << int32(CreatedBySpell); } if (changesMask[79]) { - data << int32(BaseMana); + data << int32(EmoteState); } if (changesMask[80]) { - data << int32(BaseHealth); + data << int32(BaseMana); } if (changesMask[81]) { - data << uint8(SheatheState); + data << int32(BaseHealth); } if (changesMask[82]) { - data << uint8(ViewerDependentValue<PvpFlagsTag>::GetValue(this, owner, receiver)); + data << uint8(SheatheState); } if (changesMask[83]) { - data << uint8(PetFlags); + data << uint8(ViewerDependentValue<PvpFlagsTag>::GetValue(this, owner, receiver)); } if (changesMask[84]) { - data << uint8(ShapeshiftForm); + data << uint8(PetFlags); } if (changesMask[85]) { - data << int32(AttackPower); + data << uint8(ShapeshiftForm); } if (changesMask[86]) { - data << int32(AttackPowerModPos); + data << int32(AttackPower); } if (changesMask[87]) { - data << int32(AttackPowerModNeg); + data << int32(AttackPowerModPos); } if (changesMask[88]) { - data << float(AttackPowerMultiplier); + data << int32(AttackPowerModNeg); } if (changesMask[89]) { - data << int32(RangedAttackPower); + data << float(AttackPowerMultiplier); } if (changesMask[90]) { - data << int32(RangedAttackPowerModPos); + data << int32(RangedAttackPower); } if (changesMask[91]) { - data << int32(RangedAttackPowerModNeg); + data << int32(RangedAttackPowerModPos); } if (changesMask[92]) { - data << float(RangedAttackPowerMultiplier); + data << int32(RangedAttackPowerModNeg); } if (changesMask[93]) { - data << int32(MainHandWeaponAttackPower); + data << float(RangedAttackPowerMultiplier); } if (changesMask[94]) { - data << int32(OffHandWeaponAttackPower); + data << int32(MainHandWeaponAttackPower); } if (changesMask[95]) { - data << int32(RangedWeaponAttackPower); + data << int32(OffHandWeaponAttackPower); } } if (changesMask[96]) { if (changesMask[97]) { - data << int32(SetAttackSpeedAura); + data << int32(RangedWeaponAttackPower); } if (changesMask[98]) { - data << float(Lifesteal); + data << int32(SetAttackSpeedAura); } if (changesMask[99]) { - data << float(MinRangedDamage); + data << float(Lifesteal); } if (changesMask[100]) { - data << float(MaxRangedDamage); + data << float(MinRangedDamage); } if (changesMask[101]) { - data << float(ManaCostMultiplier); + data << float(MaxRangedDamage); } if (changesMask[102]) { - data << float(MaxHealthModifier); + data << float(ManaCostMultiplier); } if (changesMask[103]) { - data << float(HoverHeight); + data << float(MaxHealthModifier); } if (changesMask[104]) { - data << int32(MinItemLevelCutoff); + data << float(HoverHeight); } if (changesMask[105]) { - data << int32(MinItemLevel); + data << int32(MinItemLevelCutoff); } if (changesMask[106]) { - data << int32(MaxItemLevel); + data << int32(MinItemLevel); } if (changesMask[107]) { - data << int32(AzeriteItemLevel); + data << int32(MaxItemLevel); } if (changesMask[108]) { - data << int32(WildBattlePetLevel); + data << int32(AzeriteItemLevel); } if (changesMask[109]) { - data << int32(BattlePetCompanionExperience); + data << int32(WildBattlePetLevel); } if (changesMask[110]) { - data << uint32(BattlePetCompanionNameTimestamp); + data << int32(BattlePetCompanionExperience); } if (changesMask[111]) { - data << int32(InteractSpellID); + data << uint32(BattlePetCompanionNameTimestamp); } if (changesMask[112]) { - data << int32(ScaleDuration); + data << int32(InteractSpellID); } if (changesMask[113]) { - data << int32(LooksLikeMountID); + data << int32(ScaleDuration); } if (changesMask[114]) { - data << int32(LooksLikeCreatureID); + data << int32(LooksLikeMountID); } if (changesMask[115]) { - data << int32(LookAtControllerID); + data << int32(LooksLikeCreatureID); } if (changesMask[116]) { - data << int32(TaxiNodesID); + data << int32(LookAtControllerID); } if (changesMask[117]) { - data << GuildGUID; + data << int32(TaxiNodesID); } if (changesMask[118]) { - data << uint32(SilencedSchoolMask); + data << GuildGUID; } if (changesMask[119]) { + data << int32(FlightCapabilityID); + } + if (changesMask[120]) + { + data << uint32(SilencedSchoolMask); + } + if (changesMask[121]) + { data << NameplateAttachToGUID; } } - if (changesMask[120]) + if (changesMask[122]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[121 + i]) + if (changesMask[123 + i]) { data << uint32(ViewerDependentValue<NpcFlagsTag>::GetValue(this, i, owner, receiver)); } } } - if (changesMask[123]) + if (changesMask[125]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[124 + i]) + if (changesMask[126 + i]) { data << int32(Power[i]); } - if (changesMask[131 + i]) + if (changesMask[133 + i]) { data << int32(MaxPower[i]); } - if (changesMask[138 + i]) + if (changesMask[140 + i]) { data << float(PowerRegenFlatModifier[i]); } - if (changesMask[145 + i]) + if (changesMask[147 + i]) { data << float(PowerRegenInterruptedFlatModifier[i]); } } } - if (changesMask[152]) + if (changesMask[154]) { for (uint32 i = 0; i < 3; ++i) { - if (changesMask[153 + i]) + if (changesMask[155 + i]) { VirtualItems[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[156]) + if (changesMask[158]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[157 + i]) + if (changesMask[159 + i]) { data << uint32(AttackRoundBaseTime[i]); } } } - if (changesMask[159]) + if (changesMask[161]) { for (uint32 i = 0; i < 4; ++i) { - if (changesMask[160 + i]) + if (changesMask[162 + i]) { data << int32(Stats[i]); } - if (changesMask[164 + i]) + if (changesMask[166 + i]) { data << int32(StatPosBuff[i]); } - if (changesMask[168 + i]) + if (changesMask[170 + i]) { data << int32(StatNegBuff[i]); } } } - if (changesMask[172]) + if (changesMask[174]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[173 + i]) + if (changesMask[175 + i]) { data << int32(Resistances[i]); } - if (changesMask[180 + i]) + if (changesMask[182 + i]) { data << int32(BonusResistanceMods[i]); } - if (changesMask[187 + i]) + if (changesMask[189 + i]) { data << int32(ManaCostModifier[i]); } @@ -1808,6 +1809,7 @@ void UnitData::ClearChangesMask() Base::ClearChangesMask(BattlePetCompanionGUID); Base::ClearChangesMask(BattlePetDBID); Base::ClearChangesMask(ChannelData); + Base::ClearChangesMask(SpellEmpowerStage); Base::ClearChangesMask(SummonedByHomeRealm); Base::ClearChangesMask(Race); Base::ClearChangesMask(ClassId); @@ -1900,6 +1902,7 @@ void UnitData::ClearChangesMask() Base::ClearChangesMask(LookAtControllerID); Base::ClearChangesMask(TaxiNodesID); Base::ClearChangesMask(GuildGUID); + Base::ClearChangesMask(FlightCapabilityID); Base::ClearChangesMask(SilencedSchoolMask); Base::ClearChangesMask(NameplateAttachToGUID); Base::ClearChangesMask(NpcFlags); @@ -2133,12 +2136,14 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi } data << uint8(CurrentBattlePetBreedQuality); data << int32(HonorLevel); + data << int64(LogoutTime); data << uint32(ArenaCooldowns.size()); data << int32(Field_B0); data << int32(Field_B4); CtrOptions->WriteCreate(data, owner, receiver); data << int32(CovenantID); data << int32(SoulbindID); + data << uint32(VisualItemReplacements.size()); for (uint32 i = 0; i < Customizations.size(); ++i) { Customizations[i].WriteCreate(data, owner, receiver); @@ -2154,6 +2159,10 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi { ArenaCooldowns[i].WriteCreate(data, owner, receiver); } + for (uint32 i = 0; i < VisualItemReplacements.size(); ++i) + { + data << int32(VisualItemReplacements[i]); + } if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::PartyMember)) { data.WriteBit(HasQuestSession); @@ -2165,7 +2174,7 @@ void PlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi void PlayerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const { - Mask allowedMaskForTarget({ 0xFFFFFFEDu, 0x00000007u, 0x00000000u, 0x00000000u, 0x00000000u, 0x0FFFFFFEu }); + Mask allowedMaskForTarget({ 0xFFFFFFEDu, 0x0000001Fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x3FFFFFF8u }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); WriteUpdate(data, _changesMask & allowedMaskForTarget, false, owner, receiver); } @@ -2173,12 +2182,12 @@ void PlayerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVi void PlayerData::AppendAllowedFieldsMaskForFlag(Mask& allowedMaskForTarget, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::PartyMember)) - allowedMaskForTarget |= { 0x00000012u, 0xFFFFFFF8u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000001u }; + allowedMaskForTarget |= { 0x00000012u, 0xFFFFFFE0u, 0xFFFFFFFFu, 0xFFFFFFFFu, 0xFFFFFFFFu, 0x00000007u }; } void PlayerData::FilterDisallowedFieldsMaskForFlag(Mask& changesMask, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags) { - Mask allowedMaskForTarget({ 0xFFFFFFEDu, 0x00000007u, 0x00000000u, 0x00000000u, 0x00000000u, 0x0FFFFFFEu }); + Mask allowedMaskForTarget({ 0xFFFFFFEDu, 0x0000001Fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x3FFFFFF8u }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); changesMask &= allowedMaskForTarget; } @@ -2222,6 +2231,13 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign else WriteCompleteDynamicFieldUpdateMask(ArenaCooldowns.size(), data); } + if (changesMask[6]) + { + if (!ignoreNestedChangesMask) + VisualItemReplacements.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(VisualItemReplacements.size(), data); + } } data.FlushBits(); if (changesMask[0]) @@ -2261,125 +2277,139 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign } if (changesMask[6]) { - data << DuelArbiter; + for (uint32 i = 0; i < VisualItemReplacements.size(); ++i) + { + if (VisualItemReplacements.HasChanged(i) || ignoreNestedChangesMask) + { + data << int32(VisualItemReplacements[i]); + } + } } if (changesMask[7]) { - data << WowAccount; + data << DuelArbiter; } if (changesMask[8]) { - data << LootTargetGUID; + data << WowAccount; } if (changesMask[9]) { - data << uint32(PlayerFlags); + data << LootTargetGUID; } if (changesMask[10]) { - data << uint32(PlayerFlagsEx); + data << uint32(PlayerFlags); } if (changesMask[11]) { - data << uint32(GuildRankID); + data << uint32(PlayerFlagsEx); } if (changesMask[12]) { - data << uint32(GuildDeleteDate); + data << uint32(GuildRankID); } if (changesMask[13]) { - data << int32(GuildLevel); + data << uint32(GuildDeleteDate); } if (changesMask[14]) { - data << uint8(PartyType); + data << int32(GuildLevel); } if (changesMask[15]) { - data << uint8(NativeSex); + data << uint8(PartyType); } if (changesMask[16]) { - data << uint8(Inebriation); + data << uint8(NativeSex); } if (changesMask[17]) { - data << uint8(PvpTitle); + data << uint8(Inebriation); } if (changesMask[18]) { - data << uint8(ArenaFaction); + data << uint8(PvpTitle); } if (changesMask[19]) { - data << uint32(DuelTeam); + data << uint8(ArenaFaction); } if (changesMask[20]) { - data << int32(GuildTimeStamp); + data << uint32(DuelTeam); } if (changesMask[21]) { - data << int32(PlayerTitle); + data << int32(GuildTimeStamp); } if (changesMask[22]) { - data << int32(FakeInebriation); + data << int32(PlayerTitle); } if (changesMask[23]) { - data << uint32(VirtualPlayerRealm); + data << int32(FakeInebriation); } if (changesMask[24]) { - data << uint32(CurrentSpecID); + data << uint32(VirtualPlayerRealm); } if (changesMask[25]) { - data << int32(TaxiMountAnimKitID); + data << uint32(CurrentSpecID); } if (changesMask[26]) { - data << uint8(CurrentBattlePetBreedQuality); + data << int32(TaxiMountAnimKitID); } if (changesMask[27]) { - data << int32(HonorLevel); + data << uint8(CurrentBattlePetBreedQuality); } if (changesMask[28]) { - data << int32(Field_B0); + data << int32(HonorLevel); } if (changesMask[29]) { - data << int32(Field_B4); + data << int64(LogoutTime); } if (changesMask[30]) { - CtrOptions->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << int32(Field_B0); } if (changesMask[31]) { - data << int32(CovenantID); + data << int32(Field_B4); } } if (changesMask[32]) { if (changesMask[33]) { - data << int32(SoulbindID); + CtrOptions->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } if (changesMask[34]) { + data << int32(CovenantID); + } + if (changesMask[35]) + { + data << int32(SoulbindID); + } + if (changesMask[36]) + { data << DungeonScore; } } - if (changesMask[35]) + if (changesMask[37]) { for (uint32 i = 0; i < 125; ++i) { - if (changesMask[36 + i]) + if (changesMask[38 + i]) { if (noQuestLogChangesMask) QuestLog[i].WriteCreate(data, owner, receiver); @@ -2388,21 +2418,21 @@ void PlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ign } } } - if (changesMask[161]) + if (changesMask[163]) { for (uint32 i = 0; i < 19; ++i) { - if (changesMask[162 + i]) + if (changesMask[164 + i]) { VisibleItems[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[181]) + if (changesMask[183]) { for (uint32 i = 0; i < 6; ++i) { - if (changesMask[182 + i]) + if (changesMask[184 + i]) { data << float(AvgItemLevel[i]); } @@ -2418,6 +2448,7 @@ void PlayerData::ClearChangesMask() Base::ClearChangesMask(Customizations); Base::ClearChangesMask(QuestSessionQuestLog); Base::ClearChangesMask(ArenaCooldowns); + Base::ClearChangesMask(VisualItemReplacements); Base::ClearChangesMask(DuelArbiter); Base::ClearChangesMask(WowAccount); Base::ClearChangesMask(LootTargetGUID); @@ -2440,6 +2471,7 @@ void PlayerData::ClearChangesMask() Base::ClearChangesMask(TaxiMountAnimKitID); Base::ClearChangesMask(CurrentBattlePetBreedQuality); Base::ClearChangesMask(HonorLevel); + Base::ClearChangesMask(LogoutTime); Base::ClearChangesMask(Field_B0); Base::ClearChangesMask(Field_B4); Base::ClearChangesMask(CtrOptions); @@ -2565,6 +2597,8 @@ void RestInfo::ClearChangesMask() void PVPInfo::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const { + data << int8(Bracket); + data << int32(PvpRatingID); data << uint32(WeeklyPlayed); data << uint32(WeeklyWon); data << uint32(SeasonPlayed); @@ -2576,6 +2610,10 @@ void PVPInfo::WriteCreate(ByteBuffer& data, Player const* owner, Player const* r data << uint32(WeeklyBestWinPvpTierID); data << uint32(Field_28); data << uint32(Field_2C); + data << uint32(WeeklyRoundsPlayed); + data << uint32(WeeklyRoundsWon); + data << uint32(SeasonRoundsPlayed); + data << uint32(SeasonRoundsWon); data.WriteBit(Disqualified); data.FlushBits(); } @@ -2586,7 +2624,7 @@ void PVPInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const if (ignoreChangesMask) changesMask.SetAll(); - data.WriteBits(changesMask.GetBlock(0), 13); + data.WriteBits(changesMask.GetBlock(0), 19); if (changesMask[0]) { @@ -2600,48 +2638,72 @@ void PVPInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const { if (changesMask[2]) { - data << uint32(WeeklyPlayed); + data << int8(Bracket); } if (changesMask[3]) { - data << uint32(WeeklyWon); + data << int32(PvpRatingID); } if (changesMask[4]) { - data << uint32(SeasonPlayed); + data << uint32(WeeklyPlayed); } if (changesMask[5]) { - data << uint32(SeasonWon); + data << uint32(WeeklyWon); } if (changesMask[6]) { - data << uint32(Rating); + data << uint32(SeasonPlayed); } if (changesMask[7]) { - data << uint32(WeeklyBestRating); + data << uint32(SeasonWon); } if (changesMask[8]) { - data << uint32(SeasonBestRating); + data << uint32(Rating); } if (changesMask[9]) { - data << uint32(PvpTierID); + data << uint32(WeeklyBestRating); } if (changesMask[10]) { - data << uint32(WeeklyBestWinPvpTierID); + data << uint32(SeasonBestRating); } if (changesMask[11]) { - data << uint32(Field_28); + data << uint32(PvpTierID); } if (changesMask[12]) { + data << uint32(WeeklyBestWinPvpTierID); + } + if (changesMask[13]) + { + data << uint32(Field_28); + } + if (changesMask[14]) + { data << uint32(Field_2C); } + if (changesMask[15]) + { + data << uint32(WeeklyRoundsPlayed); + } + if (changesMask[16]) + { + data << uint32(WeeklyRoundsWon); + } + if (changesMask[17]) + { + data << uint32(SeasonRoundsPlayed); + } + if (changesMask[18]) + { + data << uint32(SeasonRoundsWon); + } } data.FlushBits(); } @@ -2649,6 +2711,8 @@ void PVPInfo::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const void PVPInfo::ClearChangesMask() { Base::ClearChangesMask(Disqualified); + Base::ClearChangesMask(Bracket); + Base::ClearChangesMask(PvpRatingID); Base::ClearChangesMask(WeeklyPlayed); Base::ClearChangesMask(WeeklyWon); Base::ClearChangesMask(SeasonPlayed); @@ -2660,6 +2724,10 @@ void PVPInfo::ClearChangesMask() Base::ClearChangesMask(WeeklyBestWinPvpTierID); Base::ClearChangesMask(Field_28); Base::ClearChangesMask(Field_2C); + Base::ClearChangesMask(WeeklyRoundsPlayed); + Base::ClearChangesMask(WeeklyRoundsWon); + Base::ClearChangesMask(SeasonRoundsPlayed); + Base::ClearChangesMask(SeasonRoundsWon); _changesMask.ResetAll(); } @@ -2926,9 +2994,514 @@ void ReplayedQuest::ClearChangesMask() _changesMask.ResetAll(); } +void TraitEntry::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << int32(TraitNodeID); + data << int32(TraitNodeEntryID); + data << int32(Rank); + data << int32(GrantedRanks); +} + +void TraitEntry::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + data << int32(TraitNodeID); + data << int32(TraitNodeEntryID); + data << int32(Rank); + data << int32(GrantedRanks); +} + +bool TraitEntry::operator==(TraitEntry const& right) const +{ + return TraitNodeID == right.TraitNodeID + && TraitNodeEntryID == right.TraitNodeEntryID + && Rank == right.Rank + && GrantedRanks == right.GrantedRanks; +} + +void TraitConfig::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << int32(ID); + data << int32(Type); + data << uint32(Entries.size()); + if (Type == 2) + { + data << int32(SkillLineID); + } + if (Type == 1) + { + data << int32(ChrSpecializationID); + data << int32(CombatConfigFlags); + data << int32(LocalIdentifier); + } + if (Type == 3) + { + data << int32(TraitSystemID); + } + for (uint32 i = 0; i < Entries.size(); ++i) + { + Entries[i].WriteCreate(data, owner, receiver); + } + data.WriteBits(Name->size(), 9); + data.WriteString(Name); + data.FlushBits(); +} + +void TraitConfig::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 12); + + if (changesMask[0]) + { + if (changesMask[1]) + { + if (!ignoreChangesMask) + Entries.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(Entries.size(), data); + } + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + for (uint32 i = 0; i < Entries.size(); ++i) + { + if (Entries.HasChanged(i) || ignoreChangesMask) + { + Entries[i].WriteUpdate(data, ignoreChangesMask, owner, receiver); + } + } + } + if (changesMask[2]) + { + data << int32(ID); + } + } + if (changesMask[4]) + { + if (changesMask[5]) + { + data << int32(Type); + } + if (changesMask[6]) + { + if (Type == 2) + { + data << int32(SkillLineID); + } + } + if (changesMask[7]) + { + if (Type == 1) + { + data << int32(ChrSpecializationID); + } + } + } + if (changesMask[8]) + { + if (changesMask[9]) + { + if (Type == 1) + { + data << int32(CombatConfigFlags); + } + } + if (changesMask[10]) + { + if (Type == 1) + { + data << int32(LocalIdentifier); + } + } + if (changesMask[11]) + { + if (Type == 3) + { + data << int32(TraitSystemID); + } + } + } + if (changesMask[0]) + { + if (changesMask[3]) + { + data.WriteBits(Name->size(), 9); + data.WriteString(Name); + } + } + data.FlushBits(); +} + +void TraitConfig::ClearChangesMask() +{ + Base::ClearChangesMask(Entries); + Base::ClearChangesMask(ID); + Base::ClearChangesMask(Name); + Base::ClearChangesMask(Type); + Base::ClearChangesMask(SkillLineID); + Base::ClearChangesMask(ChrSpecializationID); + Base::ClearChangesMask(CombatConfigFlags); + Base::ClearChangesMask(LocalIdentifier); + Base::ClearChangesMask(TraitSystemID); + _changesMask.ResetAll(); +} + +void CraftingOrderItem::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << uint64(Field_0); + data << ItemGUID; + data << OwnerGUID; + data << int32(ItemID); + data << uint32(Quantity); + data << int32(ReagentQuality); + data.WriteBits(DataSlotIndex.has_value(), 1); + if (DataSlotIndex.has_value()) + { + data << uint8(DataSlotIndex); + } +} + +void CraftingOrderItem::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 7); + + data.FlushBits(); + if (changesMask[0]) + { + data << uint64(Field_0); + } + if (changesMask[1]) + { + data << ItemGUID; + } + if (changesMask[2]) + { + data << OwnerGUID; + } + if (changesMask[3]) + { + data << int32(ItemID); + } + if (changesMask[4]) + { + data << uint32(Quantity); + } + if (changesMask[5]) + { + data << int32(ReagentQuality); + } + data.WriteBits(DataSlotIndex.has_value(), 1); + if (changesMask[6]) + { + if (DataSlotIndex.has_value()) + { + data << uint8(DataSlotIndex); + } + } +} + +void CraftingOrderItem::ClearChangesMask() +{ + Base::ClearChangesMask(Field_0); + Base::ClearChangesMask(ItemGUID); + Base::ClearChangesMask(OwnerGUID); + Base::ClearChangesMask(ItemID); + Base::ClearChangesMask(Quantity); + Base::ClearChangesMask(ReagentQuality); + Base::ClearChangesMask(DataSlotIndex); + _changesMask.ResetAll(); +} + +void CraftingOrderData::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + data << int32(Field_0); + data << uint64(OrderID); + data << int32(SkillLineAbilityID); + data << uint8(OrderState); + data << uint8(OrderType); + data << uint8(MinQuality); + data << int64(ExpirationTime); + data << int64(ClaimEndTime); + data << int64(TipAmount); + data << int64(ConsortiumCut); + data << uint32(Flags); + data << CustomerGUID; + data << CustomerAccountGUID; + data << CrafterGUID; + data << PersonalCrafterGUID; + data << uint32(Reagents.size()); + data.WriteBits(CustomerNotes->size(), 10); + data.WriteBits(OutputItem.has_value(), 1); + data.WriteBits(OutputItemData.has_value(), 1); + for (uint32 i = 0; i < Reagents.size(); ++i) + { + Reagents[i].WriteCreate(data, owner, receiver); + } + data.WriteString(CustomerNotes); + if (OutputItem.has_value()) + { + OutputItem->WriteCreate(data, owner, receiver); + } + if (OutputItemData.has_value()) + { + data << OutputItemData; + } + data.FlushBits(); +} + +void CraftingOrderData::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 24); + + if (changesMask[0]) + { + if (changesMask[1]) + { + if (!ignoreChangesMask) + Reagents.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(Reagents.size(), data); + } + } + data.FlushBits(); + if (changesMask[0]) + { + if (changesMask[1]) + { + for (uint32 i = 0; i < Reagents.size(); ++i) + { + if (Reagents.HasChanged(i) || ignoreChangesMask) + { + Reagents[i].WriteUpdate(data, ignoreChangesMask, owner, receiver); + } + } + } + if (changesMask[2]) + { + data << int32(Field_0); + } + if (changesMask[3]) + { + data << uint64(OrderID); + } + if (changesMask[4]) + { + data << int32(SkillLineAbilityID); + } + } + if (changesMask[5]) + { + if (changesMask[6]) + { + data << uint8(OrderState); + } + if (changesMask[7]) + { + data << uint8(OrderType); + } + if (changesMask[8]) + { + data << uint8(MinQuality); + } + if (changesMask[9]) + { + data << int64(ExpirationTime); + } + } + if (changesMask[10]) + { + if (changesMask[11]) + { + data << int64(ClaimEndTime); + } + if (changesMask[12]) + { + data << int64(TipAmount); + } + if (changesMask[13]) + { + data << int64(ConsortiumCut); + } + if (changesMask[14]) + { + data << uint32(Flags); + } + } + if (changesMask[15]) + { + if (changesMask[16]) + { + data << CustomerGUID; + } + if (changesMask[17]) + { + data << CustomerAccountGUID; + } + if (changesMask[18]) + { + data << CrafterGUID; + } + if (changesMask[19]) + { + data << PersonalCrafterGUID; + } + } + if (changesMask[20]) + { + if (changesMask[21]) + { + data.WriteBits(CustomerNotes->size(), 10); + data.WriteString(CustomerNotes); + } + data.WriteBits(OutputItem.has_value(), 1); + data.WriteBits(OutputItemData.has_value(), 1); + if (changesMask[22]) + { + if (OutputItem.has_value()) + { + OutputItem->WriteUpdate(data, ignoreChangesMask, owner, receiver); + } + } + if (changesMask[23]) + { + if (OutputItemData.has_value()) + { + data << OutputItemData; + } + } + } + data.FlushBits(); +} + +void CraftingOrderData::ClearChangesMask() +{ + Base::ClearChangesMask(Reagents); + Base::ClearChangesMask(Field_0); + Base::ClearChangesMask(OrderID); + Base::ClearChangesMask(SkillLineAbilityID); + Base::ClearChangesMask(OrderState); + Base::ClearChangesMask(OrderType); + Base::ClearChangesMask(MinQuality); + Base::ClearChangesMask(ExpirationTime); + Base::ClearChangesMask(ClaimEndTime); + Base::ClearChangesMask(TipAmount); + Base::ClearChangesMask(ConsortiumCut); + Base::ClearChangesMask(Flags); + Base::ClearChangesMask(CustomerGUID); + Base::ClearChangesMask(CustomerAccountGUID); + Base::ClearChangesMask(CrafterGUID); + Base::ClearChangesMask(PersonalCrafterGUID); + Base::ClearChangesMask(CustomerNotes); + Base::ClearChangesMask(OutputItem); + Base::ClearChangesMask(OutputItemData); + _changesMask.ResetAll(); +} + +void CraftingOrder::WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const +{ + Data->WriteCreate(data, owner, receiver); + data.WriteBits(RecraftItemInfo.has_value(), 1); + data.WriteBits(Enchantments.size(), 4); + data.WriteBits(Gems.size(), 2); + if (RecraftItemInfo.has_value()) + { + data << RecraftItemInfo; + } + for (uint32 i = 0; i < Enchantments.size(); ++i) + { + data << Enchantments[i]; + } + for (uint32 i = 0; i < Gems.size(); ++i) + { + data << Gems[i]; + } + data.FlushBits(); +} + +void CraftingOrder::WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const +{ + Mask changesMask = _changesMask; + if (ignoreChangesMask) + changesMask.SetAll(); + + data.WriteBits(changesMask.GetBlock(0), 4); + + if (changesMask[0]) + { + if (!ignoreChangesMask) + Enchantments.WriteUpdateMask(data, 4); + else + WriteCompleteDynamicFieldUpdateMask(Enchantments.size(), data, 4); + } + if (changesMask[1]) + { + if (!ignoreChangesMask) + Gems.WriteUpdateMask(data, 2); + else + WriteCompleteDynamicFieldUpdateMask(Gems.size(), data, 2); + } + data.FlushBits(); + if (changesMask[0]) + { + for (uint32 i = 0; i < Enchantments.size(); ++i) + { + if (Enchantments.HasChanged(i) || ignoreChangesMask) + { + data << Enchantments[i]; + } + } + } + if (changesMask[1]) + { + for (uint32 i = 0; i < Gems.size(); ++i) + { + if (Gems.HasChanged(i) || ignoreChangesMask) + { + data << Gems[i]; + } + } + } + if (changesMask[2]) + { + Data->WriteUpdate(data, ignoreChangesMask, owner, receiver); + } + data.WriteBits(RecraftItemInfo.has_value(), 1); + if (changesMask[3]) + { + if (RecraftItemInfo.has_value()) + { + data << RecraftItemInfo; + } + } + data.FlushBits(); +} + +void CraftingOrder::ClearChangesMask() +{ + Base::ClearChangesMask(Enchantments); + Base::ClearChangesMask(Gems); + Base::ClearChangesMask(Data); + Base::ClearChangesMask(RecraftItemInfo); + _changesMask.ResetAll(); +} + void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const { - for (uint32 i = 0; i < 199; ++i) + for (uint32 i = 0; i < 218; ++i) { data << InvSlots[i]; } @@ -3014,6 +3587,7 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f { data << int32(CombatRatings[i]); } + data << uint32(PvpInfo.size()); data << int32(MaxLevel); data << int32(ScalingPlayerLevelDelta); data << int32(MaxCreatureScalingLevel); @@ -3040,7 +3614,7 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f data << uint32(OverrideZonePVPType); data << BnetAccount; data << uint64(GuildClubMemberID); - for (uint32 i = 0; i < 4; ++i) + for (uint32 i = 0; i < 5; ++i) { data << uint32(BagSlotFlags[i]); } @@ -3088,6 +3662,9 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f data << int32(TransportServerTime); data << uint32(WeeklyRewardsPeriodSinceOrigin); data << int16(DEBUGSoulbindConduitRank); + data << uint32(TraitConfigs.size()); + data << uint32(ActiveCombatTraitConfigID); + data << uint32(CraftingOrders.size()); for (uint32 i = 0; i < KnownTitles.size(); ++i) { data << uint64(KnownTitles[i]); @@ -3172,10 +3749,6 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f { data << int32(DisabledSpells[i]); } - for (uint32 i = 0; i < 6; ++i) - { - PvpInfo[i].WriteCreate(data, owner, receiver); - } data.FlushBits(); data.WriteBit(BackpackAutoSortDisabled); data.WriteBit(BankAutoSortDisabled); @@ -3188,10 +3761,22 @@ void ActivePlayerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> f QuestSession->WriteCreate(data, owner, receiver); } data << DungeonScore; + for (uint32 i = 0; i < PvpInfo.size(); ++i) + { + PvpInfo[i].WriteCreate(data, owner, receiver); + } for (uint32 i = 0; i < CharacterRestrictions.size(); ++i) { CharacterRestrictions[i].WriteCreate(data, owner, receiver); } + for (uint32 i = 0; i < TraitConfigs.size(); ++i) + { + TraitConfigs[i].WriteCreate(data, owner, receiver); + } + for (uint32 i = 0; i < CraftingOrders.size(); ++i) + { + CraftingOrders[i].WriteCreate(data, owner, receiver); + } data.FlushBits(); } @@ -3204,8 +3789,8 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo { for (uint32 i = 0; i < 1; ++i) data << uint32(changesMask.GetBlocksMask(i)); - data.WriteBits(changesMask.GetBlocksMask(1), 17); - for (uint32 i = 0; i < 49; ++i) + data.WriteBits(changesMask.GetBlocksMask(1), 18); + for (uint32 i = 0; i < 50; ++i) if (changesMask.GetBlock(i)) data.WriteBits(changesMask.GetBlock(i), 32); @@ -3237,109 +3822,116 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo if (changesMask[6]) { if (!ignoreNestedChangesMask) + PvpInfo.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(PvpInfo.size(), data); + } + if (changesMask[7]) + { + if (!ignoreNestedChangesMask) ResearchSites.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ResearchSites.size(), data); } - if (changesMask[7]) + if (changesMask[8]) { if (!ignoreNestedChangesMask) ResearchSiteProgress.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ResearchSiteProgress.size(), data); } - if (changesMask[8]) + if (changesMask[9]) { if (!ignoreNestedChangesMask) DailyQuestsCompleted.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(DailyQuestsCompleted.size(), data); } - if (changesMask[9]) + if (changesMask[10]) { if (!ignoreNestedChangesMask) AvailableQuestLineXQuestIDs.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(AvailableQuestLineXQuestIDs.size(), data); } - if (changesMask[10]) + if (changesMask[11]) { if (!ignoreNestedChangesMask) Heirlooms.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(Heirlooms.size(), data); } - if (changesMask[11]) + if (changesMask[12]) { if (!ignoreNestedChangesMask) HeirloomFlags.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(HeirloomFlags.size(), data); } - if (changesMask[12]) + if (changesMask[13]) { if (!ignoreNestedChangesMask) Toys.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(Toys.size(), data); } - if (changesMask[13]) + if (changesMask[14]) { if (!ignoreNestedChangesMask) ToyFlags.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ToyFlags.size(), data); } - if (changesMask[14]) + if (changesMask[15]) { if (!ignoreNestedChangesMask) Transmog.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(Transmog.size(), data); } - if (changesMask[15]) + if (changesMask[16]) { if (!ignoreNestedChangesMask) ConditionalTransmog.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ConditionalTransmog.size(), data); } - if (changesMask[16]) + if (changesMask[17]) { if (!ignoreNestedChangesMask) SelfResSpells.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(SelfResSpells.size(), data); } - if (changesMask[17]) + if (changesMask[18]) { if (!ignoreNestedChangesMask) RuneforgePowers.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(RuneforgePowers.size(), data); } - if (changesMask[18]) + if (changesMask[19]) { if (!ignoreNestedChangesMask) TransmogIllusions.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(TransmogIllusions.size(), data); } - if (changesMask[19]) + if (changesMask[20]) { if (!ignoreNestedChangesMask) CharacterRestrictions.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(CharacterRestrictions.size(), data); } - if (changesMask[20]) + if (changesMask[21]) { if (!ignoreNestedChangesMask) SpellPctModByLabel.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(SpellPctModByLabel.size(), data); } - if (changesMask[21]) + if (changesMask[22]) { if (!ignoreNestedChangesMask) SpellFlatModByLabel.WriteUpdateMask(data); @@ -3347,11 +3939,11 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo WriteCompleteDynamicFieldUpdateMask(SpellFlatModByLabel.size(), data); } } - if (changesMask[27]) + if (changesMask[30]) { for (uint32 i = 0; i < 1; ++i) { - if (changesMask[28 + i]) + if (changesMask[31 + i]) { if (!ignoreNestedChangesMask) Research[i].WriteUpdateMask(data); @@ -3370,41 +3962,55 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo data.FlushBits(); if (changesMask[0]) { - if (changesMask[22]) + if (changesMask[23]) { if (!ignoreNestedChangesMask) MawPowers.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(MawPowers.size(), data); } - if (changesMask[23]) + if (changesMask[24]) { if (!ignoreNestedChangesMask) MultiFloorExploration.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(MultiFloorExploration.size(), data); } - if (changesMask[24]) + if (changesMask[25]) { if (!ignoreNestedChangesMask) RecipeProgression.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(RecipeProgression.size(), data); } - if (changesMask[25]) + if (changesMask[26]) { if (!ignoreNestedChangesMask) ReplayedQuests.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(ReplayedQuests.size(), data); } - if (changesMask[26]) + if (changesMask[27]) { if (!ignoreNestedChangesMask) DisabledSpells.WriteUpdateMask(data); else WriteCompleteDynamicFieldUpdateMask(DisabledSpells.size(), data); } + if (changesMask[28]) + { + if (!ignoreNestedChangesMask) + TraitConfigs.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(TraitConfigs.size(), data); + } + if (changesMask[29]) + { + if (!ignoreNestedChangesMask) + CraftingOrders.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(CraftingOrders.size(), data); + } } data.FlushBits(); if (changesMask[0]) @@ -3419,7 +4025,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[6]) + if (changesMask[7]) { for (uint32 i = 0; i < ResearchSites.size(); ++i) { @@ -3429,7 +4035,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[7]) + if (changesMask[8]) { for (uint32 i = 0; i < ResearchSiteProgress.size(); ++i) { @@ -3439,7 +4045,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[8]) + if (changesMask[9]) { for (uint32 i = 0; i < DailyQuestsCompleted.size(); ++i) { @@ -3449,7 +4055,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[9]) + if (changesMask[10]) { for (uint32 i = 0; i < AvailableQuestLineXQuestIDs.size(); ++i) { @@ -3459,7 +4065,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[10]) + if (changesMask[11]) { for (uint32 i = 0; i < Heirlooms.size(); ++i) { @@ -3469,7 +4075,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[11]) + if (changesMask[12]) { for (uint32 i = 0; i < HeirloomFlags.size(); ++i) { @@ -3479,7 +4085,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[12]) + if (changesMask[13]) { for (uint32 i = 0; i < Toys.size(); ++i) { @@ -3489,7 +4095,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[13]) + if (changesMask[14]) { for (uint32 i = 0; i < ToyFlags.size(); ++i) { @@ -3499,7 +4105,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[14]) + if (changesMask[15]) { for (uint32 i = 0; i < Transmog.size(); ++i) { @@ -3509,7 +4115,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[15]) + if (changesMask[16]) { for (uint32 i = 0; i < ConditionalTransmog.size(); ++i) { @@ -3519,7 +4125,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[16]) + if (changesMask[17]) { for (uint32 i = 0; i < SelfResSpells.size(); ++i) { @@ -3529,7 +4135,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[17]) + if (changesMask[18]) { for (uint32 i = 0; i < RuneforgePowers.size(); ++i) { @@ -3539,7 +4145,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[18]) + if (changesMask[19]) { for (uint32 i = 0; i < TransmogIllusions.size(); ++i) { @@ -3549,7 +4155,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[20]) + if (changesMask[21]) { for (uint32 i = 0; i < SpellPctModByLabel.size(); ++i) { @@ -3559,7 +4165,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[21]) + if (changesMask[22]) { for (uint32 i = 0; i < SpellFlatModByLabel.size(); ++i) { @@ -3569,7 +4175,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[22]) + if (changesMask[23]) { for (uint32 i = 0; i < MawPowers.size(); ++i) { @@ -3579,7 +4185,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[23]) + if (changesMask[24]) { for (uint32 i = 0; i < MultiFloorExploration.size(); ++i) { @@ -3589,7 +4195,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[24]) + if (changesMask[25]) { for (uint32 i = 0; i < RecipeProgression.size(); ++i) { @@ -3599,7 +4205,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[25]) + if (changesMask[26]) { for (uint32 i = 0; i < ReplayedQuests.size(); ++i) { @@ -3609,7 +4215,7 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[26]) + if (changesMask[27]) { for (uint32 i = 0; i < DisabledSpells.size(); ++i) { @@ -3619,7 +4225,17 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[19]) + if (changesMask[6]) + { + for (uint32 i = 0; i < PvpInfo.size(); ++i) + { + if (PvpInfo.HasChanged(i) || ignoreNestedChangesMask) + { + PvpInfo[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } + } + if (changesMask[20]) { for (uint32 i = 0; i < CharacterRestrictions.size(); ++i) { @@ -3629,493 +4245,507 @@ void ActivePlayerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bo } } } - if (changesMask[29]) - { - data << FarsightObject; - } - if (changesMask[30]) + if (changesMask[28]) { - data << SummonedBattlePetGUID; + for (uint32 i = 0; i < TraitConfigs.size(); ++i) + { + if (TraitConfigs.HasChanged(i) || ignoreNestedChangesMask) + { + TraitConfigs[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } } - if (changesMask[31]) + if (changesMask[29]) { - data << uint64(Coinage); + for (uint32 i = 0; i < CraftingOrders.size(); ++i) + { + if (CraftingOrders.HasChanged(i) || ignoreNestedChangesMask) + { + CraftingOrders[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + } } if (changesMask[32]) { - data << int32(XP); + data << FarsightObject; } if (changesMask[33]) { - data << int32(NextLevelXP); + data << SummonedBattlePetGUID; } } if (changesMask[34]) { if (changesMask[35]) { - data << int32(TrialXP); + data << uint64(Coinage); } if (changesMask[36]) { - Skill->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + data << int32(XP); } if (changesMask[37]) { - data << int32(CharacterPoints); + data << int32(NextLevelXP); } if (changesMask[38]) { - data << int32(MaxTalentTiers); + data << int32(TrialXP); } if (changesMask[39]) { - data << uint32(TrackCreatureMask); + Skill->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } if (changesMask[40]) { - data << float(MainhandExpertise); + data << int32(CharacterPoints); } if (changesMask[41]) { - data << float(OffhandExpertise); + data << int32(MaxTalentTiers); } if (changesMask[42]) { - data << float(RangedExpertise); + data << uint32(TrackCreatureMask); } if (changesMask[43]) { - data << float(CombatRatingExpertise); + data << float(MainhandExpertise); } if (changesMask[44]) { - data << float(BlockPercentage); + data << float(OffhandExpertise); } if (changesMask[45]) { - data << float(DodgePercentage); + data << float(RangedExpertise); } if (changesMask[46]) { - data << float(DodgePercentageFromAttribute); + data << float(CombatRatingExpertise); } if (changesMask[47]) { - data << float(ParryPercentage); + data << float(BlockPercentage); } if (changesMask[48]) { - data << float(ParryPercentageFromAttribute); + data << float(DodgePercentage); } if (changesMask[49]) { - data << float(CritPercentage); + data << float(DodgePercentageFromAttribute); } if (changesMask[50]) { - data << float(RangedCritPercentage); + data << float(ParryPercentage); } if (changesMask[51]) { - data << float(OffhandCritPercentage); + data << float(ParryPercentageFromAttribute); } if (changesMask[52]) { - data << float(SpellCritPercentage); + data << float(CritPercentage); } if (changesMask[53]) { - data << int32(ShieldBlock); + data << float(RangedCritPercentage); } if (changesMask[54]) { - data << float(ShieldBlockCritPercentage); + data << float(OffhandCritPercentage); } if (changesMask[55]) { - data << float(Mastery); + data << float(SpellCritPercentage); } if (changesMask[56]) { - data << float(Speed); + data << int32(ShieldBlock); } if (changesMask[57]) { - data << float(Avoidance); + data << float(ShieldBlockCritPercentage); } if (changesMask[58]) { - data << float(Sturdiness); + data << float(Mastery); } if (changesMask[59]) { - data << int32(Versatility); + data << float(Speed); } if (changesMask[60]) { - data << float(VersatilityBonus); + data << float(Avoidance); } if (changesMask[61]) { - data << float(PvpPowerDamage); + data << float(Sturdiness); } if (changesMask[62]) { - data << float(PvpPowerHealing); + data << int32(Versatility); } if (changesMask[63]) { - data << int32(ModHealingDonePos); + data << float(VersatilityBonus); } if (changesMask[64]) { - data << float(ModHealingPercent); + data << float(PvpPowerDamage); } if (changesMask[65]) { - data << float(ModPeriodicHealingDonePercent); + data << float(PvpPowerHealing); } } if (changesMask[66]) { if (changesMask[67]) { - data << float(ModSpellPowerPercent); + data << int32(ModHealingDonePos); } if (changesMask[68]) { - data << float(ModResiliencePercent); + data << float(ModHealingPercent); } if (changesMask[69]) { - data << float(OverrideSpellPowerByAPPercent); + data << float(ModPeriodicHealingDonePercent); } if (changesMask[70]) { - data << float(OverrideAPBySpellPowerPercent); + data << float(ModSpellPowerPercent); } if (changesMask[71]) { - data << int32(ModTargetResistance); + data << float(ModResiliencePercent); } if (changesMask[72]) { - data << int32(ModTargetPhysicalResistance); + data << float(OverrideSpellPowerByAPPercent); } if (changesMask[73]) { - data << uint32(LocalFlags); + data << float(OverrideAPBySpellPowerPercent); } if (changesMask[74]) { - data << uint8(GrantableLevels); + data << int32(ModTargetResistance); } if (changesMask[75]) { - data << uint8(MultiActionBars); + data << int32(ModTargetPhysicalResistance); } if (changesMask[76]) { - data << uint8(LifetimeMaxRank); + data << uint32(LocalFlags); } if (changesMask[77]) { - data << uint8(NumRespecs); + data << uint8(GrantableLevels); } if (changesMask[78]) { - data << uint32(PvpMedals); + data << uint8(MultiActionBars); } if (changesMask[79]) { - data << uint16(TodayHonorableKills); + data << uint8(LifetimeMaxRank); } if (changesMask[80]) { - data << uint16(YesterdayHonorableKills); + data << uint8(NumRespecs); } if (changesMask[81]) { - data << uint32(LifetimeHonorableKills); + data << uint32(PvpMedals); } if (changesMask[82]) { - data << int32(WatchedFactionIndex); + data << uint16(TodayHonorableKills); } if (changesMask[83]) { - data << int32(MaxLevel); + data << uint16(YesterdayHonorableKills); } if (changesMask[84]) { - data << int32(ScalingPlayerLevelDelta); + data << uint32(LifetimeHonorableKills); } if (changesMask[85]) { - data << int32(MaxCreatureScalingLevel); + data << int32(WatchedFactionIndex); } if (changesMask[86]) { - data << int32(PetSpellPower); + data << int32(MaxLevel); } if (changesMask[87]) { - data << float(UiHitModifier); + data << int32(ScalingPlayerLevelDelta); } if (changesMask[88]) { - data << float(UiSpellHitModifier); + data << int32(MaxCreatureScalingLevel); } if (changesMask[89]) { - data << int32(HomeRealmTimeOffset); + data << int32(PetSpellPower); } if (changesMask[90]) { - data << float(ModPetHaste); + data << float(UiHitModifier); } if (changesMask[91]) { - data << int8(JailersTowerLevelMax); + data << float(UiSpellHitModifier); } if (changesMask[92]) { - data << int8(JailersTowerLevel); + data << int32(HomeRealmTimeOffset); } if (changesMask[93]) { - data << uint8(LocalRegenFlags); + data << float(ModPetHaste); } if (changesMask[94]) { - data << uint8(AuraVision); + data << int8(JailersTowerLevelMax); } if (changesMask[95]) { - data << uint8(NumBackpackSlots); + data << int8(JailersTowerLevel); } if (changesMask[96]) { - data << int32(OverrideSpellsID); + data << uint8(LocalRegenFlags); } if (changesMask[97]) { - data << uint16(LootSpecID); + data << uint8(AuraVision); } } if (changesMask[98]) { if (changesMask[99]) { - data << uint32(OverrideZonePVPType); + data << uint8(NumBackpackSlots); } if (changesMask[100]) { - data << BnetAccount; + data << int32(OverrideSpellsID); } if (changesMask[101]) { - data << uint64(GuildClubMemberID); + data << uint16(LootSpecID); } if (changesMask[102]) { - data << int32(Honor); + data << uint32(OverrideZonePVPType); } if (changesMask[103]) { - data << int32(HonorNextLevel); + data << BnetAccount; } if (changesMask[104]) { - data << uint8(NumBankSlots); + data << uint64(GuildClubMemberID); + } + if (changesMask[105]) + { + data << int32(Honor); + } + if (changesMask[106]) + { + data << int32(HonorNextLevel); } if (changesMask[107]) { + data << uint8(NumBankSlots); + } + if (changesMask[110]) + { data << int32(UiChromieTimeExpansionID); } - if (changesMask[108]) + if (changesMask[111]) { data << int32(TransportServerTime); } - if (changesMask[109]) + if (changesMask[112]) { data << uint32(WeeklyRewardsPeriodSinceOrigin); } - if (changesMask[110]) + if (changesMask[113]) { data << int16(DEBUGSoulbindConduitRank); } + if (changesMask[115]) + { + data << uint32(ActiveCombatTraitConfigID); + } } if (changesMask[98]) { data.WriteBits(QuestSession.has_value(), 1); - if (changesMask[106]) + if (changesMask[109]) { Field_1410->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[105]) + if (changesMask[108]) { if (QuestSession.has_value()) { QuestSession->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } - if (changesMask[111]) + if (changesMask[114]) { data << DungeonScore; } } - if (changesMask[112]) + if (changesMask[116]) { - for (uint32 i = 0; i < 199; ++i) + for (uint32 i = 0; i < 218; ++i) { - if (changesMask[113 + i]) + if (changesMask[117 + i]) { data << InvSlots[i]; } } } - if (changesMask[312]) + if (changesMask[335]) { for (uint32 i = 0; i < 240; ++i) { - if (changesMask[313 + i]) + if (changesMask[336 + i]) { data << uint64(ExploredZones[i]); } } } - if (changesMask[553]) + if (changesMask[576]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[554 + i]) + if (changesMask[577 + i]) { RestInfo[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } } } - if (changesMask[556]) + if (changesMask[579]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[557 + i]) + if (changesMask[580 + i]) { data << int32(ModDamageDonePos[i]); } - if (changesMask[564 + i]) + if (changesMask[587 + i]) { data << int32(ModDamageDoneNeg[i]); } - if (changesMask[571 + i]) + if (changesMask[594 + i]) { data << float(ModDamageDonePercent[i]); } - if (changesMask[578 + i]) + if (changesMask[601 + i]) { data << float(ModHealingDonePercent[i]); } } } - if (changesMask[585]) + if (changesMask[608]) { for (uint32 i = 0; i < 3; ++i) { - if (changesMask[586 + i]) + if (changesMask[609 + i]) { data << float(WeaponDmgMultipliers[i]); } - if (changesMask[589 + i]) + if (changesMask[612 + i]) { data << float(WeaponAtkSpeedMultipliers[i]); } } } - if (changesMask[592]) + if (changesMask[615]) { for (uint32 i = 0; i < 12; ++i) { - if (changesMask[593 + i]) + if (changesMask[616 + i]) { data << uint32(BuybackPrice[i]); } - if (changesMask[605 + i]) + if (changesMask[628 + i]) { data << int64(BuybackTimestamp[i]); } } } - if (changesMask[617]) + if (changesMask[640]) { for (uint32 i = 0; i < 32; ++i) { - if (changesMask[618 + i]) + if (changesMask[641 + i]) { data << int32(CombatRatings[i]); } } } - if (changesMask[657]) + if (changesMask[673]) { for (uint32 i = 0; i < 4; ++i) { - if (changesMask[658 + i]) + if (changesMask[674 + i]) { data << uint32(NoReagentCostMask[i]); } } } - if (changesMask[662]) + if (changesMask[678]) { for (uint32 i = 0; i < 2; ++i) { - if (changesMask[663 + i]) + if (changesMask[679 + i]) { data << int32(ProfessionSkillLine[i]); } } } - if (changesMask[665]) + if (changesMask[681]) { - for (uint32 i = 0; i < 4; ++i) + for (uint32 i = 0; i < 5; ++i) { - if (changesMask[666 + i]) + if (changesMask[682 + i]) { data << uint32(BagSlotFlags[i]); } } } - if (changesMask[670]) + if (changesMask[687]) { for (uint32 i = 0; i < 7; ++i) { - if (changesMask[671 + i]) + if (changesMask[688 + i]) { data << uint32(BankBagSlotFlags[i]); } } } - if (changesMask[678]) + if (changesMask[695]) { for (uint32 i = 0; i < 875; ++i) { - if (changesMask[679 + i]) + if (changesMask[696 + i]) { data << uint64(QuestCompleted[i]); } } } - if (changesMask[650]) - { - for (uint32 i = 0; i < 6; ++i) - { - if (changesMask[651 + i]) - { - PvpInfo[i].WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); - } - } - } data.FlushBits(); } @@ -4147,7 +4777,10 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(RecipeProgression); Base::ClearChangesMask(ReplayedQuests); Base::ClearChangesMask(DisabledSpells); + Base::ClearChangesMask(PvpInfo); Base::ClearChangesMask(CharacterRestrictions); + Base::ClearChangesMask(TraitConfigs); + Base::ClearChangesMask(CraftingOrders); Base::ClearChangesMask(FarsightObject); Base::ClearChangesMask(SummonedBattlePetGUID); Base::ClearChangesMask(Coinage); @@ -4228,6 +4861,7 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(WeeklyRewardsPeriodSinceOrigin); Base::ClearChangesMask(DEBUGSoulbindConduitRank); Base::ClearChangesMask(DungeonScore); + Base::ClearChangesMask(ActiveCombatTraitConfigID); Base::ClearChangesMask(InvSlots); Base::ClearChangesMask(ExploredZones); Base::ClearChangesMask(RestInfo); @@ -4240,7 +4874,6 @@ void ActivePlayerData::ClearChangesMask() Base::ClearChangesMask(BuybackPrice); Base::ClearChangesMask(BuybackTimestamp); Base::ClearChangesMask(CombatRatings); - Base::ClearChangesMask(PvpInfo); Base::ClearChangesMask(NoReagentCostMask); Base::ClearChangesMask(ProfessionSkillLine); Base::ClearChangesMask(BagSlotFlags); @@ -4278,10 +4911,18 @@ void GameObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie data << uint32(CustomParam); data << int32(Level); data << uint32(AnimGroupInstance); + data << uint32(UiWidgetItemID); + data << uint32(UiWidgetItemQuality); + data << uint32(UiWidgetItemUnknown1000); + data << uint32(WorldEffects.size()); for (uint32 i = 0; i < EnableDoodadSets.size(); ++i) { data << int32(EnableDoodadSets[i]); } + for (uint32 i = 0; i < WorldEffects.size(); ++i) + { + data << int32(WorldEffects[i]); + } } void GameObjectData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const @@ -4291,7 +4932,7 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, GameObject const* owner, Player const* receiver) const { - data.WriteBits(changesMask.GetBlock(0), 21); + data.WriteBits(changesMask.GetBlock(0), 25); if (changesMask[0]) { @@ -4314,6 +4955,13 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool else WriteCompleteDynamicFieldUpdateMask(EnableDoodadSets.size(), data); } + if (changesMask[3]) + { + if (!ignoreNestedChangesMask) + WorldEffects.WriteUpdateMask(data); + else + WriteCompleteDynamicFieldUpdateMask(WorldEffects.size(), data); + } } data.FlushBits(); if (changesMask[0]) @@ -4330,79 +4978,101 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool } if (changesMask[3]) { - data << int32(DisplayID); + for (uint32 i = 0; i < WorldEffects.size(); ++i) + { + if (WorldEffects.HasChanged(i) || ignoreNestedChangesMask) + { + data << int32(WorldEffects[i]); + } + } } if (changesMask[4]) { - data << uint32(SpellVisualID); + data << int32(DisplayID); } if (changesMask[5]) { - data << uint32(StateSpellVisualID); + data << uint32(SpellVisualID); } if (changesMask[6]) { - data << uint32(SpawnTrackingStateAnimID); + data << uint32(StateSpellVisualID); } if (changesMask[7]) { - data << uint32(SpawnTrackingStateAnimKitID); + data << uint32(SpawnTrackingStateAnimID); } if (changesMask[8]) { - data << uint32(StateWorldEffectsQuestObjectiveID); + data << uint32(SpawnTrackingStateAnimKitID); } if (changesMask[9]) { - data << CreatedBy; + data << uint32(StateWorldEffectsQuestObjectiveID); } if (changesMask[10]) { - data << GuildGUID; + data << CreatedBy; } if (changesMask[11]) { - data << uint32(ViewerDependentValue<FlagsTag>::GetValue(this, owner, receiver)); + data << GuildGUID; } if (changesMask[12]) { + data << uint32(ViewerDependentValue<FlagsTag>::GetValue(this, owner, receiver)); + } + if (changesMask[13]) + { data << float(ParentRotation->x); data << float(ParentRotation->y); data << float(ParentRotation->z); data << float(ParentRotation->w); } - if (changesMask[13]) + if (changesMask[14]) { data << int32(FactionTemplate); } - if (changesMask[14]) + if (changesMask[15]) { data << int8(ViewerDependentValue<StateTag>::GetValue(this, owner, receiver)); } - if (changesMask[15]) + if (changesMask[16]) { data << int8(TypeID); } - if (changesMask[16]) + if (changesMask[17]) { data << uint8(PercentHealth); } - if (changesMask[17]) + if (changesMask[18]) { data << uint32(ArtKit); } - if (changesMask[18]) + if (changesMask[19]) { data << uint32(CustomParam); } - if (changesMask[19]) + if (changesMask[20]) { data << int32(Level); } - if (changesMask[20]) + if (changesMask[21]) { data << uint32(AnimGroupInstance); } + if (changesMask[22]) + { + data << uint32(UiWidgetItemID); + } + if (changesMask[23]) + { + data << uint32(UiWidgetItemQuality); + } + if (changesMask[24]) + { + data << uint32(UiWidgetItemUnknown1000); + } } } @@ -4410,6 +5080,7 @@ void GameObjectData::ClearChangesMask() { Base::ClearChangesMask(StateWorldEffectIDs); Base::ClearChangesMask(EnableDoodadSets); + Base::ClearChangesMask(WorldEffects); Base::ClearChangesMask(DisplayID); Base::ClearChangesMask(SpellVisualID); Base::ClearChangesMask(StateSpellVisualID); @@ -4428,6 +5099,9 @@ void GameObjectData::ClearChangesMask() Base::ClearChangesMask(CustomParam); Base::ClearChangesMask(Level); Base::ClearChangesMask(AnimGroupInstance); + Base::ClearChangesMask(UiWidgetItemID); + Base::ClearChangesMask(UiWidgetItemQuality); + Base::ClearChangesMask(UiWidgetItemUnknown1000); _changesMask.ResetAll(); } @@ -4746,6 +5420,7 @@ void AreaTriggerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi data << uint32(TimeToTarget); data << uint32(TimeToTargetScale); data << uint32(TimeToTargetExtraScale); + data << uint32(Field_B0); data << int32(SpellID); data << int32(SpellForVisuals); SpellVisual->WriteCreate(data, owner, receiver); @@ -4755,7 +5430,11 @@ void AreaTriggerData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi data << uint32(Field_80); data << uint32(Field_84); data << Field_88; + data << Field_F8; ExtraScaleCurve->WriteCreate(data, owner, receiver); + Field_C38->WriteCreate(data, owner, receiver); + Field_C54->WriteCreate(data, owner, receiver); + Field_C70->WriteCreate(data, owner, receiver); VisualAnim->WriteCreate(data, owner, receiver); } @@ -4766,7 +5445,7 @@ void AreaTriggerData::WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fi void AreaTriggerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignoreNestedChangesMask, AreaTrigger const* owner, Player const* receiver) const { - data.WriteBits(changesMask.GetBlock(0), 18); + data.WriteBits(changesMask.GetBlock(0), 23); data.FlushBits(); if (changesMask[0]) @@ -4775,67 +5454,87 @@ void AreaTriggerData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, boo { OverrideScaleCurve->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[3]) + if (changesMask[6]) { data << Caster; } - if (changesMask[4]) + if (changesMask[7]) { data << uint32(Duration); } - if (changesMask[5]) + if (changesMask[8]) { data << uint32(TimeToTarget); } - if (changesMask[6]) + if (changesMask[9]) { data << uint32(TimeToTargetScale); } - if (changesMask[7]) + if (changesMask[10]) { data << uint32(TimeToTargetExtraScale); } - if (changesMask[8]) + if (changesMask[11]) + { + data << uint32(Field_B0); + } + if (changesMask[12]) { data << int32(SpellID); } - if (changesMask[9]) + if (changesMask[13]) { data << int32(SpellForVisuals); } - if (changesMask[10]) + if (changesMask[14]) { SpellVisual->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[11]) + if (changesMask[15]) { data << float(BoundsRadius2D); } - if (changesMask[12]) + if (changesMask[16]) { data << uint32(DecalPropertiesID); } - if (changesMask[13]) + if (changesMask[17]) { data << CreatingEffectGUID; } - if (changesMask[14]) + if (changesMask[18]) { data << uint32(Field_80); } - if (changesMask[15]) + if (changesMask[19]) { data << uint32(Field_84); } - if (changesMask[16]) + if (changesMask[20]) { data << Field_88; } + if (changesMask[21]) + { + data << Field_F8; + } if (changesMask[2]) { ExtraScaleCurve->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } - if (changesMask[17]) + if (changesMask[3]) + { + Field_C38->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (changesMask[4]) + { + Field_C54->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (changesMask[5]) + { + Field_C70->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); + } + if (changesMask[22]) { VisualAnim->WriteUpdate(data, ignoreNestedChangesMask, owner, receiver); } @@ -4846,11 +5545,15 @@ void AreaTriggerData::ClearChangesMask() { Base::ClearChangesMask(OverrideScaleCurve); Base::ClearChangesMask(ExtraScaleCurve); + Base::ClearChangesMask(Field_C38); + Base::ClearChangesMask(Field_C54); + Base::ClearChangesMask(Field_C70); Base::ClearChangesMask(Caster); Base::ClearChangesMask(Duration); Base::ClearChangesMask(TimeToTarget); Base::ClearChangesMask(TimeToTargetScale); Base::ClearChangesMask(TimeToTargetExtraScale); + Base::ClearChangesMask(Field_B0); Base::ClearChangesMask(SpellID); Base::ClearChangesMask(SpellForVisuals); Base::ClearChangesMask(SpellVisual); @@ -4860,6 +5563,7 @@ void AreaTriggerData::ClearChangesMask() Base::ClearChangesMask(Field_80); Base::ClearChangesMask(Field_84); Base::ClearChangesMask(Field_88); + Base::ClearChangesMask(Field_F8); Base::ClearChangesMask(VisualAnim); _changesMask.ResetAll(); } diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index 1d6d1499df8..a075a11ab81 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -19,6 +19,7 @@ #define UpdateFields_h__ #include "EnumFlag.h" +#include "ItemPacketsCommon.h" #include "MythicPlusPacketsCommon.h" #include "ObjectGuid.h" #include "Position.h" @@ -115,25 +116,25 @@ struct SocketedGem : public IsUpdateFieldStructureTag, public HasChangesMask<20> struct ItemData : public IsUpdateFieldStructureTag, public HasChangesMask<41> { - UpdateField<std::vector<int32>, 0, 1> BonusListIDs; - DynamicUpdateField<UF::ArtifactPower, 0, 2> ArtifactPowers; - DynamicUpdateField<UF::SocketedGem, 0, 3> Gems; - UpdateField<ObjectGuid, 0, 4> Owner; - UpdateField<ObjectGuid, 0, 5> ContainedIn; - UpdateField<ObjectGuid, 0, 6> Creator; - UpdateField<ObjectGuid, 0, 7> GiftCreator; - UpdateField<uint32, 0, 8> StackCount; - UpdateField<uint32, 0, 9> Expiration; - UpdateField<uint32, 0, 10> DynamicFlags; - UpdateField<uint32, 0, 11> Durability; - UpdateField<uint32, 0, 12> MaxDurability; - UpdateField<uint32, 0, 13> CreatePlayedTime; - UpdateField<int32, 0, 14> Context; - UpdateField<int64, 0, 15> CreateTime; - UpdateField<uint64, 0, 16> ArtifactXP; - UpdateField<uint8, 0, 17> ItemAppearanceModID; - UpdateField<UF::ItemModList, 0, 18> Modifiers; - UpdateField<uint32, 0, 19> DynamicFlags2; + DynamicUpdateField<UF::ArtifactPower, 0, 1> ArtifactPowers; + DynamicUpdateField<UF::SocketedGem, 0, 2> Gems; + UpdateField<ObjectGuid, 0, 3> Owner; + UpdateField<ObjectGuid, 0, 4> ContainedIn; + UpdateField<ObjectGuid, 0, 5> Creator; + UpdateField<ObjectGuid, 0, 6> GiftCreator; + UpdateField<uint32, 0, 7> StackCount; + UpdateField<uint32, 0, 8> Expiration; + UpdateField<uint32, 0, 9> DynamicFlags; + UpdateField<uint32, 0, 10> Durability; + UpdateField<uint32, 0, 11> MaxDurability; + UpdateField<uint32, 0, 12> CreatePlayedTime; + UpdateField<int32, 0, 13> Context; + UpdateField<int64, 0, 14> CreateTime; + UpdateField<uint64, 0, 15> ArtifactXP; + UpdateField<uint8, 0, 16> ItemAppearanceModID; + UpdateField<UF::ItemModList, 0, 17> Modifiers; + UpdateField<uint32, 0, 18> DynamicFlags2; + UpdateField<WorldPackets::Item::ItemBonusKey, 0, 19> ItemBonusKey; UpdateField<uint16, 0, 20> DEBUGItemLevel; UpdateFieldArray<int32, 5, 21, 22> SpellCharges; UpdateFieldArray<UF::ItemEnchantment, 13, 27, 28> Enchantment; @@ -254,7 +255,7 @@ struct PassiveSpellHistory : public IsUpdateFieldStructureTag bool operator!=(PassiveSpellHistory const& right) const { return !(*this == right); } }; -struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<194> +struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<196> { UpdateField<std::vector<uint32>, 0, 1> StateWorldEffectIDs; DynamicUpdateField<UF::PassiveSpellHistory, 0, 2> PassiveSpells; @@ -279,119 +280,121 @@ struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<194> UpdateField<ObjectGuid, 0, 20> BattlePetCompanionGUID; UpdateField<uint64, 0, 21> BattlePetDBID; UpdateField<UF::UnitChannel, 0, 22> ChannelData; - UpdateField<uint32, 0, 23> SummonedByHomeRealm; - UpdateField<uint8, 0, 24> Race; - UpdateField<uint8, 0, 25> ClassId; - UpdateField<uint8, 0, 26> PlayerClassId; - UpdateField<uint8, 0, 27> Sex; - UpdateField<uint8, 0, 28> DisplayPower; - UpdateField<uint32, 0, 29> OverrideDisplayPowerID; - UpdateField<int64, 0, 30> Health; - UpdateField<int64, 0, 31> MaxHealth; - UpdateField<int32, 32, 33> Level; - UpdateField<int32, 32, 34> EffectiveLevel; - UpdateField<int32, 32, 35> ContentTuningID; - UpdateField<int32, 32, 36> ScalingLevelMin; - UpdateField<int32, 32, 37> ScalingLevelMax; - UpdateField<int32, 32, 38> ScalingLevelDelta; - UpdateField<int32, 32, 39> ScalingFactionGroup; - UpdateField<int32, 32, 40> ScalingHealthItemLevelCurveID; - UpdateField<int32, 32, 41> ScalingDamageItemLevelCurveID; - UpdateField<int32, 32, 42> FactionTemplate; + UpdateField<int8, 0, 23> SpellEmpowerStage; + UpdateField<uint32, 0, 24> SummonedByHomeRealm; + UpdateField<uint8, 0, 25> Race; + UpdateField<uint8, 0, 26> ClassId; + UpdateField<uint8, 0, 27> PlayerClassId; + UpdateField<uint8, 0, 28> Sex; + UpdateField<uint8, 0, 29> DisplayPower; + UpdateField<uint32, 0, 30> OverrideDisplayPowerID; + UpdateField<int64, 0, 31> Health; + UpdateField<int64, 32, 33> MaxHealth; + UpdateField<int32, 32, 34> Level; + UpdateField<int32, 32, 35> EffectiveLevel; + UpdateField<int32, 32, 36> ContentTuningID; + UpdateField<int32, 32, 37> ScalingLevelMin; + UpdateField<int32, 32, 38> ScalingLevelMax; + UpdateField<int32, 32, 39> ScalingLevelDelta; + UpdateField<int32, 32, 40> ScalingFactionGroup; + UpdateField<int32, 32, 41> ScalingHealthItemLevelCurveID; + UpdateField<int32, 32, 42> ScalingDamageItemLevelCurveID; + UpdateField<int32, 32, 43> FactionTemplate; struct FactionTemplateTag : ViewerDependentValueTag<int32> {}; - UpdateField<uint32, 32, 43> Flags; + UpdateField<uint32, 32, 44> Flags; struct FlagsTag : ViewerDependentValueTag<uint32> {}; - UpdateField<uint32, 32, 44> Flags2; - UpdateField<uint32, 32, 45> Flags3; + UpdateField<uint32, 32, 45> Flags2; + UpdateField<uint32, 32, 46> Flags3; struct Flags3Tag : ViewerDependentValueTag<uint32> {}; - UpdateField<uint32, 32, 46> AuraState; + UpdateField<uint32, 32, 47> AuraState; struct AuraStateTag : ViewerDependentValueTag<uint32> {}; - UpdateField<uint32, 32, 47> RangedAttackRoundBaseTime; - UpdateField<float, 32, 48> BoundingRadius; - UpdateField<float, 32, 49> CombatReach; - UpdateField<float, 32, 50> DisplayScale; - UpdateField<int32, 32, 51> CreatureFamily; - UpdateField<int32, 32, 52> CreatureType; - UpdateField<int32, 32, 53> NativeDisplayID; - UpdateField<float, 32, 54> NativeXDisplayScale; - UpdateField<int32, 32, 55> MountDisplayID; - UpdateField<int32, 32, 56> CosmeticMountDisplayID; - UpdateField<float, 32, 57> MinDamage; - UpdateField<float, 32, 58> MaxDamage; - UpdateField<float, 32, 59> MinOffHandDamage; - UpdateField<float, 32, 60> MaxOffHandDamage; - UpdateField<uint8, 32, 61> StandState; - UpdateField<uint8, 32, 62> PetTalentPoints; - UpdateField<uint8, 32, 63> VisFlags; - UpdateField<uint8, 64, 65> AnimTier; - UpdateField<uint32, 64, 66> PetNumber; - UpdateField<uint32, 64, 67> PetNameTimestamp; - UpdateField<uint32, 64, 68> PetExperience; - UpdateField<uint32, 64, 69> PetNextLevelExperience; - UpdateField<float, 64, 70> ModCastingSpeed; - UpdateField<float, 64, 71> ModCastingSpeedNeg; - UpdateField<float, 64, 72> ModSpellHaste; - UpdateField<float, 64, 73> ModHaste; - UpdateField<float, 64, 74> ModRangedHaste; - UpdateField<float, 64, 75> ModHasteRegen; - UpdateField<float, 64, 76> ModTimeRate; - UpdateField<int32, 64, 77> CreatedBySpell; - UpdateField<int32, 64, 78> EmoteState; - UpdateField<int32, 64, 79> BaseMana; - UpdateField<int32, 64, 80> BaseHealth; - UpdateField<uint8, 64, 81> SheatheState; - UpdateField<uint8, 64, 82> PvpFlags; + UpdateField<uint32, 32, 48> RangedAttackRoundBaseTime; + UpdateField<float, 32, 49> BoundingRadius; + UpdateField<float, 32, 50> CombatReach; + UpdateField<float, 32, 51> DisplayScale; + UpdateField<int32, 32, 52> CreatureFamily; + UpdateField<int32, 32, 53> CreatureType; + UpdateField<int32, 32, 54> NativeDisplayID; + UpdateField<float, 32, 55> NativeXDisplayScale; + UpdateField<int32, 32, 56> MountDisplayID; + UpdateField<int32, 32, 57> CosmeticMountDisplayID; + UpdateField<float, 32, 58> MinDamage; + UpdateField<float, 32, 59> MaxDamage; + UpdateField<float, 32, 60> MinOffHandDamage; + UpdateField<float, 32, 61> MaxOffHandDamage; + UpdateField<uint8, 32, 62> StandState; + UpdateField<uint8, 32, 63> PetTalentPoints; + UpdateField<uint8, 64, 65> VisFlags; + UpdateField<uint8, 64, 66> AnimTier; + UpdateField<uint32, 64, 67> PetNumber; + UpdateField<uint32, 64, 68> PetNameTimestamp; + UpdateField<uint32, 64, 69> PetExperience; + UpdateField<uint32, 64, 70> PetNextLevelExperience; + UpdateField<float, 64, 71> ModCastingSpeed; + UpdateField<float, 64, 72> ModCastingSpeedNeg; + UpdateField<float, 64, 73> ModSpellHaste; + UpdateField<float, 64, 74> ModHaste; + UpdateField<float, 64, 75> ModRangedHaste; + UpdateField<float, 64, 76> ModHasteRegen; + UpdateField<float, 64, 77> ModTimeRate; + UpdateField<int32, 64, 78> CreatedBySpell; + UpdateField<int32, 64, 79> EmoteState; + UpdateField<int32, 64, 80> BaseMana; + UpdateField<int32, 64, 81> BaseHealth; + UpdateField<uint8, 64, 82> SheatheState; + UpdateField<uint8, 64, 83> PvpFlags; struct PvpFlagsTag : ViewerDependentValueTag<uint8> {}; - UpdateField<uint8, 64, 83> PetFlags; - UpdateField<uint8, 64, 84> ShapeshiftForm; - UpdateField<int32, 64, 85> AttackPower; - UpdateField<int32, 64, 86> AttackPowerModPos; - UpdateField<int32, 64, 87> AttackPowerModNeg; - UpdateField<float, 64, 88> AttackPowerMultiplier; - UpdateField<int32, 64, 89> RangedAttackPower; - UpdateField<int32, 64, 90> RangedAttackPowerModPos; - UpdateField<int32, 64, 91> RangedAttackPowerModNeg; - UpdateField<float, 64, 92> RangedAttackPowerMultiplier; - UpdateField<int32, 64, 93> MainHandWeaponAttackPower; - UpdateField<int32, 64, 94> OffHandWeaponAttackPower; - UpdateField<int32, 64, 95> RangedWeaponAttackPower; - UpdateField<int32, 96, 97> SetAttackSpeedAura; - UpdateField<float, 96, 98> Lifesteal; - UpdateField<float, 96, 99> MinRangedDamage; - UpdateField<float, 96, 100> MaxRangedDamage; - UpdateField<float, 96, 101> ManaCostMultiplier; - UpdateField<float, 96, 102> MaxHealthModifier; - UpdateField<float, 96, 103> HoverHeight; - UpdateField<int32, 96, 104> MinItemLevelCutoff; - UpdateField<int32, 96, 105> MinItemLevel; - UpdateField<int32, 96, 106> MaxItemLevel; - UpdateField<int32, 96, 107> AzeriteItemLevel; - UpdateField<int32, 96, 108> WildBattlePetLevel; - UpdateField<int32, 96, 109> BattlePetCompanionExperience; - UpdateField<uint32, 96, 110> BattlePetCompanionNameTimestamp; - UpdateField<int32, 96, 111> InteractSpellID; - UpdateField<int32, 96, 112> ScaleDuration; - UpdateField<int32, 96, 113> LooksLikeMountID; - UpdateField<int32, 96, 114> LooksLikeCreatureID; - UpdateField<int32, 96, 115> LookAtControllerID; - UpdateField<int32, 96, 116> TaxiNodesID; - UpdateField<ObjectGuid, 96, 117> GuildGUID; - UpdateField<uint32, 96, 118> SilencedSchoolMask; - UpdateField<ObjectGuid, 96, 119> NameplateAttachToGUID; // When set, nameplate of this unit will instead appear on that object - UpdateFieldArray<uint32, 2, 120, 121> NpcFlags; + UpdateField<uint8, 64, 84> PetFlags; + UpdateField<uint8, 64, 85> ShapeshiftForm; + UpdateField<int32, 64, 86> AttackPower; + UpdateField<int32, 64, 87> AttackPowerModPos; + UpdateField<int32, 64, 88> AttackPowerModNeg; + UpdateField<float, 64, 89> AttackPowerMultiplier; + UpdateField<int32, 64, 90> RangedAttackPower; + UpdateField<int32, 64, 91> RangedAttackPowerModPos; + UpdateField<int32, 64, 92> RangedAttackPowerModNeg; + UpdateField<float, 64, 93> RangedAttackPowerMultiplier; + UpdateField<int32, 64, 94> MainHandWeaponAttackPower; + UpdateField<int32, 64, 95> OffHandWeaponAttackPower; + UpdateField<int32, 96, 97> RangedWeaponAttackPower; + UpdateField<int32, 96, 98> SetAttackSpeedAura; + UpdateField<float, 96, 99> Lifesteal; + UpdateField<float, 96, 100> MinRangedDamage; + UpdateField<float, 96, 101> MaxRangedDamage; + UpdateField<float, 96, 102> ManaCostMultiplier; + UpdateField<float, 96, 103> MaxHealthModifier; + UpdateField<float, 96, 104> HoverHeight; + UpdateField<int32, 96, 105> MinItemLevelCutoff; + UpdateField<int32, 96, 106> MinItemLevel; + UpdateField<int32, 96, 107> MaxItemLevel; + UpdateField<int32, 96, 108> AzeriteItemLevel; + UpdateField<int32, 96, 109> WildBattlePetLevel; + UpdateField<int32, 96, 110> BattlePetCompanionExperience; + UpdateField<uint32, 96, 111> BattlePetCompanionNameTimestamp; + UpdateField<int32, 96, 112> InteractSpellID; + UpdateField<int32, 96, 113> ScaleDuration; + UpdateField<int32, 96, 114> LooksLikeMountID; + UpdateField<int32, 96, 115> LooksLikeCreatureID; + UpdateField<int32, 96, 116> LookAtControllerID; + UpdateField<int32, 96, 117> TaxiNodesID; + UpdateField<ObjectGuid, 96, 118> GuildGUID; + UpdateField<int32, 96, 119> FlightCapabilityID; + UpdateField<uint32, 96, 120> SilencedSchoolMask; + UpdateField<ObjectGuid, 96, 121> NameplateAttachToGUID; // When set, nameplate of this unit will instead appear on that object + UpdateFieldArray<uint32, 2, 122, 123> NpcFlags; struct NpcFlagsTag : ViewerDependentValueTag<uint32> {}; - UpdateFieldArray<int32, 7, 123, 124> Power; - UpdateFieldArray<int32, 7, 123, 131> MaxPower; - UpdateFieldArray<float, 7, 123, 138> PowerRegenFlatModifier; - UpdateFieldArray<float, 7, 123, 145> PowerRegenInterruptedFlatModifier; - UpdateFieldArray<UF::VisibleItem, 3, 152, 153> VirtualItems; - UpdateFieldArray<uint32, 2, 156, 157> AttackRoundBaseTime; - UpdateFieldArray<int32, 4, 159, 160> Stats; - UpdateFieldArray<int32, 4, 159, 164> StatPosBuff; - UpdateFieldArray<int32, 4, 159, 168> StatNegBuff; - UpdateFieldArray<int32, 7, 172, 173> Resistances; - UpdateFieldArray<int32, 7, 172, 180> BonusResistanceMods; - UpdateFieldArray<int32, 7, 172, 187> ManaCostModifier; + UpdateFieldArray<int32, 7, 125, 126> Power; + UpdateFieldArray<int32, 7, 125, 133> MaxPower; + UpdateFieldArray<float, 7, 125, 140> PowerRegenFlatModifier; + UpdateFieldArray<float, 7, 125, 147> PowerRegenInterruptedFlatModifier; + UpdateFieldArray<UF::VisibleItem, 3, 154, 155> VirtualItems; + UpdateFieldArray<uint32, 2, 158, 159> AttackRoundBaseTime; + UpdateFieldArray<int32, 4, 161, 162> Stats; + UpdateFieldArray<int32, 4, 161, 166> StatPosBuff; + UpdateFieldArray<int32, 4, 161, 170> StatNegBuff; + UpdateFieldArray<int32, 7, 174, 175> Resistances; + UpdateFieldArray<int32, 7, 174, 182> BonusResistanceMods; + UpdateFieldArray<int32, 7, 174, 189> ManaCostModifier; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Unit const* owner, Player const* receiver) const; @@ -453,44 +456,46 @@ struct CTROptions : public IsUpdateFieldStructureTag bool operator!=(CTROptions const& right) const { return !(*this == right); } }; -struct PlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<188> +struct PlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<190> { UpdateField<bool, 0, 1> HasQuestSession; UpdateField<bool, 0, 2> HasLevelLink; DynamicUpdateField<UF::ChrCustomizationChoice, 0, 3> Customizations; DynamicUpdateField<UF::QuestLog, 0, 4> QuestSessionQuestLog; DynamicUpdateField<UF::ArenaCooldown, 0, 5> ArenaCooldowns; - UpdateField<ObjectGuid, 0, 6> DuelArbiter; - UpdateField<ObjectGuid, 0, 7> WowAccount; - UpdateField<ObjectGuid, 0, 8> LootTargetGUID; - UpdateField<uint32, 0, 9> PlayerFlags; - UpdateField<uint32, 0, 10> PlayerFlagsEx; - UpdateField<uint32, 0, 11> GuildRankID; - UpdateField<uint32, 0, 12> GuildDeleteDate; - UpdateField<int32, 0, 13> GuildLevel; - UpdateField<uint8, 0, 14> PartyType; - UpdateField<uint8, 0, 15> NativeSex; - UpdateField<uint8, 0, 16> Inebriation; - UpdateField<uint8, 0, 17> PvpTitle; - UpdateField<uint8, 0, 18> ArenaFaction; - UpdateField<uint32, 0, 19> DuelTeam; - UpdateField<int32, 0, 20> GuildTimeStamp; - UpdateField<int32, 0, 21> PlayerTitle; - UpdateField<int32, 0, 22> FakeInebriation; - UpdateField<uint32, 0, 23> VirtualPlayerRealm; - UpdateField<uint32, 0, 24> CurrentSpecID; - UpdateField<int32, 0, 25> TaxiMountAnimKitID; - UpdateField<uint8, 0, 26> CurrentBattlePetBreedQuality; - UpdateField<int32, 0, 27> HonorLevel; - UpdateField<int32, 0, 28> Field_B0; - UpdateField<int32, 0, 29> Field_B4; - UpdateField<UF::CTROptions, 0, 30> CtrOptions; - UpdateField<int32, 0, 31> CovenantID; - UpdateField<int32, 32, 33> SoulbindID; - UpdateField<WorldPackets::MythicPlus::DungeonScoreSummary, 32, 34> DungeonScore; - UpdateFieldArray<UF::QuestLog, 125, 35, 36> QuestLog; - UpdateFieldArray<UF::VisibleItem, 19, 161, 162> VisibleItems; - UpdateFieldArray<float, 6, 181, 182> AvgItemLevel; + DynamicUpdateField<int32, 0, 6> VisualItemReplacements; + UpdateField<ObjectGuid, 0, 7> DuelArbiter; + UpdateField<ObjectGuid, 0, 8> WowAccount; + UpdateField<ObjectGuid, 0, 9> LootTargetGUID; + UpdateField<uint32, 0, 10> PlayerFlags; + UpdateField<uint32, 0, 11> PlayerFlagsEx; + UpdateField<uint32, 0, 12> GuildRankID; + UpdateField<uint32, 0, 13> GuildDeleteDate; + UpdateField<int32, 0, 14> GuildLevel; + UpdateField<uint8, 0, 15> PartyType; + UpdateField<uint8, 0, 16> NativeSex; + UpdateField<uint8, 0, 17> Inebriation; + UpdateField<uint8, 0, 18> PvpTitle; + UpdateField<uint8, 0, 19> ArenaFaction; + UpdateField<uint32, 0, 20> DuelTeam; + UpdateField<int32, 0, 21> GuildTimeStamp; + UpdateField<int32, 0, 22> PlayerTitle; + UpdateField<int32, 0, 23> FakeInebriation; + UpdateField<uint32, 0, 24> VirtualPlayerRealm; + UpdateField<uint32, 0, 25> CurrentSpecID; + UpdateField<int32, 0, 26> TaxiMountAnimKitID; + UpdateField<uint8, 0, 27> CurrentBattlePetBreedQuality; + UpdateField<int32, 0, 28> HonorLevel; + UpdateField<int64, 0, 29> LogoutTime; + UpdateField<int32, 0, 30> Field_B0; + UpdateField<int32, 0, 31> Field_B4; + UpdateField<UF::CTROptions, 32, 33> CtrOptions; + UpdateField<int32, 32, 34> CovenantID; + UpdateField<int32, 32, 35> SoulbindID; + UpdateField<WorldPackets::MythicPlus::DungeonScoreSummary, 32, 36> DungeonScore; + UpdateFieldArray<UF::QuestLog, 125, 37, 38> QuestLog; + UpdateFieldArray<UF::VisibleItem, 19, 163, 164> VisibleItems; + UpdateFieldArray<float, 6, 183, 184> AvgItemLevel; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; @@ -526,20 +531,26 @@ struct RestInfo : public IsUpdateFieldStructureTag, public HasChangesMask<3> void ClearChangesMask(); }; -struct PVPInfo : public IsUpdateFieldStructureTag, public HasChangesMask<13> +struct PVPInfo : public IsUpdateFieldStructureTag, public HasChangesMask<19> { UpdateField<bool, 0, 1> Disqualified; - UpdateField<uint32, 0, 2> WeeklyPlayed; - UpdateField<uint32, 0, 3> WeeklyWon; - UpdateField<uint32, 0, 4> SeasonPlayed; - UpdateField<uint32, 0, 5> SeasonWon; - UpdateField<uint32, 0, 6> Rating; - UpdateField<uint32, 0, 7> WeeklyBestRating; - UpdateField<uint32, 0, 8> SeasonBestRating; - UpdateField<uint32, 0, 9> PvpTierID; - UpdateField<uint32, 0, 10> WeeklyBestWinPvpTierID; - UpdateField<uint32, 0, 11> Field_28; - UpdateField<uint32, 0, 12> Field_2C; + UpdateField<int8, 0, 2> Bracket; + UpdateField<int32, 0, 3> PvpRatingID; + UpdateField<uint32, 0, 4> WeeklyPlayed; + UpdateField<uint32, 0, 5> WeeklyWon; + UpdateField<uint32, 0, 6> SeasonPlayed; + UpdateField<uint32, 0, 7> SeasonWon; + UpdateField<uint32, 0, 8> Rating; + UpdateField<uint32, 0, 9> WeeklyBestRating; + UpdateField<uint32, 0, 10> SeasonBestRating; + UpdateField<uint32, 0, 11> PvpTierID; + UpdateField<uint32, 0, 12> WeeklyBestWinPvpTierID; + UpdateField<uint32, 0, 13> Field_28; + UpdateField<uint32, 0, 14> Field_2C; + UpdateField<uint32, 0, 15> WeeklyRoundsPlayed; + UpdateField<uint32, 0, 16> WeeklyRoundsWon; + UpdateField<uint32, 0, 17> SeasonRoundsPlayed; + UpdateField<uint32, 0, 18> SeasonRoundsWon; void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; @@ -656,133 +667,220 @@ struct ReplayedQuest : public IsUpdateFieldStructureTag, public HasChangesMask<3 void ClearChangesMask(); }; -struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<1554> +struct TraitEntry : public IsUpdateFieldStructureTag +{ + int32 TraitNodeID; + int32 TraitNodeEntryID; + int32 Rank; + int32 GrantedRanks; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + bool operator==(TraitEntry const& right) const; + bool operator!=(TraitEntry const& right) const { return !(*this == right); } +}; + +struct TraitConfig : public IsUpdateFieldStructureTag, public HasChangesMask<12> +{ + DynamicUpdateField<UF::TraitEntry, 0, 1> Entries; + UpdateField<int32, 0, 2> ID; + UpdateField<std::string, 0, 3> Name; + UpdateField<int32, 4, 5> Type; + UpdateField<int32, 4, 6> SkillLineID; + UpdateField<int32, 4, 7> ChrSpecializationID; + UpdateField<int32, 8, 9> CombatConfigFlags; + UpdateField<int32, 8, 10> LocalIdentifier; + UpdateField<int32, 8, 11> TraitSystemID; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct CraftingOrderItem : public IsUpdateFieldStructureTag, public HasChangesMask<7> +{ + UpdateField<uint64, -1, 0> Field_0; + UpdateField<ObjectGuid, -1, 1> ItemGUID; + UpdateField<ObjectGuid, -1, 2> OwnerGUID; + UpdateField<int32, -1, 3> ItemID; + UpdateField<uint32, -1, 4> Quantity; + UpdateField<int32, -1, 5> ReagentQuality; + OptionalUpdateField<uint8, -1, 6> DataSlotIndex; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct CraftingOrderData : public IsUpdateFieldStructureTag, public HasChangesMask<24> +{ + DynamicUpdateField<UF::CraftingOrderItem, 0, 1> Reagents; + UpdateField<int32, 0, 2> Field_0; + UpdateField<uint64, 0, 3> OrderID; + UpdateField<int32, 0, 4> SkillLineAbilityID; + UpdateField<uint8, 5, 6> OrderState; + UpdateField<uint8, 5, 7> OrderType; + UpdateField<uint8, 5, 8> MinQuality; + UpdateField<int64, 5, 9> ExpirationTime; + UpdateField<int64, 10, 11> ClaimEndTime; + UpdateField<int64, 10, 12> TipAmount; + UpdateField<int64, 10, 13> ConsortiumCut; + UpdateField<uint32, 10, 14> Flags; + UpdateField<ObjectGuid, 15, 16> CustomerGUID; + UpdateField<ObjectGuid, 15, 17> CustomerAccountGUID; + UpdateField<ObjectGuid, 15, 18> CrafterGUID; + UpdateField<ObjectGuid, 15, 19> PersonalCrafterGUID; + UpdateField<std::string, 20, 21> CustomerNotes; + OptionalUpdateField<UF::CraftingOrderItem, 20, 22> OutputItem; + OptionalUpdateField<WorldPackets::Item::ItemInstance, 20, 23> OutputItemData; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct CraftingOrder : public IsUpdateFieldStructureTag, public HasChangesMask<4> +{ + DynamicUpdateField<WorldPackets::Item::ItemEnchantData, -1, 0> Enchantments; + DynamicUpdateField<WorldPackets::Item::ItemGemData, -1, 1> Gems; + UpdateField<UF::CraftingOrderData, -1, 2> Data; + OptionalUpdateField<WorldPackets::Item::ItemInstance, -1, 3> RecraftItemInfo; + + void WriteCreate(ByteBuffer& data, Player const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, bool ignoreChangesMask, Player const* owner, Player const* receiver) const; + void ClearChangesMask(); +}; + +struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMask<1571> { UpdateField<bool, 0, 1> BackpackAutoSortDisabled; UpdateField<bool, 0, 2> BankAutoSortDisabled; UpdateField<bool, 0, 3> SortBagsRightToLeft; UpdateField<bool, 0, 4> InsertItemsLeftToRight; - UpdateFieldArray<DynamicUpdateFieldBase<UF::Research>, 1, 27, 28> Research; + UpdateFieldArray<DynamicUpdateFieldBase<UF::Research>, 1, 30, 31> Research; DynamicUpdateField<uint64, 0, 5> KnownTitles; - DynamicUpdateField<uint16, 0, 6> ResearchSites; - DynamicUpdateField<uint32, 0, 7> ResearchSiteProgress; - DynamicUpdateField<int32, 0, 8> DailyQuestsCompleted; - DynamicUpdateField<int32, 0, 9> AvailableQuestLineXQuestIDs; - DynamicUpdateField<int32, 0, 10> Heirlooms; - DynamicUpdateField<uint32, 0, 11> HeirloomFlags; - DynamicUpdateField<int32, 0, 12> Toys; - DynamicUpdateField<uint32, 0, 13> ToyFlags; - DynamicUpdateField<uint32, 0, 14> Transmog; - DynamicUpdateField<int32, 0, 15> ConditionalTransmog; - DynamicUpdateField<int32, 0, 16> SelfResSpells; - DynamicUpdateField<uint32, 0, 17> RuneforgePowers; - DynamicUpdateField<uint32, 0, 18> TransmogIllusions; - DynamicUpdateField<UF::SpellPctModByLabel, 0, 20> SpellPctModByLabel; - DynamicUpdateField<UF::SpellFlatModByLabel, 0, 21> SpellFlatModByLabel; - DynamicUpdateField<UF::MawPower, 0, 22> MawPowers; - DynamicUpdateField<UF::MultiFloorExplore, 0, 23> MultiFloorExploration; - DynamicUpdateField<UF::RecipeProgressionInfo, 0, 24> RecipeProgression; - DynamicUpdateField<UF::ReplayedQuest, 0, 25> ReplayedQuests; - DynamicUpdateField<int32, 0, 26> DisabledSpells; - DynamicUpdateField<UF::CharacterRestriction, 0, 19> CharacterRestrictions; - UpdateField<ObjectGuid, 0, 29> FarsightObject; - UpdateField<ObjectGuid, 0, 30> SummonedBattlePetGUID; - UpdateField<uint64, 0, 31> Coinage; - UpdateField<int32, 0, 32> XP; - UpdateField<int32, 0, 33> NextLevelXP; - UpdateField<int32, 34, 35> TrialXP; - UpdateField<UF::SkillInfo, 34, 36> Skill; - UpdateField<int32, 34, 37> CharacterPoints; - UpdateField<int32, 34, 38> MaxTalentTiers; - UpdateField<uint32, 34, 39> TrackCreatureMask; - UpdateField<float, 34, 40> MainhandExpertise; - UpdateField<float, 34, 41> OffhandExpertise; - UpdateField<float, 34, 42> RangedExpertise; - UpdateField<float, 34, 43> CombatRatingExpertise; - UpdateField<float, 34, 44> BlockPercentage; - UpdateField<float, 34, 45> DodgePercentage; - UpdateField<float, 34, 46> DodgePercentageFromAttribute; - UpdateField<float, 34, 47> ParryPercentage; - UpdateField<float, 34, 48> ParryPercentageFromAttribute; - UpdateField<float, 34, 49> CritPercentage; - UpdateField<float, 34, 50> RangedCritPercentage; - UpdateField<float, 34, 51> OffhandCritPercentage; - UpdateField<float, 34, 52> SpellCritPercentage; - UpdateField<int32, 34, 53> ShieldBlock; - UpdateField<float, 34, 54> ShieldBlockCritPercentage; - UpdateField<float, 34, 55> Mastery; - UpdateField<float, 34, 56> Speed; - UpdateField<float, 34, 57> Avoidance; - UpdateField<float, 34, 58> Sturdiness; - UpdateField<int32, 34, 59> Versatility; - UpdateField<float, 34, 60> VersatilityBonus; - UpdateField<float, 34, 61> PvpPowerDamage; - UpdateField<float, 34, 62> PvpPowerHealing; - UpdateField<int32, 34, 63> ModHealingDonePos; - UpdateField<float, 34, 64> ModHealingPercent; - UpdateField<float, 34, 65> ModPeriodicHealingDonePercent; - UpdateField<float, 66, 67> ModSpellPowerPercent; - UpdateField<float, 66, 68> ModResiliencePercent; - UpdateField<float, 66, 69> OverrideSpellPowerByAPPercent; - UpdateField<float, 66, 70> OverrideAPBySpellPowerPercent; - UpdateField<int32, 66, 71> ModTargetResistance; - UpdateField<int32, 66, 72> ModTargetPhysicalResistance; - UpdateField<uint32, 66, 73> LocalFlags; - UpdateField<uint8, 66, 74> GrantableLevels; - UpdateField<uint8, 66, 75> MultiActionBars; - UpdateField<uint8, 66, 76> LifetimeMaxRank; - UpdateField<uint8, 66, 77> NumRespecs; - UpdateField<uint32, 66, 78> PvpMedals; - UpdateField<uint16, 66, 79> TodayHonorableKills; - UpdateField<uint16, 66, 80> YesterdayHonorableKills; - UpdateField<uint32, 66, 81> LifetimeHonorableKills; - UpdateField<int32, 66, 82> WatchedFactionIndex; - UpdateField<int32, 66, 83> MaxLevel; - UpdateField<int32, 66, 84> ScalingPlayerLevelDelta; - UpdateField<int32, 66, 85> MaxCreatureScalingLevel; - UpdateField<int32, 66, 86> PetSpellPower; - UpdateField<float, 66, 87> UiHitModifier; - UpdateField<float, 66, 88> UiSpellHitModifier; - UpdateField<int32, 66, 89> HomeRealmTimeOffset; - UpdateField<float, 66, 90> ModPetHaste; - UpdateField<int8, 66, 91> JailersTowerLevelMax; - UpdateField<int8, 66, 92> JailersTowerLevel; - UpdateField<uint8, 66, 93> LocalRegenFlags; - UpdateField<uint8, 66, 94> AuraVision; - UpdateField<uint8, 66, 95> NumBackpackSlots; - UpdateField<int32, 66, 96> OverrideSpellsID; - UpdateField<uint16, 66, 97> LootSpecID; - UpdateField<uint32, 98, 99> OverrideZonePVPType; - UpdateField<ObjectGuid, 98, 100> BnetAccount; - UpdateField<uint64, 98, 101> GuildClubMemberID; - UpdateField<int32, 98, 102> Honor; - UpdateField<int32, 98, 103> HonorNextLevel; - UpdateField<uint8, 98, 104> NumBankSlots; - UpdateField<UF::ActivePlayerUnk901, 98, 106> Field_1410; - OptionalUpdateField<UF::QuestSession, 98, 105> QuestSession; - UpdateField<int32, 98, 107> UiChromieTimeExpansionID; - UpdateField<int32, 98, 108> TransportServerTime; - UpdateField<uint32, 98, 109> WeeklyRewardsPeriodSinceOrigin; // week count since Cfg_RegionsEntry::ChallengeOrigin - UpdateField<int16, 98, 110> DEBUGSoulbindConduitRank; - UpdateField<WorldPackets::MythicPlus::DungeonScoreData, 98, 111> DungeonScore; - UpdateFieldArray<ObjectGuid, 199, 112, 113> InvSlots; - UpdateFieldArray<uint64, 240, 312, 313> ExploredZones; - UpdateFieldArray<UF::RestInfo, 2, 553, 554> RestInfo; - UpdateFieldArray<int32, 7, 556, 557> ModDamageDonePos; - UpdateFieldArray<int32, 7, 556, 564> ModDamageDoneNeg; - UpdateFieldArray<float, 7, 556, 571> ModDamageDonePercent; - UpdateFieldArray<float, 7, 556, 578> ModHealingDonePercent; - UpdateFieldArray<float, 3, 585, 586> WeaponDmgMultipliers; - UpdateFieldArray<float, 3, 585, 589> WeaponAtkSpeedMultipliers; - UpdateFieldArray<uint32, 12, 592, 593> BuybackPrice; - UpdateFieldArray<int64, 12, 592, 605> BuybackTimestamp; - UpdateFieldArray<int32, 32, 617, 618> CombatRatings; - UpdateFieldArray<UF::PVPInfo, 6, 650, 651> PvpInfo; - UpdateFieldArray<uint32, 4, 657, 658> NoReagentCostMask; - UpdateFieldArray<int32, 2, 662, 663> ProfessionSkillLine; - UpdateFieldArray<uint32, 4, 665, 666> BagSlotFlags; - UpdateFieldArray<uint32, 7, 670, 671> BankBagSlotFlags; - UpdateFieldArray<uint64, 875, 678, 679> QuestCompleted; + DynamicUpdateField<uint16, 0, 7> ResearchSites; + DynamicUpdateField<uint32, 0, 8> ResearchSiteProgress; + DynamicUpdateField<int32, 0, 9> DailyQuestsCompleted; + DynamicUpdateField<int32, 0, 10> AvailableQuestLineXQuestIDs; + DynamicUpdateField<int32, 0, 11> Heirlooms; + DynamicUpdateField<uint32, 0, 12> HeirloomFlags; + DynamicUpdateField<int32, 0, 13> Toys; + DynamicUpdateField<uint32, 0, 14> ToyFlags; + DynamicUpdateField<uint32, 0, 15> Transmog; + DynamicUpdateField<int32, 0, 16> ConditionalTransmog; + DynamicUpdateField<int32, 0, 17> SelfResSpells; + DynamicUpdateField<uint32, 0, 18> RuneforgePowers; + DynamicUpdateField<uint32, 0, 19> TransmogIllusions; + DynamicUpdateField<UF::SpellPctModByLabel, 0, 21> SpellPctModByLabel; + DynamicUpdateField<UF::SpellFlatModByLabel, 0, 22> SpellFlatModByLabel; + DynamicUpdateField<UF::MawPower, 0, 23> MawPowers; + DynamicUpdateField<UF::MultiFloorExplore, 0, 24> MultiFloorExploration; + DynamicUpdateField<UF::RecipeProgressionInfo, 0, 25> RecipeProgression; + DynamicUpdateField<UF::ReplayedQuest, 0, 26> ReplayedQuests; + DynamicUpdateField<int32, 0, 27> DisabledSpells; + DynamicUpdateField<UF::PVPInfo, 0, 6> PvpInfo; + DynamicUpdateField<UF::CharacterRestriction, 0, 20> CharacterRestrictions; + DynamicUpdateField<UF::TraitConfig, 0, 28> TraitConfigs; + DynamicUpdateField<UF::CraftingOrder, 0, 29> CraftingOrders; + UpdateField<ObjectGuid, 0, 32> FarsightObject; + UpdateField<ObjectGuid, 0, 33> SummonedBattlePetGUID; + UpdateField<uint64, 34, 35> Coinage; + UpdateField<int32, 34, 36> XP; + UpdateField<int32, 34, 37> NextLevelXP; + UpdateField<int32, 34, 38> TrialXP; + UpdateField<UF::SkillInfo, 34, 39> Skill; + UpdateField<int32, 34, 40> CharacterPoints; + UpdateField<int32, 34, 41> MaxTalentTiers; + UpdateField<uint32, 34, 42> TrackCreatureMask; + UpdateField<float, 34, 43> MainhandExpertise; + UpdateField<float, 34, 44> OffhandExpertise; + UpdateField<float, 34, 45> RangedExpertise; + UpdateField<float, 34, 46> CombatRatingExpertise; + UpdateField<float, 34, 47> BlockPercentage; + UpdateField<float, 34, 48> DodgePercentage; + UpdateField<float, 34, 49> DodgePercentageFromAttribute; + UpdateField<float, 34, 50> ParryPercentage; + UpdateField<float, 34, 51> ParryPercentageFromAttribute; + UpdateField<float, 34, 52> CritPercentage; + UpdateField<float, 34, 53> RangedCritPercentage; + UpdateField<float, 34, 54> OffhandCritPercentage; + UpdateField<float, 34, 55> SpellCritPercentage; + UpdateField<int32, 34, 56> ShieldBlock; + UpdateField<float, 34, 57> ShieldBlockCritPercentage; + UpdateField<float, 34, 58> Mastery; + UpdateField<float, 34, 59> Speed; + UpdateField<float, 34, 60> Avoidance; + UpdateField<float, 34, 61> Sturdiness; + UpdateField<int32, 34, 62> Versatility; + UpdateField<float, 34, 63> VersatilityBonus; + UpdateField<float, 34, 64> PvpPowerDamage; + UpdateField<float, 34, 65> PvpPowerHealing; + UpdateField<int32, 66, 67> ModHealingDonePos; + UpdateField<float, 66, 68> ModHealingPercent; + UpdateField<float, 66, 69> ModPeriodicHealingDonePercent; + UpdateField<float, 66, 70> ModSpellPowerPercent; + UpdateField<float, 66, 71> ModResiliencePercent; + UpdateField<float, 66, 72> OverrideSpellPowerByAPPercent; + UpdateField<float, 66, 73> OverrideAPBySpellPowerPercent; + UpdateField<int32, 66, 74> ModTargetResistance; + UpdateField<int32, 66, 75> ModTargetPhysicalResistance; + UpdateField<uint32, 66, 76> LocalFlags; + UpdateField<uint8, 66, 77> GrantableLevels; + UpdateField<uint8, 66, 78> MultiActionBars; + UpdateField<uint8, 66, 79> LifetimeMaxRank; + UpdateField<uint8, 66, 80> NumRespecs; + UpdateField<uint32, 66, 81> PvpMedals; + UpdateField<uint16, 66, 82> TodayHonorableKills; + UpdateField<uint16, 66, 83> YesterdayHonorableKills; + UpdateField<uint32, 66, 84> LifetimeHonorableKills; + UpdateField<int32, 66, 85> WatchedFactionIndex; + UpdateField<int32, 66, 86> MaxLevel; + UpdateField<int32, 66, 87> ScalingPlayerLevelDelta; + UpdateField<int32, 66, 88> MaxCreatureScalingLevel; + UpdateField<int32, 66, 89> PetSpellPower; + UpdateField<float, 66, 90> UiHitModifier; + UpdateField<float, 66, 91> UiSpellHitModifier; + UpdateField<int32, 66, 92> HomeRealmTimeOffset; + UpdateField<float, 66, 93> ModPetHaste; + UpdateField<int8, 66, 94> JailersTowerLevelMax; + UpdateField<int8, 66, 95> JailersTowerLevel; + UpdateField<uint8, 66, 96> LocalRegenFlags; + UpdateField<uint8, 66, 97> AuraVision; + UpdateField<uint8, 98, 99> NumBackpackSlots; + UpdateField<int32, 98, 100> OverrideSpellsID; + UpdateField<uint16, 98, 101> LootSpecID; + UpdateField<uint32, 98, 102> OverrideZonePVPType; + UpdateField<ObjectGuid, 98, 103> BnetAccount; + UpdateField<uint64, 98, 104> GuildClubMemberID; + UpdateField<int32, 98, 105> Honor; + UpdateField<int32, 98, 106> HonorNextLevel; + UpdateField<uint8, 98, 107> NumBankSlots; + UpdateField<UF::ActivePlayerUnk901, 98, 109> Field_1410; + OptionalUpdateField<UF::QuestSession, 98, 108> QuestSession; + UpdateField<int32, 98, 110> UiChromieTimeExpansionID; + UpdateField<int32, 98, 111> TransportServerTime; + UpdateField<uint32, 98, 112> WeeklyRewardsPeriodSinceOrigin; // week count since Cfg_RegionsEntry::ChallengeOrigin + UpdateField<int16, 98, 113> DEBUGSoulbindConduitRank; + UpdateField<WorldPackets::MythicPlus::DungeonScoreData, 98, 114> DungeonScore; + UpdateField<uint32, 98, 115> ActiveCombatTraitConfigID; + UpdateFieldArray<ObjectGuid, 218, 116, 117> InvSlots; + UpdateFieldArray<uint64, 240, 335, 336> ExploredZones; + UpdateFieldArray<UF::RestInfo, 2, 576, 577> RestInfo; + UpdateFieldArray<int32, 7, 579, 580> ModDamageDonePos; + UpdateFieldArray<int32, 7, 579, 587> ModDamageDoneNeg; + UpdateFieldArray<float, 7, 579, 594> ModDamageDonePercent; + UpdateFieldArray<float, 7, 579, 601> ModHealingDonePercent; + UpdateFieldArray<float, 3, 608, 609> WeaponDmgMultipliers; + UpdateFieldArray<float, 3, 608, 612> WeaponAtkSpeedMultipliers; + UpdateFieldArray<uint32, 12, 615, 616> BuybackPrice; + UpdateFieldArray<int64, 12, 615, 628> BuybackTimestamp; + UpdateFieldArray<int32, 32, 640, 641> CombatRatings; + UpdateFieldArray<uint32, 4, 673, 674> NoReagentCostMask; + UpdateFieldArray<int32, 2, 678, 679> ProfessionSkillLine; + UpdateFieldArray<uint32, 5, 681, 682> BagSlotFlags; + UpdateFieldArray<uint32, 7, 687, 688> BankBagSlotFlags; + UpdateFieldArray<uint64, 875, 695, 696> QuestCompleted; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, Player const* owner, Player const* receiver) const; @@ -790,30 +888,34 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas void ClearChangesMask(); }; -struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<21> +struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask<25> { UpdateField<std::vector<uint32>, 0, 1> StateWorldEffectIDs; DynamicUpdateField<int32, 0, 2> EnableDoodadSets; - UpdateField<int32, 0, 3> DisplayID; - UpdateField<uint32, 0, 4> SpellVisualID; - UpdateField<uint32, 0, 5> StateSpellVisualID; - UpdateField<uint32, 0, 6> SpawnTrackingStateAnimID; - UpdateField<uint32, 0, 7> SpawnTrackingStateAnimKitID; - UpdateField<uint32, 0, 8> StateWorldEffectsQuestObjectiveID; - UpdateField<ObjectGuid, 0, 9> CreatedBy; - UpdateField<ObjectGuid, 0, 10> GuildGUID; - UpdateField<uint32, 0, 11> Flags; + DynamicUpdateField<int32, 0, 3> WorldEffects; + UpdateField<int32, 0, 4> DisplayID; + UpdateField<uint32, 0, 5> SpellVisualID; + UpdateField<uint32, 0, 6> StateSpellVisualID; + UpdateField<uint32, 0, 7> SpawnTrackingStateAnimID; + UpdateField<uint32, 0, 8> SpawnTrackingStateAnimKitID; + UpdateField<uint32, 0, 9> StateWorldEffectsQuestObjectiveID; + UpdateField<ObjectGuid, 0, 10> CreatedBy; + UpdateField<ObjectGuid, 0, 11> GuildGUID; + UpdateField<uint32, 0, 12> Flags; struct FlagsTag : ViewerDependentValueTag<uint32> {}; - UpdateField<QuaternionData, 0, 12> ParentRotation; - UpdateField<int32, 0, 13> FactionTemplate; - UpdateField<int8, 0, 14> State; + UpdateField<QuaternionData, 0, 13> ParentRotation; + UpdateField<int32, 0, 14> FactionTemplate; + UpdateField<int8, 0, 15> State; struct StateTag : ViewerDependentValueTag<int8> {}; - UpdateField<int8, 0, 15> TypeID; - UpdateField<uint8, 0, 16> PercentHealth; - UpdateField<uint32, 0, 17> ArtKit; - UpdateField<uint32, 0, 18> CustomParam; - UpdateField<int32, 0, 19> Level; - UpdateField<uint32, 0, 20> AnimGroupInstance; + UpdateField<int8, 0, 16> TypeID; + UpdateField<uint8, 0, 17> PercentHealth; + UpdateField<uint32, 0, 18> ArtKit; + UpdateField<uint32, 0, 19> CustomParam; + UpdateField<int32, 0, 20> Level; + UpdateField<uint32, 0, 21> AnimGroupInstance; + UpdateField<uint32, 0, 22> UiWidgetItemID; + UpdateField<uint32, 0, 23> UiWidgetItemQuality; + UpdateField<uint32, 0, 24> UiWidgetItemUnknown1000; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, GameObject const* owner, Player const* receiver) const; @@ -882,25 +984,30 @@ struct VisualAnim : public IsUpdateFieldStructureTag, public HasChangesMask<5> void ClearChangesMask(); }; -struct AreaTriggerData : public IsUpdateFieldStructureTag, public HasChangesMask<18> +struct AreaTriggerData : public IsUpdateFieldStructureTag, public HasChangesMask<23> { UpdateField<UF::ScaleCurve, 0, 1> OverrideScaleCurve; UpdateField<UF::ScaleCurve, 0, 2> ExtraScaleCurve; - UpdateField<ObjectGuid, 0, 3> Caster; - UpdateField<uint32, 0, 4> Duration; - UpdateField<uint32, 0, 5> TimeToTarget; - UpdateField<uint32, 0, 6> TimeToTargetScale; - UpdateField<uint32, 0, 7> TimeToTargetExtraScale; - UpdateField<int32, 0, 8> SpellID; - UpdateField<int32, 0, 9> SpellForVisuals; - UpdateField<UF::SpellCastVisual, 0, 10> SpellVisual; - UpdateField<float, 0, 11> BoundsRadius2D; - UpdateField<uint32, 0, 12> DecalPropertiesID; - UpdateField<ObjectGuid, 0, 13> CreatingEffectGUID; - UpdateField<uint32, 0, 14> Field_80; - UpdateField<uint32, 0, 15> Field_84; - UpdateField<ObjectGuid, 0, 16> Field_88; - UpdateField<UF::VisualAnim, 0, 17> VisualAnim; + UpdateField<UF::ScaleCurve, 0, 3> Field_C38; + UpdateField<UF::ScaleCurve, 0, 4> Field_C54; + UpdateField<UF::ScaleCurve, 0, 5> Field_C70; + UpdateField<ObjectGuid, 0, 6> Caster; + UpdateField<uint32, 0, 7> Duration; + UpdateField<uint32, 0, 8> TimeToTarget; + UpdateField<uint32, 0, 9> TimeToTargetScale; + UpdateField<uint32, 0, 10> TimeToTargetExtraScale; + UpdateField<uint32, 0, 11> Field_B0; + UpdateField<int32, 0, 12> SpellID; + UpdateField<int32, 0, 13> SpellForVisuals; + UpdateField<UF::SpellCastVisual, 0, 14> SpellVisual; + UpdateField<float, 0, 15> BoundsRadius2D; + UpdateField<uint32, 0, 16> DecalPropertiesID; + UpdateField<ObjectGuid, 0, 17> CreatingEffectGUID; + UpdateField<uint32, 0, 18> Field_80; + UpdateField<uint32, 0, 19> Field_84; + UpdateField<ObjectGuid, 0, 20> Field_88; + UpdateField<TaggedPosition<Position::XYZ>, 0, 21> Field_F8; + UpdateField<UF::VisualAnim, 0, 22> VisualAnim; void WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const; void WriteUpdate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisibilityFlags, AreaTrigger const* owner, Player const* receiver) const; diff --git a/src/server/game/Entities/Player/CollectionMgr.cpp b/src/server/game/Entities/Player/CollectionMgr.cpp index 296b03b6720..17603908065 100644 --- a/src/server/game/Entities/Player/CollectionMgr.cpp +++ b/src/server/game/Entities/Player/CollectionMgr.cpp @@ -322,9 +322,9 @@ void CollectionMgr::CheckHeirloomUpgrades(Item* item) return; } - auto const& bonusListIDs = item->m_itemData->BonusListIDs; + std::vector<int32> const& bonusListIDs = item->GetBonusListIDs(); - for (uint32 bonusId : *bonusListIDs) + for (uint32 bonusId : bonusListIDs) { if (bonusId != itr->second.bonusId) { @@ -333,7 +333,7 @@ void CollectionMgr::CheckHeirloomUpgrades(Item* item) } } - if (std::find(bonusListIDs->begin(), bonusListIDs->end(), int32(itr->second.bonusId)) == bonusListIDs->end()) + if (std::find(bonusListIDs.begin(), bonusListIDs.end(), int32(itr->second.bonusId)) == bonusListIDs.end()) item->AddBonuses(itr->second.bonusId); } } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 90a414e6ad7..e2cdadfb468 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -537,7 +537,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac // original items for (PlayerCreateInfoItem initialItem : info->item) - StoreNewItemInBestSlots(initialItem.item_id, initialItem.item_amount); + StoreNewItemInBestSlots(initialItem.item_id, initialItem.item_amount, info->itemContext); // bags and main-hand weapon must equipped at this moment // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon) @@ -581,46 +581,45 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac return true; } -bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount) +bool Player::StoreNewItemInBestSlots(uint32 itemId, uint32 amount, ItemContext context) { TC_LOG_DEBUG("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) creates initial item (ItemID: %u, Count: %u)", - GetName().c_str(), GetGUID().ToString().c_str(), titem_id, titem_amount); + GetName().c_str(), GetGUID().ToString().c_str(), itemId, amount); - ItemContext itemContext = ItemContext::New_Character; std::vector<int32> bonusListIDs; - std::set<uint32> contextBonuses = sDB2Manager.GetDefaultItemBonusTree(titem_id, itemContext); + std::set<uint32> contextBonuses = sDB2Manager.GetDefaultItemBonusTree(itemId, context); bonusListIDs.insert(bonusListIDs.begin(), contextBonuses.begin(), contextBonuses.end()); // attempt equip by one - while (titem_amount > 0) + while (amount > 0) { uint16 eDest; - InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, titem_id, false); + InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, itemId, false); if (msg != EQUIP_ERR_OK) break; - Item* item = EquipNewItem(eDest, titem_id, itemContext, true); + Item* item = EquipNewItem(eDest, itemId, context, true); item->SetBonuses(bonusListIDs); AutoUnequipOffhandIfNeed(); - --titem_amount; + --amount; } - if (titem_amount == 0) + if (amount == 0) return true; // equipped // attempt store ItemPosCountVec sDest; // store in main bag to simplify second pass (special bags can be not equipped yet at this moment) - InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount); + InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, itemId, amount); if (msg == EQUIP_ERR_OK) { - StoreNewItem(sDest, titem_id, true, GenerateItemRandomBonusListId(titem_id), GuidSet(), itemContext, bonusListIDs); + StoreNewItem(sDest, itemId, true, GenerateItemRandomBonusListId(itemId), GuidSet(), context, bonusListIDs); return true; // stored } // item can't be added TC_LOG_ERROR("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) can't equip or store initial item (ItemID: %u, Race: %u, Class: %u, InventoryResult: %u)", - GetName().c_str(), GetGUID().ToString().c_str(), titem_id, GetRace(), GetClass(), msg); + GetName().c_str(), GetGUID().ToString().c_str(), itemId, GetRace(), GetClass(), msg); return false; } @@ -2292,7 +2291,6 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate) packet.Reason = victim ? LOG_XP_REASON_KILL : LOG_XP_REASON_NO_KILL; packet.Amount = xp; packet.GroupBonus = group_rate; - packet.ReferAFriendBonusType = recruitAFriend ? 1 : 0; SendDirectMessage(packet.Write()); uint32 nextLvlXP = GetXPForNextLevel(); @@ -3182,10 +3180,11 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/ // prevent duplicated entires in spell book, also not send if not in world (loading) if (learning && IsInWorld()) { - WorldPackets::Spells::LearnedSpells packet; - packet.SpellID.push_back(spell_id); - packet.SuppressMessaging = suppressMessaging; - SendDirectMessage(packet.Write()); + WorldPackets::Spells::LearnedSpells learnedSpells; + WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = learnedSpells.ClientLearnedSpellData.emplace_back(); + learnedSpellInfo.SpellID = spell_id; + learnedSpells.SuppressMessaging = suppressMessaging; + SendDirectMessage(learnedSpells.Write()); } // learn all disabled higher ranks and required spells (recursive) @@ -3519,23 +3518,7 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c { if (target == this) { - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); - } - - for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); - } - - for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; ++i) { if (m_items[i] == nullptr) continue; @@ -3543,7 +3526,7 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c m_items[i]->BuildCreateUpdateBlockForPlayer(data, target); } - for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) + for (uint8 i = REAGENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) { if (m_items[i] == nullptr) continue; @@ -3684,7 +3667,7 @@ void Player::DestroyForPlayer(Player* target) const if (target == this) { - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; ++i) { if (m_items[i] == nullptr) continue; @@ -3692,23 +3675,7 @@ void Player::DestroyForPlayer(Player* target) const m_items[i]->DestroyForPlayer(target); } - for (uint8 i = INVENTORY_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->DestroyForPlayer(target); - } - - for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) - { - if (m_items[i] == nullptr) - continue; - - m_items[i]->DestroyForPlayer(target); - } - - for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) + for (uint8 i = REAGENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i) { if (m_items[i] == nullptr) continue; @@ -4493,7 +4460,7 @@ Corpse* Player::CreateCorpse() corpse->SetDisplayId(GetNativeDisplayId()); corpse->SetFactionTemplate(sChrRacesStore.AssertEntry(GetRace())->FactionID); - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; i++) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) { if (m_items[i]) { @@ -8211,8 +8178,9 @@ void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const { AddTemporarySpell(artifactPowerRank->SpellID); WorldPackets::Spells::LearnedSpells learnedSpells; + WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = learnedSpells.ClientLearnedSpellData.emplace_back(); + learnedSpellInfo.SpellID = artifactPowerRank->SpellID; learnedSpells.SuppressMessaging = true; - learnedSpells.SpellID.push_back(artifactPowerRank->SpellID); SendDirectMessage(learnedSpells.Write()); } else if (!apply) @@ -8898,8 +8866,11 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId) void Player::SetBindPoint(ObjectGuid guid) const { - WorldPackets::Misc::BinderConfirm packet(guid); - SendDirectMessage(packet.Write()); + WorldPackets::NPC::NPCInteractionOpenResult npcInteraction; + npcInteraction.Npc = guid; + npcInteraction.InteractionType = PlayerInteractionType::Binder; + npcInteraction.Success = true; + SendDirectMessage(npcInteraction.Write()); } void Player::SendRespecWipeConfirm(ObjectGuid const& guid, uint32 cost, SpecResetType respecType) const @@ -9064,10 +9035,16 @@ uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location / uint32 freeSlotCount = 0; if (location.HasFlag(ItemSearchLocation::Equipment)) + { for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) ++freeSlotCount; + for (uint8 i = PROFESSION_SLOT_START; i < PROFESSION_SLOT_END; ++i) + if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeSlotCount; + } + if (location.HasFlag(ItemSearchLocation::Inventory)) { uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount(); @@ -9096,9 +9073,17 @@ uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location / } if (location.HasFlag(ItemSearchLocation::ReagentBank)) + { + for (uint8 i = REAGENT_BAG_SLOT_START; i < REAGENT_BAG_SLOT_END; ++i) + if (Bag* bag = GetBagByPos(i)) + for (uint32 j = 0; j < GetBagSize(bag); ++j) + if (!GetItemInBag(bag, j)) + ++freeSlotCount; + for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) if (!GetItemByPos(INVENTORY_SLOT_BAG_0, i)) ++freeSlotCount; + } return freeSlotCount; } @@ -9233,7 +9218,8 @@ Item* Player::GetUseableItemByPos(uint8 bag, uint8 slot) const Bag* Player::GetBagByPos(uint8 bag) const { if ((bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) - || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)) + || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END) + || (bag >= REAGENT_BAG_SLOT_START && bag < REAGENT_BAG_SLOT_END)) if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, bag)) return item->ToBag(); return nullptr; @@ -9355,8 +9341,12 @@ bool Player::IsEquipmentPos(uint8 bag, uint8 slot) { if (bag == INVENTORY_SLOT_BAG_0 && (slot < EQUIPMENT_SLOT_END)) return true; + if (bag == INVENTORY_SLOT_BAG_0 && (slot >= PROFESSION_SLOT_START && slot < PROFESSION_SLOT_END)) + return true; if (bag == INVENTORY_SLOT_BAG_0 && (slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END)) return true; + if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END)) + return true; return false; } @@ -9388,6 +9378,8 @@ bool Player::IsBagPos(uint16 pos) return true; if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)) return true; + if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END)) + return true; return false; } @@ -9412,10 +9404,18 @@ bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const if (slot < EQUIPMENT_SLOT_END) return true; + // profession equipment + if (slot >= PROFESSION_SLOT_START && slot < PROFESSION_SLOT_END) + return true; + // bag equip slots if (slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END) return true; + // reagent bag equip slots + if (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END) + return true; + // backpack slots if (slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_START + GetInventorySlotCount()) return true; @@ -11663,7 +11663,7 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update) pItem->RemoveItemFlag2(ITEM_FIELD_FLAG2_EQUIPPED); // remove item dependent auras and casts (only weapon and armor slots) - if (slot < EQUIPMENT_SLOT_END) + if (slot < PROFESSION_SLOT_END) { // update expertise if (slot == EQUIPMENT_SLOT_MAINHAND) @@ -13648,7 +13648,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues { switch (gossipMenuItem.OptionNpc) { - case GossipOptionNpc::TaxiNode: + case GossipOptionNpc::Taxinode: if (GetSession()->SendLearnNewTaxiNode(creature)) return; break; @@ -13656,7 +13656,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues if (!isDead()) canTalk = false; break; - case GossipOptionNpc::BattleMaster: + case GossipOptionNpc::Battlemaster: if (!creature->isCanInteractWithBattleMaster(this, false)) canTalk = false; break; @@ -13666,7 +13666,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues if (!creature->CanResetTalents(this)) canTalk = false; break; - case GossipOptionNpc::StableMaster: + case GossipOptionNpc::Stablemaster: case GossipOptionNpc::PetSpecializationMaster: if (GetClass() != CLASS_HUNTER) canTalk = false; @@ -13695,29 +13695,29 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues canTalk = false; // Deprecated break; case GossipOptionNpc::GuildBanker: - case GossipOptionNpc::SpellClick: - case GossipOptionNpc::WorldPVPQueue: + case GossipOptionNpc::Spellclick: + case GossipOptionNpc::WorldPvPQueue: case GossipOptionNpc::LFGDungeon: case GossipOptionNpc::ArtifactRespec: case GossipOptionNpc::QueueScenario: case GossipOptionNpc::GarrisonArchitect: - case GossipOptionNpc::GarrisonMission: + case GossipOptionNpc::GarrisonMissionNpc: case GossipOptionNpc::ShipmentCrafter: - case GossipOptionNpc::GarrisonTradeskill: + case GossipOptionNpc::GarrisonTradeskillNpc: case GossipOptionNpc::GarrisonRecruitment: case GossipOptionNpc::AdventureMap: case GossipOptionNpc::GarrisonTalent: case GossipOptionNpc::ContributionCollector: - case GossipOptionNpc::IslandsMission: + case GossipOptionNpc::IslandsMissionNpc: case GossipOptionNpc::UIItemInteraction: case GossipOptionNpc::WorldMap: case GossipOptionNpc::Soulbind: - case GossipOptionNpc::ChromieTime: - case GossipOptionNpc::CovenantPreview: + case GossipOptionNpc::ChromieTimeNpc: + case GossipOptionNpc::CovenantPreviewNpc: case GossipOptionNpc::RuneforgeLegendaryCrafting: case GossipOptionNpc::NewPlayerGuide: case GossipOptionNpc::RuneforgeLegendaryUpgrade: - case GossipOptionNpc::CovenantRenown: + case GossipOptionNpc::CovenantRenownNpc: break; // NYI default: TC_LOG_ERROR("sql.sql", "Creature entry %u has an unknown gossip option icon %u for menu %u.", creature->GetEntry(), AsUnderlyingType(gossipMenuItem.OptionNpc), gossipMenuItem.MenuID); @@ -13740,42 +13740,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQues } if (canTalk) - { - std::string strOptionText, strBoxText; - BroadcastTextEntry const* optionBroadcastText = sBroadcastTextStore.LookupEntry(gossipMenuItem.OptionBroadcastTextID); - BroadcastTextEntry const* boxBroadcastText = sBroadcastTextStore.LookupEntry(gossipMenuItem.BoxBroadcastTextID); - LocaleConstant locale = GetSession()->GetSessionDbLocaleIndex(); - - if (optionBroadcastText) - strOptionText = DB2Manager::GetBroadcastTextValue(optionBroadcastText, locale, GetGender()); - else - strOptionText = gossipMenuItem.OptionText; - - if (boxBroadcastText) - strBoxText = DB2Manager::GetBroadcastTextValue(boxBroadcastText, locale, GetGender()); - else - strBoxText = gossipMenuItem.BoxText; - - if (locale != DEFAULT_LOCALE) - { - if (!optionBroadcastText) - { - /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(menuId, gossipMenuItem.OptionID)) - ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, locale, strOptionText); - } - - if (!boxBroadcastText) - { - /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(menuId, gossipMenuItem.OptionID)) - ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, locale, strBoxText); - } - } - - menu->GetGossipMenu().AddMenuItem(gossipMenuItem.OptionID, gossipMenuItem.OptionNpc, strOptionText, 0, AsUnderlyingType(gossipMenuItem.OptionNpc), strBoxText, gossipMenuItem.BoxMoney, gossipMenuItem.BoxCoded); - menu->GetGossipMenu().AddGossipMenuItemData(gossipMenuItem.OptionID, gossipMenuItem.ActionMenuID, gossipMenuItem.ActionPoiID); - } + menu->GetGossipMenu().AddMenuItem(gossipMenuItem, gossipMenuItem.MenuID, gossipMenuItem.OrderIndex); } } @@ -13804,7 +13769,7 @@ void Player::SendPreparedGossip(WorldObject* source) PlayerTalkClass->SendGossipMenu(textId, source->GetGUID()); } -void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 menuId) +void Player::OnGossipSelect(WorldObject* source, int32 gossipOptionId, uint32 menuId) { GossipMenu& gossipMenu = PlayerTalkClass->GetGossipMenu(); @@ -13812,7 +13777,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men if (menuId != gossipMenu.GetMenuId()) return; - GossipMenuItem const* item = gossipMenu.GetItem(gossipListId); + GossipMenuItem const* item = gossipMenu.GetItem(gossipOptionId); if (!item) return; @@ -13829,10 +13794,6 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men } } - GossipMenuItemData const* menuItemData = gossipMenu.GetItemData(gossipListId); - if (!menuItemData) - return; - int64 cost = int64(item->BoxMoney); if (!HasEnoughMoney(cost)) { @@ -13841,51 +13802,37 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men return; } - switch (gossipOptionNpc) - { - case GossipOptionNpc::None: - { - if (menuItemData->GossipActionPoi) - PlayerTalkClass->SendPointOfInterest(menuItemData->GossipActionPoi); + if (item->ActionPoiID) + PlayerTalkClass->SendPointOfInterest(item->ActionPoiID); - if (menuItemData->GossipActionMenuId) - { - PrepareGossipMenu(source, menuItemData->GossipActionMenuId); - SendPreparedGossip(source); - } + if (item->ActionMenuID) + { + PrepareGossipMenu(source, item->ActionMenuID); + SendPreparedGossip(source); + } - break; - } + // types that have their dedicated open opcode dont send WorldPackets::NPC::GossipOptionNPCInteraction + bool handled = true; + switch (gossipOptionNpc) + { case GossipOptionNpc::Vendor: GetSession()->SendListInventory(guid); break; - case GossipOptionNpc::TaxiNode: + case GossipOptionNpc::Taxinode: GetSession()->SendTaxiMenu(source->ToCreature()); break; case GossipOptionNpc::Trainer: - GetSession()->SendTrainerList(source->ToCreature(), sObjectMgr->GetCreatureTrainerForGossipOption(source->GetEntry(), menuId, gossipListId)); + GetSession()->SendTrainerList(source->ToCreature(), sObjectMgr->GetCreatureTrainerForGossipOption(source->GetEntry(), menuId, gossipOptionId)); break; case GossipOptionNpc::SpiritHealer: - if (isDead()) - source->ToCreature()->CastSpell(source->ToCreature(), 17251, CastSpellExtraArgs(TRIGGERED_FULL_MASK) - .SetOriginalCaster(GetGUID())); - break; - case GossipOptionNpc::Binder: - PlayerTalkClass->SendCloseGossip(); - SetBindPoint(guid); - break; - case GossipOptionNpc::Banker: - GetSession()->SendShowBank(guid); + source->CastSpell(source->ToCreature(), 17251, CastSpellExtraArgs(TRIGGERED_FULL_MASK).SetOriginalCaster(GetGUID())); + handled = false; break; case GossipOptionNpc::PetitionVendor: PlayerTalkClass->SendCloseGossip(); GetSession()->SendPetitionShowList(guid); break; - case GossipOptionNpc::TabardVendor: - PlayerTalkClass->SendCloseGossip(); - GetSession()->SendTabardVendorActivate(guid); - break; - case GossipOptionNpc::BattleMaster: + case GossipOptionNpc::Battlemaster: { BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(source->GetEntry()); @@ -13906,13 +13853,23 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men PlayerTalkClass->SendCloseGossip(); SendRespecWipeConfirm(guid, sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : GetNextResetTalentsCost(), SPEC_RESET_TALENTS); break; - case GossipOptionNpc::StableMaster: + case GossipOptionNpc::Stablemaster: GetSession()->SendStablePet(guid); break; case GossipOptionNpc::PetSpecializationMaster: PlayerTalkClass->SendCloseGossip(); SendRespecWipeConfirm(guid, sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST) ? 0 : GetNextResetTalentsCost(), SPEC_RESET_PET_TALENTS); break; + case GossipOptionNpc::GuildBanker: + if (Guild* const guild = GetGuild()) + guild->SendBankList(GetSession(), 0, true); + else + Guild::SendCommandResult(GetSession(), GUILD_COMMAND_VIEW_TAB, ERR_GUILD_PLAYER_NOT_IN_GUILD); + break; + case GossipOptionNpc::Spellclick: + if (Unit* sourceUnit = source->ToUnit()) + sourceUnit->HandleSpellClick(this); + break; case GossipOptionNpc::DisableXPGain: PlayerTalkClass->SendCloseGossip(); CastSpell(nullptr, SPELL_EXPERIENCE_ELIMINATED, true); @@ -13923,9 +13880,6 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men RemoveAurasDueToSpell(SPELL_EXPERIENCE_ELIMINATED); RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); break; - case GossipOptionNpc::Mailbox: - GetSession()->SendShowMailBox(guid); - break; case GossipOptionNpc::SpecializationMaster: PlayerTalkClass->SendCloseGossip(); SendRespecWipeConfirm(guid, 0, SPEC_RESET_SPECIALIZATION); @@ -13934,24 +13888,77 @@ 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); + case GossipOptionNpc::GarrisonTradeskillNpc: // NYI break; - } - case GossipOptionNpc::Transmogrify: - GetSession()->SendOpenTransmogrifier(guid); + case GossipOptionNpc::GarrisonRecruitment: // NYI break; - case GossipOptionNpc::AzeriteRespec: - PlayerTalkClass->SendCloseGossip(); - GetSession()->SendAzeriteRespecNPC(guid); + case GossipOptionNpc::ChromieTimeNpc: // NYI + break; + case GossipOptionNpc::RuneforgeLegendaryCrafting: // NYI + break; + case GossipOptionNpc::RuneforgeLegendaryUpgrade: // NYI + break; + case GossipOptionNpc::ProfessionsCraftingOrder: // NYI + break; + case GossipOptionNpc::ProfessionsCustomerOrder: // NYI + break; + case GossipOptionNpc::BarbersChoice: // NYI - unknown if needs sending break; default: + handled = false; break; } + if (!handled) + { + if (item->GossipNpcOptionID) + { + GossipMenuAddon const* addon = sObjectMgr->GetGossipMenuAddon(menuId); + + WorldPackets::NPC::GossipOptionNPCInteraction npcInteraction; + npcInteraction.GossipGUID = source->GetGUID(); + npcInteraction.GossipNpcOptionID = *item->GossipNpcOptionID; + if (addon && addon->FriendshipFactionID) + npcInteraction.FriendshipFactionID = addon->FriendshipFactionID; + + SendDirectMessage(npcInteraction.Write()); + } + else + { + static constexpr std::array<PlayerInteractionType, AsUnderlyingType(GossipOptionNpc::Count)> GossipOptionNpcToInteractionType = + { + PlayerInteractionType::None, PlayerInteractionType::Vendor, PlayerInteractionType::TaxiNode, + PlayerInteractionType::Trainer, PlayerInteractionType::SpiritHealer, PlayerInteractionType::Binder, + PlayerInteractionType::Banker, PlayerInteractionType::PetitionVendor, PlayerInteractionType::TabardVendor, + PlayerInteractionType::BattleMaster, PlayerInteractionType::Auctioneer, PlayerInteractionType::TalentMaster, + PlayerInteractionType::StableMaster, PlayerInteractionType::None, PlayerInteractionType::GuildBanker, + PlayerInteractionType::None, PlayerInteractionType::None, PlayerInteractionType::None, + PlayerInteractionType::MailInfo, PlayerInteractionType::None, PlayerInteractionType::LFGDungeon, + PlayerInteractionType::ArtifactForge, PlayerInteractionType::None, PlayerInteractionType::SpecializationMaster, + PlayerInteractionType::None, PlayerInteractionType::None, PlayerInteractionType::GarrArchitect, + PlayerInteractionType::GarrMission, PlayerInteractionType::ShipmentCrafter, PlayerInteractionType::GarrTradeskill, + PlayerInteractionType::GarrRecruitment, PlayerInteractionType::AdventureMap, PlayerInteractionType::GarrTalent, + PlayerInteractionType::ContributionCollector, PlayerInteractionType::Transmogrifier, PlayerInteractionType::AzeriteRespec, + PlayerInteractionType::IslandQueue, PlayerInteractionType::ItemInteraction, PlayerInteractionType::WorldMap, + PlayerInteractionType::Soulbind, PlayerInteractionType::ChromieTime, PlayerInteractionType::CovenantPreview, + PlayerInteractionType::LegendaryCrafting, PlayerInteractionType::NewPlayerGuide, PlayerInteractionType::LegendaryCrafting, + PlayerInteractionType::Renown, PlayerInteractionType::BlackMarketAuctioneer, PlayerInteractionType::PerksProgramVendor, + PlayerInteractionType::ProfessionsCraftingOrder, PlayerInteractionType::Professions, PlayerInteractionType::ProfessionsCustomerOrder, + PlayerInteractionType::TraitSystem, PlayerInteractionType::BarbersChoice, PlayerInteractionType::MajorFactionRenown + }; + + PlayerInteractionType interactionType = GossipOptionNpcToInteractionType[AsUnderlyingType(gossipOptionNpc)]; + if (interactionType != PlayerInteractionType::None) + { + WorldPackets::NPC::NPCInteractionOpenResult npcInteraction; + npcInteraction.Npc = source->GetGUID(); + npcInteraction.InteractionType = interactionType; + npcInteraction.Success = true; + SendDirectMessage(npcInteraction.Write()); + } + } + } + ModifyMoney(-cost); } @@ -16781,7 +16788,7 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result) eqSet.Data.AssignedSpecIndex = fields[5].GetInt32(); eqSet.State = EQUIPMENT_SET_UNCHANGED; - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint32 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) if (ObjectGuid::LowType guid = fields[6 + i].GetUInt64()) eqSet.Data.Pieces[i] = ObjectGuid::Create<HighGuid::Item>(guid); @@ -16820,7 +16827,7 @@ void Player::_LoadTransmogOutfits(PreparedQueryResult result) eqSet.State = EQUIPMENT_SET_UNCHANGED; eqSet.Data.Pieces.fill(ObjectGuid::Empty); - for (uint32 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint32 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) eqSet.Data.Appearances[i] = fields[5 + i].GetInt32(); for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) @@ -17185,16 +17192,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol InitDisplayIds(); - // cleanup inventory related item value fields (it will be filled correctly in _LoadInventory) - for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) - { - SetInvSlot(slot, ObjectGuid::Empty); - SetVisibleItemSlot(slot, nullptr); - - delete m_items[slot]; - m_items[slot] = nullptr; - } - TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Load Basic value of player '%s' is: ", m_name.c_str()); outDebugValues(); @@ -17489,6 +17486,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol time_t now = GameTime::GetGameTime(); time_t logoutTime = time_t(fields.logout_time); + SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::LogoutTime), logoutTime); + // since last logout (in seconds) uint32 time_diff = uint32(now - logoutTime); //uint64 is excessive for a time_diff in seconds.. uint32 allows for 136~ year difference. @@ -19353,7 +19352,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba ss.str(""); // cache equipment... - for (uint32 i = 0; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i) { if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) { @@ -19501,7 +19500,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba ss.str(""); // cache equipment... - for (uint32 i = 0; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i) { if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) { @@ -22350,7 +22349,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin return false; } - if (iece->MinFactionID && uint32(GetReputationRank(iece->MinFactionID)) < iece->MinReputation) + if (iece->MinFactionID && int32(GetReputationRank(iece->MinFactionID)) < iece->MinReputation) { SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, item, 0); return false; @@ -25897,6 +25896,10 @@ TalentLearnResult Player::LearnPvpTalent(uint32 talentID, uint8 slot, int32* spe if (HasPvpTalent(talentID, GetActiveTalentGroup())) return TALENT_FAILED_UNKNOWN; + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(talentInfo->PlayerConditionID)) + if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition)) + return TALENT_FAILED_CANT_DO_THAT_RIGHT_NOW; + if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry(GetPvpTalentMap(GetActiveTalentGroup())[slot])) { if (!HasPlayerFlag(PLAYER_FLAGS_RESTING) && !HasUnitFlag2(UNIT_FLAG2_ALLOW_CHANGING_TALENTS)) @@ -26283,7 +26286,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans) stmt->setString(j++, eqSet.Data.SetIcon); stmt->setUInt32(j++, eqSet.Data.IgnoreMask); stmt->setInt32(j++, eqSet.Data.AssignedSpecIndex); - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); stmt->setUInt64(j++, GetGUID().GetCounter()); stmt->setUInt64(j++, eqSet.Data.Guid); @@ -26295,7 +26298,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans) stmt->setString(j++, eqSet.Data.SetName); stmt->setString(j++, eqSet.Data.SetIcon); stmt->setUInt32(j++, eqSet.Data.IgnoreMask); - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) stmt->setInt32(j++, eqSet.Data.Appearances[i]); for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) stmt->setInt32(j++, eqSet.Data.Enchants[i]); @@ -26320,7 +26323,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans) stmt->setString(j++, eqSet.Data.SetIcon); stmt->setUInt32(j++, eqSet.Data.IgnoreMask); stmt->setInt32(j++, eqSet.Data.AssignedSpecIndex); - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter()); } else @@ -26332,7 +26335,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans) stmt->setString(j++, eqSet.Data.SetName); stmt->setString(j++, eqSet.Data.SetIcon); stmt->setUInt32(j++, eqSet.Data.IgnoreMask); - for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) stmt->setInt32(j++, eqSet.Data.Appearances[i]); for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i) stmt->setInt32(j++, eqSet.Data.Enchants[i]); @@ -27639,8 +27642,9 @@ void Player::ValidateMovementInfo(MovementInfo* mi) void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const { WorldPackets::Spells::SupercededSpells supercededSpells; - supercededSpells.SpellID.push_back(newSpell); - supercededSpells.Superceded.push_back(oldSpell); + WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = supercededSpells.ClientLearnedSpellData.emplace_back(); + learnedSpellInfo.SpellID = newSpell; + learnedSpellInfo.Superceded = oldSpell; SendDirectMessage(supercededSpells.Write()); } @@ -27934,7 +27938,7 @@ void Player::UpdateAverageItemLevelTotal() ForEachItem(ItemSearchLocation::Everywhere, [this, &bestItemLevels, &sum](Item* item) { ItemTemplate const* itemTemplate = item->GetTemplate(); - if (itemTemplate) + if (itemTemplate && itemTemplate->GetInventoryType() < INVTYPE_PROFESSION_TOOL) { uint16 dest; if (item->IsEquipped()) @@ -28133,12 +28137,3 @@ 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 c155ccd6d01..ff4b3b1afa9 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -358,7 +358,7 @@ struct ActionButton } }; -#define MAX_ACTION_BUTTONS 132 +#define MAX_ACTION_BUTTONS 180 typedef std::map<uint8, ActionButton> ActionButtonList; @@ -637,7 +637,7 @@ enum PlayerSlots // first slot for item stored (in any way in player m_items data) PLAYER_SLOT_START = 0, // last+1 slot for item stored (in any way in player m_items data) - PLAYER_SLOT_END = 199, + PLAYER_SLOT_END = 218, PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START) }; @@ -671,50 +671,82 @@ enum EquipmentSlots : uint8 // 19 slots EQUIPMENT_SLOT_END = 19 }; -#define VISIBLE_ITEM_ENTRY_OFFSET 0 -#define VISIBLE_ITEM_ENCHANTMENT_OFFSET 1 +enum ProfessionSlots : uint8 +{ + PROFESSION_SLOT_PROFESSION1_TOOL = 19, + PROFESSION_SLOT_PROFESSION1_GEAR1 = 20, + PROFESSION_SLOT_PROFESSION1_GEAR2 = 21, + PROFESSION_SLOT_PROFESSION2_TOOL = 22, + PROFESSION_SLOT_PROFESSION2_GEAR1 = 23, + PROFESSION_SLOT_PROFESSION2_GEAR2 = 24, + PROFESSION_SLOT_COOKING_TOOL = 25, + PROFESSION_SLOT_COOKING_GEAR1 = 26, + PROFESSION_SLOT_FISHING_TOOL = 27, + PROFESSION_SLOT_FISHING_GEAR1 = 28, + PROFESSION_SLOT_FISHING_GEAR2 = 29, + + PROFESSION_SLOT_END, + PROFESSION_SLOT_START = PROFESSION_SLOT_PROFESSION1_TOOL +}; enum InventorySlots : uint8 // 4 slots { - INVENTORY_SLOT_BAG_START = 19, - INVENTORY_SLOT_BAG_END = 23 + INVENTORY_SLOT_BAG_START = 30, + INVENTORY_SLOT_BAG_END = 34 +}; + +enum ReagentBagSlots : uint8 // 1 slot +{ + REAGENT_BAG_SLOT_START = 34, + REAGENT_BAG_SLOT_END = 35 }; enum InventoryPackSlots : uint8 // 28 slots { - INVENTORY_SLOT_ITEM_START = 23, - INVENTORY_SLOT_ITEM_END = 51 + INVENTORY_SLOT_ITEM_START = 35, + INVENTORY_SLOT_ITEM_END = 63 }; enum BankItemSlots // 28 slots { - BANK_SLOT_ITEM_START = 51, - BANK_SLOT_ITEM_END = 79 + BANK_SLOT_ITEM_START = 63, + BANK_SLOT_ITEM_END = 91 }; enum BankBagSlots // 7 slots { - BANK_SLOT_BAG_START = 79, - BANK_SLOT_BAG_END = 86 + BANK_SLOT_BAG_START = 91, + BANK_SLOT_BAG_END = 98 }; enum BuyBackSlots // 12 slots { // stored in m_buybackitems - BUYBACK_SLOT_START = 86, - BUYBACK_SLOT_END = 98 + BUYBACK_SLOT_START = 98, + BUYBACK_SLOT_END = 110 }; enum ReagentSlots // 98 slots { - REAGENT_SLOT_START = 98, - REAGENT_SLOT_END = 196, + REAGENT_SLOT_START = 110, + REAGENT_SLOT_END = 208, }; enum ChildEquipmentSlots { - CHILD_EQUIPMENT_SLOT_START = 196, - CHILD_EQUIPMENT_SLOT_END = 199, + CHILD_EQUIPMENT_SLOT_START = 208, + CHILD_EQUIPMENT_SLOT_END = 211, +}; + +enum EquipableSpellSlots +{ + EQUIPABLE_SPELL_OFFENSIVE_SLOT1 = 211, + EQUIPABLE_SPELL_OFFENSIVE_SLOT2 = 212, + EQUIPABLE_SPELL_OFFENSIVE_SLOT3 = 213, + EQUIPABLE_SPELL_OFFENSIVE_SLOT4 = 214, + EQUIPABLE_SPELL_UTILITY_SLOT1 = 215, + EQUIPABLE_SPELL_DEFENSIVE_SLOT1 = 216, + EQUIPABLE_SPELL_MOBILITY_SLOT1 = 217 }; struct ItemPosCount @@ -1037,7 +1069,9 @@ enum TalentLearnResult TALENT_FAILED_AFFECTING_COMBAT = 5, TALENT_FAILED_CANT_REMOVE_TALENT = 6, TALENT_FAILED_CANT_DO_THAT_CHALLENGE_MODE_ACTIVE = 7, - TALENT_FAILED_REST_AREA = 8 + TALENT_FAILED_REST_AREA = 8, + TALENT_FAILED_UNSPENT_TALENT_POINTS = 9, + TALENT_FAILED_IN_PVP_MATCH = 10 }; struct TC_GAME_API SpecializationInfo @@ -1236,11 +1270,18 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> EnumFlag<ItemSearchLocation> flag = location; if (flag.HasFlag(ItemSearchLocation::Equipment)) + { for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) if (callback(pItem) == ItemSearchCallbackResult::Stop) return false; + for (uint8 i = PROFESSION_SLOT_START; i < PROFESSION_SLOT_END; ++i) + if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (callback(pItem) == ItemSearchCallbackResult::Stop) + return false; + } + if (flag.HasFlag(ItemSearchLocation::Inventory)) { uint8 inventoryEnd = INVENTORY_SLOT_ITEM_START + GetInventorySlotCount(); @@ -1278,10 +1319,19 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> } if (flag.HasFlag(ItemSearchLocation::ReagentBank)) + { + for (uint8 i = REAGENT_BAG_SLOT_START; i < REAGENT_BAG_SLOT_END; ++i) + if (Bag* bag = GetBagByPos(i)) + for (uint32 j = 0; j < GetBagSize(bag); ++j) + if (Item* pItem = GetItemInBag(bag, j)) + if (callback(pItem) == ItemSearchCallbackResult::Stop) + return false; + for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i) if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) if (callback(pItem) == ItemSearchCallbackResult::Stop) return false; + } return true; } @@ -1363,7 +1413,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void AutoUnequipOffhandIfNeed(bool force = false); void EquipChildItem(uint8 parentBag, uint8 parentSlot, Item* parentItem); void AutoUnequipChildItem(Item* parentItem); - bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count); + bool StoreNewItemInBestSlots(uint32 itemId, uint32 amount, ItemContext context); void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, ItemContext context = ItemContext::NONE, bool broadcast = false, bool createdByPlayer = false); void AutoStoreLoot(uint32 loot_id, LootStore const& store, ItemContext context = ItemContext::NONE, bool broadcast = false, bool createdByPlayer = false) { AutoStoreLoot(NULL_BAG, NULL_SLOT, loot_id, store, context, broadcast, createdByPlayer); } void StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* loot, AELootResult* aeResult = nullptr); @@ -1481,7 +1531,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQuests = false); void SendPreparedGossip(WorldObject* source); - void OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 menuId); + void OnGossipSelect(WorldObject* source, int32 gossipOptionId, uint32 menuId); uint32 GetGossipTextId(uint32 menuId, WorldObject* source); uint32 GetGossipTextId(WorldObject* source); @@ -2770,8 +2820,6 @@ 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/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 38fec84894d..bb35bf3db24 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -595,7 +595,9 @@ float const m_diminishing_k[MAX_CLASSES] = 0.9830f, // Warlock 0.9830f, // Monk 0.9720f, // Druid - 0.9830f // Demon Hunter + 0.9830f, // Demon Hunter + 0.9880f, // Evoker + 1.0f, // Adventurer }; // helper function @@ -634,7 +636,9 @@ float const parry_cap[MAX_CLASSES] = 0.0f, // Warlock 90.6425f, // Monk 0.0f, // Druid - 65.631440f // Demon Hunter + 65.631440f, // Demon Hunter + 0.0f, // Evoker + 0.0f, // Adventurer }; void Player::UpdateParryPercentage() @@ -673,7 +677,9 @@ float const dodge_cap[MAX_CLASSES] = 150.375940f, // Warlock 145.560408f, // Monk 116.890707f, // Druid - 145.560408f // Demon Hunter + 145.560408f, // Demon Hunter + 145.560408f, // Evoker + 0.0f, // Adventurer }; void Player::UpdateDodgePercentage() diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 3580a5c2824..96e0da89968 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -6645,6 +6645,11 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui { return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto); }); + + TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_BY_LABEL, [caster, spellProto](AuraEffect const* aurEff) -> bool + { + return aurEff->GetCasterGUID() == caster->GetGUID() && spellProto->HasLabel(aurEff->GetMiscValue()); + }); } if (damagetype == DOT) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 9f8c2fbafcb..cd0c4858597 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -188,6 +188,7 @@ enum UnitMods UNIT_MOD_ARCANE_CHARGES, UNIT_MOD_FURY, UNIT_MOD_PAIN, + UNIT_MOD_ESSENCE, UNIT_MOD_ARMOR, // UNIT_MOD_ARMOR..UNIT_MOD_RESISTANCE_ARCANE must be in existed order, it's accessed by index values of SpellSchools enum. UNIT_MOD_RESISTANCE_HOLY, UNIT_MOD_RESISTANCE_FIRE, @@ -207,7 +208,7 @@ enum UnitMods UNIT_MOD_RESISTANCE_START = UNIT_MOD_ARMOR, UNIT_MOD_RESISTANCE_END = UNIT_MOD_RESISTANCE_ARCANE + 1, UNIT_MOD_POWER_START = UNIT_MOD_MANA, - UNIT_MOD_POWER_END = UNIT_MOD_PAIN + 1 + UNIT_MOD_POWER_END = UNIT_MOD_ESSENCE + 1 }; static_assert(UNIT_MOD_POWER_END - UNIT_MOD_POWER_START == MAX_POWERS, "UnitMods powers section does not match Powers enum!"); diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index c71b061b07e..0f9b5e35032 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -418,6 +418,8 @@ enum MovementFlags3 : uint32 { MOVEMENTFLAG3_NONE = 0x00000000, MOVEMENTFLAG3_DISABLE_INERTIA = 0x00000001, + MOVEMENTFLAG3_CAN_ADV_FLY = 0x00000002, + MOVEMENTFLAG3_ADV_FLYING = 0x00000004, }; enum HitInfo |
