diff options
| author | Shauren <shauren.trinity@gmail.com> | 2019-11-22 11:02:04 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2019-11-22 11:02:04 +0100 |
| commit | ec9d624aec9e0a39b1bcee7d4077f46be358faad (patch) | |
| tree | e5aceec6e06d537fb1966f0ccab913f8558b3b8e /src/server/game/Entities | |
| parent | 2a46798362c7e39544886e406a619360096298a1 (diff) | |
Core/Items: Implement azerite essences
* Implement inspecting heart of azeroth data
* Fixed heart of azeroth item level - bonuses now apply
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 43 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp | 211 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h | 28 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 79 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.h | 28 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/ItemDefines.h | 16 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateField.h | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateFields.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateFields.h | 5 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 138 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 15 |
11 files changed, 524 insertions, 48 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index db212bf76d5..7266be71202 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -18,6 +18,8 @@ #include "GameObject.h" #include "ArtifactPackets.h" +#include "AzeriteItem.h" +#include "AzeritePackets.h" #include "Battleground.h" #include "CellImpl.h" #include "CreatureAISelector.h" @@ -1983,18 +1985,39 @@ void GameObject::Use(Unit* user) if (!sConditionMgr->IsPlayerMeetingCondition(player, playerCondition)) return; - Aura const* artifactAura = player->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE); - Item const* item = artifactAura ? player->GetItemByGuid(artifactAura->GetCastItemGUID()) : nullptr; - if (!item) + switch (info->itemForge.ForgeType) { - player->SendDirectMessage(WorldPackets::Misc::DisplayGameError(GameError::ERR_MUST_EQUIP_ARTIFACT).Write()); - return; - } + case 0: // Artifact Forge + case 1: // Relic Forge + { + Aura const* artifactAura = player->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE); + Item const* item = artifactAura ? player->GetItemByGuid(artifactAura->GetCastItemGUID()) : nullptr; + if (!item) + { + player->SendDirectMessage(WorldPackets::Misc::DisplayGameError(GameError::ERR_MUST_EQUIP_ARTIFACT).Write()); + return; + } + + WorldPackets::Artifact::ArtifactForgeOpened artifactForgeOpened; + artifactForgeOpened.ArtifactGUID = item->GetGUID(); + artifactForgeOpened.ForgeGUID = GetGUID(); + player->SendDirectMessage(artifactForgeOpened.Write()); + break; + } + case 2: // Heart Forge + { + Item const* item = player->GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH); + if (!item) + return; - WorldPackets::Artifact::ArtifactForgeOpened artifactForgeOpened; - artifactForgeOpened.ArtifactGUID = item->GetGUID(); - artifactForgeOpened.ForgeGUID = GetGUID(); - player->SendDirectMessage(artifactForgeOpened.Write()); + WorldPackets::Azerite::AzeriteEssenceForgeOpened azeriteEssenceForgeOpened; + azeriteEssenceForgeOpened.ForgeGUID = GetGUID(); + player->SendDirectMessage(azeriteEssenceForgeOpened.Write()); + break; + } + default: + break; + } return; } case GAMEOBJECT_TYPE_UI_LINK: diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp index 8d9367d839a..1eb600e5722 100644 --- a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp @@ -19,6 +19,7 @@ #include "AzeritePackets.h" #include "DatabaseEnv.h" #include "DB2Stores.h" +#include "GameObject.h" #include "GameTime.h" #include "Player.h" #include <boost/date_time/gregorian/gregorian_types.hpp> @@ -39,6 +40,7 @@ bool AzeriteItem::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player cons SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), 1); SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::KnowledgeLevel), GetCurrentKnowledgeLevel()); + UnlockDefaultMilestones(); return true; } @@ -55,10 +57,49 @@ void AzeriteItem::SaveToDB(CharacterDatabaseTransaction& trans) stmt->setUInt64(1, m_azeriteItemData->Xp); stmt->setUInt32(2, m_azeriteItemData->Level); stmt->setUInt32(3, m_azeriteItemData->KnowledgeLevel); + std::size_t specIndex = 0; + for (; specIndex < m_azeriteItemData->SelectedEssences.size(); ++specIndex) + { + stmt->setUInt32(4 + specIndex * 4, m_azeriteItemData->SelectedEssences[specIndex].SpecializationID); + for (std::size_t j = 0; j < MAX_AZERITE_ESSENCE_SLOT; ++j) + stmt->setUInt32(5 + specIndex * 4 + j, m_azeriteItemData->SelectedEssences[specIndex].AzeriteEssenceID[j]); + } + for (; specIndex < MAX_SPECIALIZATIONS; ++specIndex) + { + stmt->setUInt32(4 + specIndex * 4, 0); + for (std::size_t j = 0; j < MAX_AZERITE_ESSENCE_SLOT; ++j) + stmt->setUInt32(5 + specIndex * 4 + j, 0); + } + + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + for (uint32 azeriteItemMilestonePowerId : m_azeriteItemData->UnlockedEssenceMilestones) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, azeriteItemMilestonePowerId); + trans->Append(stmt); + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); + + for (UF::UnlockedAzeriteEssence const& azeriteEssence : m_azeriteItemData->UnlockedEssences) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, azeriteEssence.AzeriteEssenceID); + stmt->setUInt32(2, azeriteEssence.Rank); + trans->Append(stmt); + } } -void AzeriteItem::LoadAzeriteItemData(AzeriteItemData& azeriteItemData) +void AzeriteItem::LoadAzeriteItemData(Player* owner, AzeriteItemData& azeriteItemData) { bool needSave = false; @@ -94,6 +135,37 @@ void AzeriteItem::LoadAzeriteItemData(AzeriteItemData& azeriteItemData) SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Xp), azeriteItemData.Xp); SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), azeriteItemData.Level); SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::KnowledgeLevel), azeriteItemData.KnowledgeLevel); + for (uint32 azeriteItemMilestonePowerId : azeriteItemData.AzeriteItemMilestonePowers) + AddUnlockedEssenceMilestone(azeriteItemMilestonePowerId); + + UnlockDefaultMilestones(); + + for (AzeriteEssencePowerEntry const* unlockedAzeriteEssence : azeriteItemData.UnlockedAzeriteEssences) + SetEssenceRank(unlockedAzeriteEssence->AzeriteEssenceID, unlockedAzeriteEssence->Tier); + + for (AzeriteItemSelectedEssencesData const& selectedEssenceData : azeriteItemData.SelectedAzeriteEssences) + { + if (!selectedEssenceData.SpecializationId) + continue; + + auto selectedEssences = AddDynamicUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::SelectedEssences)); + selectedEssences.ModifyValue(&UF::SelectedAzeriteEssences::SpecializationID).SetValue(selectedEssenceData.SpecializationId); + for (uint32 i = 0; i < MAX_AZERITE_ESSENCE_SLOT; ++i) + { + // Check if essence was unlocked + if (!GetEssenceRank(selectedEssenceData.AzeriteEssenceId[i])) + continue; + + selectedEssences.ModifyValue(&UF::SelectedAzeriteEssences::AzeriteEssenceID, i).SetValue(selectedEssenceData.AzeriteEssenceId[i]); + } + + if (owner->GetPrimarySpecialization() == selectedEssenceData.SpecializationId) + selectedEssences.ModifyValue(&UF::SelectedAzeriteEssences::Enabled).SetValue(1); + } + + // add selected essences for current spec + if (!GetSelectedAzeriteEssences()) + CreateSelectedAzeriteEssences(owner->GetPrimarySpecialization()); if (needSave) { @@ -111,12 +183,15 @@ void AzeriteItem::DeleteFromDB(CharacterDatabaseTransaction& trans) stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); - Item::DeleteFromDB(trans); -} + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); -uint32 AzeriteItem::GetItemLevel(Player const* /*owner*/) const -{ - return sAzeriteLevelInfoStore.AssertEntry(m_azeriteItemData->Level)->ItemLevel; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + Item::DeleteFromDB(trans); } uint32 AzeriteItem::GetCurrentKnowledgeLevel() @@ -176,6 +251,7 @@ void AzeriteItem::GiveXP(uint64 xp) owner->_ApplyItemBonuses(this, GetSlot(), false); SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), level); + UnlockDefaultMilestones(); owner->UpdateCriteria(CRITERIA_TYPE_HEART_OF_AZEROTH_LEVEL_REACHED, level); if (IsEquipped()) @@ -191,6 +267,70 @@ void AzeriteItem::GiveXP(uint64 xp) owner->SendDirectMessage(xpGain.Write()); } +GameObject const* AzeriteItem::FindHeartForge(Player const* owner) +{ + if (GameObject const* forge = owner->FindNearestGameObjectOfType(GAMEOBJECT_TYPE_ITEM_FORGE, 40.0f)) + if (forge->GetGOInfo()->itemForge.ForgeType == 2) + return forge; + + return nullptr; +} + +bool AzeriteItem::CanUseEssences() const +{ + if (PlayerConditionEntry const* condition = sPlayerConditionStore.LookupEntry(PLAYER_CONDITION_ID_UNLOCKED_AZERITE_ESSENCES)) + return ConditionMgr::IsPlayerMeetingCondition(GetOwner(), condition); + + return false; +} + +bool AzeriteItem::HasUnlockedEssenceSlot(uint8 slot) const +{ + AzeriteItemMilestonePowerEntry const* milestone = sDB2Manager.GetAzeriteItemMilestonePower(slot); + return m_azeriteItemData->UnlockedEssenceMilestones.FindIndex(milestone->ID) != -1; +} + +uint32 AzeriteItem::GetEssenceRank(uint32 azeriteEssenceId) const +{ + int32 index = m_azeriteItemData->UnlockedEssences.FindIndexIf([azeriteEssenceId](UF::UnlockedAzeriteEssence const& essence) + { + return essence.AzeriteEssenceID == azeriteEssenceId; + }); + + if (index < 0) + return 0; + + return m_azeriteItemData->UnlockedEssences[index].Rank; +} + +void AzeriteItem::SetEssenceRank(uint32 azeriteEssenceId, uint32 rank) +{ + int32 index = m_azeriteItemData->UnlockedEssences.FindIndexIf([azeriteEssenceId](UF::UnlockedAzeriteEssence const& essence) + { + return essence.AzeriteEssenceID == azeriteEssenceId; + }); + + if (!rank && index >= 0) + { + RemoveDynamicUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::UnlockedEssences), index); + return; + } + + if (!sDB2Manager.GetAzeriteEssencePower(azeriteEssenceId, rank)) + return; + + if (index < 0) + { + UF::UnlockedAzeriteEssence& unlockedEssence = AddDynamicUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData) + .ModifyValue(&UF::AzeriteItemData::UnlockedEssences)); + unlockedEssence.AzeriteEssenceID = azeriteEssenceId; + unlockedEssence.Rank = rank; + } + else + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::UnlockedEssences, index) + .ModifyValue(&UF::UnlockedAzeriteEssence::Rank), rank); +} + UF::SelectedAzeriteEssences const* AzeriteItem::GetSelectedAzeriteEssences() const { for (UF::SelectedAzeriteEssences const& essences : m_azeriteItemData->SelectedEssences) @@ -200,6 +340,34 @@ UF::SelectedAzeriteEssences const* AzeriteItem::GetSelectedAzeriteEssences() con return nullptr; } +void AzeriteItem::SetSelectedAzeriteEssences(uint32 specializationId) +{ + int32 index = m_azeriteItemData->SelectedEssences.FindIndexIf([](UF::SelectedAzeriteEssences const& essences) { return essences.Enabled == 1; }); + if (index >= 0) + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::SelectedEssences, index) + .ModifyValue(&UF::SelectedAzeriteEssences::Enabled), 0); + + index = m_azeriteItemData->SelectedEssences.FindIndexIf([specializationId](UF::SelectedAzeriteEssences const& essences) + { + return essences.SpecializationID == specializationId; + }); + + if (index >= 0) + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::SelectedEssences, index) + .ModifyValue(&UF::SelectedAzeriteEssences::Enabled), 1); + else + CreateSelectedAzeriteEssences(specializationId); +} + +void AzeriteItem::SetSelectedAzeriteEssence(uint8 slot, uint32 azeriteEssenceId) +{ + ASSERT(slot < MAX_AZERITE_ESSENCE_SLOT); + int32 index = m_azeriteItemData->SelectedEssences.FindIndexIf([](UF::SelectedAzeriteEssences const& essences) { return essences.Enabled == 1; }); + ASSERT(index >= 0); + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::SelectedEssences, index) + .ModifyValue(&UF::SelectedAzeriteEssences::AzeriteEssenceID, slot), azeriteEssenceId); +} + void AzeriteItem::BuildValuesCreate(ByteBuffer* data, Player const* target) const { UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); @@ -257,3 +425,34 @@ void AzeriteItem::ClearUpdateMask(bool remove) m_values.ClearChangesMask(&AzeriteItem::m_azeriteItemData); Item::ClearUpdateMask(remove); } + +void AzeriteItem::UnlockDefaultMilestones() +{ + bool hasPreviousMilestone = true; + for (AzeriteItemMilestonePowerEntry const* milestone : sDB2Manager.GetAzeriteItemMilestonePowers()) + { + if (!hasPreviousMilestone) + break; + + if (milestone->RequiredLevel > int32(GetLevel())) + break; + + if (HasUnlockedEssenceMilestone(milestone->ID)) + continue; + + if (milestone->AutoUnlock) + { + AddUnlockedEssenceMilestone(milestone->ID); + hasPreviousMilestone = true; + } + else + hasPreviousMilestone = false; + } +} + +void AzeriteItem::CreateSelectedAzeriteEssences(uint32 specializationId) +{ + auto selectedEssences = AddDynamicUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::SelectedEssences)); + selectedEssences.ModifyValue(&UF::SelectedAzeriteEssences::SpecializationID).SetValue(specializationId); + selectedEssences.ModifyValue(&UF::SelectedAzeriteEssences::Enabled).SetValue(1); +} diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h index 6c08ab57f9e..830b71b9a98 100644 --- a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h @@ -23,6 +23,8 @@ constexpr uint32 ITEM_ID_HEART_OF_AZEROTH = 158075; constexpr uint32 MAX_AZERITE_ITEM_LEVEL = 70; constexpr uint32 MAX_AZERITE_ITEM_KNOWLEDGE_LEVEL = 30; +constexpr uint32 PLAYER_CONDITION_ID_UNLOCKED_AZERITE_ESSENCES = 69048; +constexpr uint32 SPELL_ID_HEART_ESSENCE_ACTION_BAR_OVERRIDE = 298554; class TC_GAME_API AzeriteItem : public Item { @@ -32,11 +34,9 @@ public: bool Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owner) override; void SaveToDB(CharacterDatabaseTransaction& trans) override; - void LoadAzeriteItemData(AzeriteItemData& azeriteItem); + void LoadAzeriteItemData(Player* owner, AzeriteItemData& azeriteItem); void DeleteFromDB(CharacterDatabaseTransaction& trans) override; - uint32 GetItemLevel(Player const* owner) const override; - uint32 GetLevel() const { return m_azeriteItemData->Level; } uint32 GetEffectiveLevel() const { @@ -47,11 +47,29 @@ public: return level; } + // Gaining artifact power static uint32 GetCurrentKnowledgeLevel(); static uint64 CalcTotalXPToNextLevel(uint32 level, uint32 knowledgeLevel); void GiveXP(uint64 xp); + // Essences + // C_AzeriteEssence.CanOpenUI - checks PlayerCondition 69048 - HasAura(261912) || RewardedQuest(57010) || IsOnQuest(57010) + static GameObject const* FindHeartForge(Player const* owner); + bool CanUseEssences() const; + bool HasUnlockedEssenceSlot(uint8 slot) const; + bool HasUnlockedEssenceMilestone(uint32 azeriteItemMilestonePowerId) const { return m_azeriteItemData->UnlockedEssenceMilestones.FindIndex(azeriteItemMilestonePowerId) != -1; } + void AddUnlockedEssenceMilestone(uint32 azeriteItemMilestonePowerId) + { + AddDynamicUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData) + .ModifyValue(&UF::AzeriteItemData::UnlockedEssenceMilestones)) = azeriteItemMilestonePowerId; + } + + uint32 GetEssenceRank(uint32 azeriteEssenceId) const; + void SetEssenceRank(uint32 azeriteEssenceId, uint32 rank); + UF::SelectedAzeriteEssences const* GetSelectedAzeriteEssences() const; + void SetSelectedAzeriteEssences(uint32 specializationId); + void SetSelectedAzeriteEssence(uint8 slot, uint32 azeriteEssenceId); void BuildValuesCreate(ByteBuffer* data, Player const* target) const override; void BuildValuesUpdate(ByteBuffer* data, Player const* target) const override; @@ -59,6 +77,10 @@ public: void ClearUpdateMask(bool remove) override; UF::UpdateField<UF::AzeriteItemData, 0, TYPEID_AZERITE_ITEM> m_azeriteItemData; + +private: + void UnlockDefaultMilestones(); + void CreateSelectedAzeriteEssences(uint32 specializationId); }; #endif // AzeriteItem_h__ diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index f0ec7dbd383..c702be312db 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -284,7 +284,8 @@ static uint32 const IllusionModifierMaskSpecSpecific = (1 << ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4); void ItemAdditionalLoadInfo::Init(std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo>* loadInfo, - PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult) + PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, + PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult) { // 0 1 2 3 4 5 // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid ... @@ -321,7 +322,16 @@ void ItemAdditionalLoadInfo::Init(std::unordered_map<ObjectGuid::LowType, ItemAd } // 0 1 2 3 - // SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN ... + // SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel, + // 4 5 6 7 + // iz.selectedAzeriteEssences1specId, iz.selectedAzeriteEssences1azeriteEssenceId1, iz.selectedAzeriteEssences1azeriteEssenceId2, iz.selectedAzeriteEssences1azeriteEssenceId3, + // 8 9 10 11 + // iz.selectedAzeriteEssences2specId, iz.selectedAzeriteEssences2azeriteEssenceId1, iz.selectedAzeriteEssences2azeriteEssenceId2, iz.selectedAzeriteEssences2azeriteEssenceId3, + // 12 13 14 15 + // iz.selectedAzeriteEssences3specId, iz.selectedAzeriteEssences3azeriteEssenceId1, iz.selectedAzeriteEssences3azeriteEssenceId2, iz.selectedAzeriteEssences3azeriteEssenceId3, + // 16 17 18 19 + // iz.selectedAzeriteEssences4specId, iz.selectedAzeriteEssences4azeriteEssenceId1, iz.selectedAzeriteEssences4azeriteEssenceId2, iz.selectedAzeriteEssences4azeriteEssenceId3 + // FROM item_instance_azerite iz INNER JOIN ... if (azeriteItemResult) { do @@ -333,9 +343,59 @@ void ItemAdditionalLoadInfo::Init(std::unordered_map<ObjectGuid::LowType, ItemAd info.AzeriteItem->Xp = fields[1].GetUInt64(); info.AzeriteItem->Level = fields[2].GetUInt32(); info.AzeriteItem->KnowledgeLevel = fields[3].GetUInt32(); + for (std::size_t i = 0; i < MAX_SPECIALIZATIONS; ++i) + { + uint32 specializationId = fields[4 + i * 4].GetUInt32(); + if (!sChrSpecializationStore.LookupEntry(specializationId)) + continue; + + info.AzeriteItem->SelectedAzeriteEssences[i].SpecializationId = specializationId; + for (std::size_t j = 0; j < MAX_AZERITE_ESSENCE_SLOT; ++j) + { + AzeriteEssenceEntry const* azeriteEssence = sAzeriteEssenceStore.LookupEntry(fields[5 + i * 4 + j].GetUInt32()); + if (!azeriteEssence || !sDB2Manager.IsSpecSetMember(azeriteEssence->SpecSetID, specializationId)) + continue; + + info.AzeriteItem->SelectedAzeriteEssences[i].AzeriteEssenceId[j] = azeriteEssence->ID; + } + } } while (azeriteItemResult->NextRow()); } + + // 0 1 + // SELECT iamp.itemGuid, iamp.azeriteItemMilestonePowerId FROM item_instance_azerite_milestone_power iamp INNER JOIN ... + if (azeriteItemMilestonePowersResult) + { + do + { + Field* fields = azeriteItemMilestonePowersResult->Fetch(); + ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()]; + if (!info.AzeriteItem) + info.AzeriteItem = boost::in_place(); + info.AzeriteItem->AzeriteItemMilestonePowers.push_back(fields[1].GetUInt32()); + } + while (azeriteItemMilestonePowersResult->NextRow()); + } + + // 0 1 2 + // SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN ... + if (azeriteItemUnlockedEssencesResult) + { + do + { + Field* fields = azeriteItemUnlockedEssencesResult->Fetch(); + if (AzeriteEssencePowerEntry const* azeriteEssencePower = sDB2Manager.GetAzeriteEssencePower(fields[1].GetUInt32(), fields[2].GetUInt32())) + { + ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()]; + if (!info.AzeriteItem) + info.AzeriteItem = boost::in_place(); + + info.AzeriteItem->UnlockedAzeriteEssences.push_back(azeriteEssencePower); + } + } + while (azeriteItemUnlockedEssencesResult->NextRow()); + } } Item::Item() @@ -2180,21 +2240,28 @@ void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB() uint32 Item::GetItemLevel(Player const* owner) const { + ItemTemplate const* itemTemplate = GetTemplate(); uint32 minItemLevel = owner->m_unitData->MinItemLevel; uint32 minItemLevelCutoff = owner->m_unitData->MinItemLevelCutoff; - uint32 maxItemLevel = GetTemplate()->GetFlags3() & ITEM_FLAG3_IGNORE_ITEM_LEVEL_CAP_IN_PVP ? 0 : owner->m_unitData->MaxItemLevel; + uint32 maxItemLevel = itemTemplate->GetFlags3() & ITEM_FLAG3_IGNORE_ITEM_LEVEL_CAP_IN_PVP ? 0 : owner->m_unitData->MaxItemLevel; bool pvpBonus = owner->IsUsingPvpItemLevels(); - return Item::GetItemLevel(GetTemplate(), _bonusData, owner->getLevel(), GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL), - minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus); + uint32 azeriteLevel = 0; + if (AzeriteItem const* azeriteItem = ToAzeriteItem()) + azeriteLevel = azeriteItem->GetEffectiveLevel(); + return Item::GetItemLevel(itemTemplate, _bonusData, owner->getLevel(), GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL), + minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus, azeriteLevel); } uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, - uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus) + uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus, uint32 azeriteLevel) { if (!itemTemplate) return MIN_ITEM_LEVEL; uint32 itemLevel = itemTemplate->GetBaseItemLevel(); + if (AzeriteLevelInfoEntry const* azeriteLevelInfo = sAzeriteLevelInfoStore.LookupEntry(azeriteLevel)) + itemLevel = azeriteLevelInfo->ItemLevel; + if (ScalingStatDistributionEntry const* ssd = sScalingStatDistributionStore.LookupEntry(bonusData.ScalingStatDistribution)) { if (fixedLevel) diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index e029bc0ee05..5b5cb12a569 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -110,29 +110,39 @@ private: struct ArtifactPowerData { - uint32 ArtifactPowerId; - uint8 PurchasedRank; - uint8 CurrentRankWithBonus; + uint32 ArtifactPowerId = 0; + uint8 PurchasedRank = 0; + uint8 CurrentRankWithBonus = 0; }; struct ArtifactData { - uint64 Xp; - uint32 ArtifactAppearanceId; - uint32 ArtifactTierId; + uint64 Xp = 0; + uint32 ArtifactAppearanceId = 0; + uint32 ArtifactTierId = 0; std::vector<ArtifactPowerData> ArtifactPowers; }; +struct AzeriteItemSelectedEssencesData +{ + uint32 SpecializationId = 0; + std::array<uint32, MAX_AZERITE_ESSENCE_SLOT> AzeriteEssenceId = { }; +}; + struct AzeriteItemData { uint64 Xp; uint32 Level; uint32 KnowledgeLevel; + std::vector<uint32> AzeriteItemMilestonePowers; + std::vector<AzeriteEssencePowerEntry const*> UnlockedAzeriteEssences; + std::array<AzeriteItemSelectedEssencesData, MAX_SPECIALIZATIONS> SelectedAzeriteEssences = { }; }; struct ItemAdditionalLoadInfo { - static void Init(std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo>* loadInfo, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult); + static void Init(std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo>* loadInfo, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, + PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult); Optional<ArtifactData> Artifact; Optional<AzeriteItemData> AzeriteItem; @@ -308,9 +318,9 @@ class TC_GAME_API Item : public Object bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); } bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); } uint32 GetQuality() const { return _bonusData.Quality; } - virtual uint32 GetItemLevel(Player const* owner) const; + uint32 GetItemLevel(Player const* owner) const; static uint32 GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, - uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus); + uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus, uint32 azeriteLevel); int32 GetRequiredLevel() const; int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return _bonusData.ItemStatType[index]; } int32 GetItemStatValue(uint32 index, Player const* owner) const; diff --git a/src/server/game/Entities/Item/ItemDefines.h b/src/server/game/Entities/Item/ItemDefines.h index 3bb7eb7296a..0b34fe56b4a 100644 --- a/src/server/game/Entities/Item/ItemDefines.h +++ b/src/server/game/Entities/Item/ItemDefines.h @@ -217,4 +217,20 @@ enum ItemModifier : uint16 MAX_ITEM_MODIFIERS }; +enum class AzeriteEssenceActivateResult : uint32 +{ + None = 0, + EssenceNotUnlocked = 2, // Arg: AzeriteEssenceID + CantDoThatRightNow = 3, + AffectingCombat = 4, + CantRemoveEssence = 5, // Arg: SpellID of active essence on cooldown + ChallengeModeActive = 6, + NotInRestArea = 7, + ConditionFailed = 8, + SlotLocked = 9, + NotAtForge = 10, + HeartLevelTooLow = 11, // Arg: RequiredLevel + NotEquipped = 12 +}; + #endif // ItemDefines_h__ diff --git a/src/server/game/Entities/Object/Updates/UpdateField.h b/src/server/game/Entities/Object/Updates/UpdateField.h index f99960fa451..d7a279ada4d 100644 --- a/src/server/game/Entities/Object/Updates/UpdateField.h +++ b/src/server/game/Entities/Object/Updates/UpdateField.h @@ -582,6 +582,11 @@ namespace UF return std::end(_values); } + std::size_t size() const + { + return Size; + } + T const& operator[](uint32 index) const { return _values[index]; diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index 141f6f27317..04c2fd78b6e 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -470,7 +470,7 @@ void ContainerData::ClearChangesMask() _changesMask.ResetAll(); } -void AzeriteEmpoweredItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const +void AzeriteEmpoweredItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteEmpoweredItem const* owner, Player const* receiver) const { for (std::size_t i = 0; i < 5; ++i) { @@ -478,7 +478,7 @@ void AzeriteEmpoweredItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<Updat } } -void AzeriteEmpoweredItemData::WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const +void AzeriteEmpoweredItemData::WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteEmpoweredItem const* owner, Player const* receiver) const { UpdateMask<6> const& changesMask = _changesMask; data.WriteBits(changesMask.GetBlocksMask(0), 1); diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index 75c15ad52d8..e6f207e5049 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -26,6 +26,7 @@ #include "UpdateMask.h" class AreaTrigger; +class AzeriteEmpoweredItem; class AzeriteItem; class Bag; class ByteBuffer; @@ -130,8 +131,8 @@ struct AzeriteEmpoweredItemData : public IsUpdateFieldStructureTag, public HasCh { UpdateFieldArray<int32, 5, 0, 1> Selections; - void WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const; - void WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const; + void WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteEmpoweredItem const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteEmpoweredItem const* owner, Player const* receiver) const; void ClearChangesMask(); }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3b1eebbc10b..b5a96465e79 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3225,7 +3225,7 @@ bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const return false; } -void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/) +void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/, bool suppressMessaging /*= false*/) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); @@ -3239,6 +3239,7 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/ { WorldPackets::Spells::LearnedSpells packet; packet.SpellID.push_back(spell_id); + packet.SuppressMessaging = suppressMessaging; GetSession()->SendPacket(packet.Write()); } @@ -3262,7 +3263,7 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/ } } -void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) +void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_low_rank /*= true*/, bool suppressMessaging /*= false*/) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); if (itr == m_spells.end()) @@ -3430,6 +3431,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank) { WorldPackets::Spells::UnlearnedSpells unlearnedSpells; unlearnedSpells.SpellID.push_back(spell_id); + unlearnedSpells.SuppressMessaging = suppressMessaging; SendDirectMessage(unlearnedSpells.Write()); } } @@ -4053,6 +4055,14 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER_BY_OWNER); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE_BY_OWNER); + stmt->setUInt64(0, guid); + trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER); stmt->setUInt64(0, guid); trans->Append(stmt); @@ -7325,6 +7335,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemA if (updateItemAuras) ApplyItemDependentAuras(item, apply); ApplyArtifactPowers(item, apply); + ApplyAzeritePowers(item, apply); ApplyEnchantment(item, apply); TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); @@ -7910,6 +7921,90 @@ void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const } +void Player::ApplyAzeritePowers(Item* item, bool apply) +{ + if (AzeriteItem* azeriteItem = item->ToAzeriteItem()) + { + // milestone powers + for (uint32 azeriteItemMilestonePowerId : azeriteItem->m_azeriteItemData->UnlockedEssenceMilestones) + ApplyAzeriteItemMilestonePower(item, sAzeriteItemMilestonePowerStore.AssertEntry(azeriteItemMilestonePowerId), apply); + + // essences + if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences()) + for (uint8 slot = 0; slot < MAX_AZERITE_ESSENCE_SLOT; ++slot) + if (selectedEssences->AzeriteEssenceID[slot]) + ApplyAzeriteEssence(item, selectedEssences->AzeriteEssenceID[slot], azeriteItem->GetEssenceRank(selectedEssences->AzeriteEssenceID[slot]), + AzeriteItemMilestoneType(sDB2Manager.GetAzeriteItemMilestonePower(slot)->Type) == AzeriteItemMilestoneType::MajorEssence, apply); + + return; + } +} + +void Player::ApplyAzeriteItemMilestonePower(Item* item, AzeriteItemMilestonePowerEntry const* azeriteItemMilestonePower, bool apply) +{ + AzeriteItemMilestoneType type = AzeriteItemMilestoneType(azeriteItemMilestonePower->Type); + if (type == AzeriteItemMilestoneType::BonusStamina) + { + if (AzeritePowerEntry const* azeritePower = sAzeritePowerStore.LookupEntry(azeriteItemMilestonePower->AzeritePowerID)) + { + if (apply) + CastSpell(this, azeritePower->SpellID, true, item); + else + RemoveAurasDueToItemSpell(azeritePower->SpellID, item->GetGUID()); + } + } +} + +void Player::ApplyAzeriteEssence(Item* item, uint32 azeriteEssenceId, uint32 rank, bool major, bool apply) +{ + for (uint32 currentRank = 1; currentRank <= rank; ++currentRank) + { + if (AzeriteEssencePowerEntry const* azeriteEssencePower = sDB2Manager.GetAzeriteEssencePower(azeriteEssenceId, currentRank)) + { + ApplyAzeriteEssencePower(item, azeriteEssencePower, major, apply); + if (major && currentRank == 1) + { + if (apply) + CastCustomSpell(SPELL_ID_HEART_ESSENCE_ACTION_BAR_OVERRIDE, SPELLVALUE_BASE_POINT0, azeriteEssencePower->MajorPowerDescription, this, TRIGGERED_FULL_MASK); + else + RemoveAurasDueToSpell(SPELL_ID_HEART_ESSENCE_ACTION_BAR_OVERRIDE); + } + } + } +} + +void Player::ApplyAzeriteEssencePower(Item* item, AzeriteEssencePowerEntry const* azeriteEssencePower, bool major, bool apply) +{ + if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MinorPowerDescription)) + { + if (apply) + CastSpell(this, powerSpell, true, item); + else + RemoveAurasDueToItemSpell(powerSpell->Id, item->GetGUID()); + } + + if (major) + { + if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MajorPowerDescription)) + { + if (powerSpell->IsPassive()) + { + if (apply) + CastSpell(this, powerSpell, true, item); + else + RemoveAurasDueToItemSpell(powerSpell->Id, item->GetGUID()); + } + else + { + if (apply) + LearnSpell(powerSpell->Id, true, 0, true); + else + RemoveSpell(powerSpell->Id, false, false, true); + } + } + } +} + void Player::CastItemCombatSpell(DamageInfo const& damageInfo) { Unit* target = damageInfo.GetVictim(); @@ -8215,6 +8310,7 @@ void Player::_RemoveAllItemMods() ApplyItemEquipSpell(m_items[i], false); ApplyEnchantment(m_items[i], false); + ApplyAzeritePowers(m_items[i], false); ApplyArtifactPowers(m_items[i], false); } } @@ -8267,6 +8363,7 @@ void Player::_ApplyAllItemMods() ApplyItemEquipSpell(m_items[i], true); ApplyArtifactPowers(m_items[i], true); + ApplyAzeritePowers(m_items[i], true); ApplyEnchantment(m_items[i], true); } } @@ -18188,6 +18285,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder* holder) _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AZERITE), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES), time_diff); if (IsVoidStorageUnlocked()) @@ -18585,7 +18684,8 @@ void Player::LoadCorpse(PreparedQueryResult result) RemoveAtLoginFlag(AT_LOGIN_RESURRECT); } -void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, uint32 timeDiff) +void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, + PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, uint32 timeDiff) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, @@ -18616,7 +18716,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti //expected to be equipped before offhand items (@todo fixme) std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData; - ItemAdditionalLoadInfo::Init(&additionalData, artifactsResult, azeriteResult); + ItemAdditionalLoadInfo::Init(&additionalData, artifactsResult, azeriteResult, azeriteItemMilestonePowersResult, azeriteItemUnlockedEssencesResult); if (result) { @@ -18642,7 +18742,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti if (addionalDataPtr->AzeriteItem) if (AzeriteItem* azeriteItem = item->ToAzeriteItem()) - azeriteItem->LoadAzeriteItemData(*addionalDataPtr->AzeriteItem); + azeriteItem->LoadAzeriteItemData(this, *addionalDataPtr->AzeriteItem); } ObjectGuid bagGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[43].GetUInt64()) : ObjectGuid::Empty; @@ -19000,7 +19100,7 @@ void Player::_LoadMailedItem(Mail* mail, Field* fields, ItemAdditionalLoadInfo* if (addionalData->AzeriteItem) if (AzeriteItem* azeriteItem = item->ToAzeriteItem()) - azeriteItem->LoadAzeriteItemData(*addionalData->AzeriteItem); + azeriteItem->LoadAzeriteItemData(this, *addionalData->AzeriteItem); } AddMItem(item); @@ -19078,8 +19178,16 @@ void Player::_LoadMail() stmt->setUInt64(0, GetGUID().GetCounter()); PreparedQueryResult azeriteResult = CharacterDatabase.Query(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_MILESTONE_POWER); + stmt->setUInt64(0, GetGUID().GetCounter()); + PreparedQueryResult azeriteItemMilestonePowersResult = CharacterDatabase.Query(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE); + stmt->setUInt64(0, GetGUID().GetCounter()); + PreparedQueryResult azeriteItemUnlockedEssencesResult = CharacterDatabase.Query(stmt); + std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData; - ItemAdditionalLoadInfo::Init(&additionalData, artifactResult, azeriteResult); + ItemAdditionalLoadInfo::Init(&additionalData, artifactResult, azeriteResult, azeriteItemMilestonePowersResult, azeriteItemUnlockedEssencesResult); do { @@ -27070,6 +27178,22 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec) activeGlyphs.IsFullUpdate = true; SendDirectMessage(activeGlyphs.Write()); + if (Item* item = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH)) + { + if (AzeriteItem* azeriteItem = item->ToAzeriteItem()) + { + if (azeriteItem->IsEquipped()) + ApplyAzeritePowers(azeriteItem, false); + + azeriteItem->SetSelectedAzeriteEssences(spec->ID); + + if (azeriteItem->IsEquipped()) + ApplyAzeritePowers(azeriteItem, true); + + azeriteItem->SetState(ITEM_CHANGED, this); + } + } + Unit::AuraEffectList const& shapeshiftAuras = GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); for (AuraEffect* aurEff : shapeshiftAuras) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 07c2f7030c1..0c2131a3e9b 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -39,6 +39,8 @@ struct AchievementEntry; struct AreaTableEntry; struct AreaTriggerEntry; struct ArtifactPowerRankEntry; +struct AzeriteEssencePowerEntry; +struct AzeriteItemMilestonePowerEntry; struct BarberShopStyleEntry; struct CharTitlesEntry; struct ChatChannelsEntry; @@ -751,6 +753,8 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_INVENTORY, PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS, PLAYER_LOGIN_QUERY_LOAD_AZERITE, + PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS, + PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES, PLAYER_LOGIN_QUERY_LOAD_ACTIONS, PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT, PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE, @@ -1543,8 +1547,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const; void SendKnownSpells(); bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, int32 fromSkill = 0); - void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill = 0); - void RemoveSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true); + void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill = 0, bool suppressMessaging = false); + void RemoveSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true, bool suppressMessaging = false); void ResetSpells(bool myClassOnly = false); void LearnCustomSpells(); void LearnDefaultSkills(); @@ -2012,6 +2016,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void UpdateItemSetAuras(bool formChange = false); void ApplyArtifactPowers(Item* item, bool apply); void ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply); + void ApplyAzeritePowers(Item* item, bool apply); + void ApplyAzeriteItemMilestonePower(Item* item, AzeriteItemMilestonePowerEntry const* azeriteItemMilestonePower, bool apply); + void ApplyAzeriteEssence(Item* item, uint32 azeriteEssenceId, uint32 rank, bool major, bool apply); + void ApplyAzeriteEssencePower(Item* item, AzeriteEssencePowerEntry const* azeriteEssencePower, bool major, bool apply); void CastItemCombatSpell(DamageInfo const& damageInfo); void CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto); @@ -2489,7 +2497,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effectResult, uint32 timediff); void _LoadGlyphAuras(); void _LoadBoundInstances(PreparedQueryResult result); - void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, uint32 timeDiff); + void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, + PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, uint32 timeDiff); void _LoadVoidStorage(PreparedQueryResult result); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); |
