aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-11-22 11:02:04 +0100
committerShauren <shauren.trinity@gmail.com>2019-11-22 11:02:04 +0100
commitec9d624aec9e0a39b1bcee7d4077f46be358faad (patch)
treee5aceec6e06d537fb1966f0ccab913f8558b3b8e /src/server/game/Entities
parent2a46798362c7e39544886e406a619360096298a1 (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.cpp43
-rw-r--r--src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp211
-rw-r--r--src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h28
-rw-r--r--src/server/game/Entities/Item/Item.cpp79
-rw-r--r--src/server/game/Entities/Item/Item.h28
-rw-r--r--src/server/game/Entities/Item/ItemDefines.h16
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateField.h5
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.cpp4
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.h5
-rw-r--r--src/server/game/Entities/Player/Player.cpp138
-rw-r--r--src/server/game/Entities/Player/Player.h15
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();