diff options
Diffstat (limited to 'src/server/game/Entities')
| -rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 29 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 350 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/Item.h | 26 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/ItemEnchantmentMgr.cpp | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Item/ItemTemplate.h | 1 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 158 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 17 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 6 | ||||
| -rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 3 |
9 files changed, 568 insertions, 23 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index eb7b3ec9d85..56e4ca80c59 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -25,6 +25,7 @@ #include "GridNotifiersImpl.h" #include "Group.h" #include "GroupMgr.h" +#include "ArtifactPackets.h" #include "MiscPackets.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" @@ -1816,6 +1817,34 @@ void GameObject::Use(Unit* user) player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->barberChair.chairheight), info->barberChair.SitAnimKit); return; } + case GAMEOBJECT_TYPE_ARTIFACT_FORGE: + { + GameObjectTemplate const* info = GetGOInfo(); + if (!info) + return; + + if (user->GetTypeId() != TYPEID_PLAYER) + return; + + Player* player = user->ToPlayer(); + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(info->artifactForge.conditionID1)) + 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) + { + 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()); + return; + } default: if (GetGoType() >= MAX_GAMEOBJECT_TYPE) TC_LOG_ERROR("misc", "GameObject::Use(): unit (type: %u, %s, name: %s) tries to use object (%s, name: %s) of unknown type (%u)", diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index b01508c3933..d79bf16ac07 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -33,6 +33,7 @@ #include "TradeData.h" #include "GameTables.h" #include "CollectionMgr.h" +#include "ArtifactPackets.h" void AddItemsSetItem(Player* player, Item* item) { @@ -308,11 +309,40 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owne SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability); SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability); - for (uint8 i = 0; i < itemProto->Effects.size() && i < 5; ++i) - SetSpellCharges(i, itemProto->Effects[i]->Charges); + for (std::size_t i = 0; i < itemProto->Effects.size(); ++i) + { + if (i < 5) + SetSpellCharges(i, itemProto->Effects[i]->Charges); + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemProto->Effects[i]->SpellID)) + if (spellInfo->HasEffect(SPELL_EFFECT_GIVE_ARTIFACT_POWER)) + if (uint32 artifactKnowledgeLevel = owner->GetCurrency(CURRENCY_TYPE_ARTIFACT_KNOWLEDGE)) + SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, artifactKnowledgeLevel + 1); + } SetUInt32Value(ITEM_FIELD_DURATION, itemProto->GetDuration()); SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, 0); + + if (itemProto->GetArtifactID()) + { + InitArtifactPowers(itemProto->GetArtifactID()); + for (ArtifactAppearanceEntry const* artifactAppearance : sArtifactAppearanceStore) + { + if (ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID)) + { + if (itemProto->GetArtifactID() != artifactAppearanceSet->ArtifactID) + continue; + + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactAppearance->PlayerConditionID)) + if (!sConditionMgr->IsPlayerMeetingCondition(owner, playerCondition)) + continue; + + SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID); + SetAppearanceModId(artifactAppearance->AppearanceModID); + break; + } + } + } + return true; } @@ -481,6 +511,51 @@ void Item::SaveToDB(SQLTransaction& trans) trans->Append(stmt); } + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + if (GetTemplate()->GetArtifactID()) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, GetUInt32Value(ITEM_FIELD_ARTIFACT_XP)); + stmt->setUInt32(2, GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)); + trans->Append(stmt); + + for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers()) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, artifactPower.ArtifactPowerId); + stmt->setUInt8(2, artifactPower.PurchasedRank); + trans->Append(stmt); + } + } + + static ItemModifier const modifiersTable[] = + { + ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, + ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL + }; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + if (std::find_if(std::begin(modifiersTable), std::end(modifiersTable), [this](ItemModifier modifier) { return GetModifier(modifier) != 0; }) != std::end(modifiersTable)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL)); + stmt->setUInt32(2, GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL)); + trans->Append(stmt); + } + break; } case ITEM_REMOVED: @@ -497,6 +572,18 @@ void Item::SaveToDB(SQLTransaction& trans) stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); @@ -534,8 +621,8 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, // 24 25 26 27 28 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 34 35 36 37 - // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3 FROM item_instance + // 29 30 31 32 33 34 35 36 37 38 39 + // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, fixedScalingLevel, artifactKnowledgeLevel FROM item_instance // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB @@ -665,6 +752,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie SetGem(i, &gemData[i]); } + SetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, fields[38].GetUInt32()); + SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[39].GetUInt32()); + if (need_save) // normal item changed state set not work at loading { uint8 index = 0; @@ -680,6 +770,58 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie return true; } +void Item::LoadArtifactData(uint32 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers) +{ + InitArtifactPowers(GetTemplate()->GetArtifactID()); + SetUInt32Value(ITEM_FIELD_ARTIFACT_XP, xp); + SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearanceId); + if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactAppearanceId)) + SetAppearanceModId(artifactAppearance->AppearanceModID); + + uint8 totalPurchasedRanks = 0; + for (ItemDynamicFieldArtifactPowers& power : powers) + { + power.CurrentRankWithBonus += power.PurchasedRank; + totalPurchasedRanks += power.PurchasedRank; + + ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId); + for (uint32 e = SOCK_ENCHANTMENT_SLOT; e <= SOCK_ENCHANTMENT_SLOT_3; ++e) + { + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e)))) + { + for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i) + { + switch (enchant->Effect[i]) + { + case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE: + if (artifactPower->RelicType == enchant->EffectSpellID[i]) + power.CurrentRankWithBonus += enchant->EffectPointsMin[i]; + break; + case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID: + if (artifactPower->ID == enchant->EffectSpellID[i]) + power.CurrentRankWithBonus += enchant->EffectPointsMin[i]; + break; + default: + break; + } + } + } + } + + SetArtifactPower(&power); + } + + for (ItemDynamicFieldArtifactPowers& power : powers) + { + ArtifactPowerEntry const* scaledArtifactPowerEntry = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId); + if (!(scaledArtifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS)) + continue; + + power.CurrentRankWithBonus = totalPurchasedRanks; + SetArtifactPower(&power); + } +} + /*static*/ void Item::DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid) { @@ -1049,6 +1191,9 @@ void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint owner->GetSession()->SendEnchantmentLog(GetOwnerGUID(), caster, GetEntry(), id); } + ApplyArtifactPowerEnchantmentBonuses(GetEnchantmentId(slot), false, owner); + ApplyArtifactPowerEnchantmentBonuses(id, true, owner); + SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET, id); SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET, duration); SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET, charges); @@ -1098,6 +1243,49 @@ ItemDynamicFieldGems const* Item::GetGem(uint16 slot) const void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem) { ASSERT(slot < MAX_GEM_SOCKETS); + _bonusData.GemItemLevelBonus[slot] = 0; + if (ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(gem->ItemId)) + { + if (GemPropertiesEntry const* gemProperties = sGemPropertiesStore.LookupEntry(gemTemplate->GetGemProperties())) + { + if (SpellItemEnchantmentEntry const* gemEnchant = sSpellItemEnchantmentStore.LookupEntry(gemProperties->EnchantID)) + { + BonusData gemBonus; + gemBonus.Initialize(gemTemplate); + for (uint16 bonusListId : gem->BonusListIDs) + if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListId)) + for (ItemBonusEntry const* itemBonus : *bonuses) + gemBonus.AddBonus(itemBonus->Type, itemBonus->Value); + + for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i) + { + switch (gemEnchant->Effect[i]) + { + case ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID: + { + if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(gemEnchant->EffectSpellID[i])) + for (ItemBonusEntry const* itemBonus : *bonuses) + if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL) + _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0]; + break; + } + case ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE: + { + if (uint32 bonusListId = sDB2Manager.GetItemBonusListForItemLevelDelta(int16(sDB2Manager.GetCurveValueAt(CURVE_ID_ARTIFACT_RELIC_ITEM_LEVEL_BONUS, gemTemplate->GetBaseItemLevel() + gemBonus.ItemLevel)))) + if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListId)) + for (ItemBonusEntry const* itemBonus : *bonuses) + if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL) + _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0]; + break; + } + default: + break; + } + } + } + } + } + SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_GEMS, slot, gem); } @@ -1978,6 +2166,9 @@ uint32 Item::GetItemLevel(Player const* owner) const if (ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(GetModifier(ITEM_MODIFIER_UPGRADE_ID))) itemLevel += upgrade->ItemLevelBonus; + for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + itemLevel += _bonusData.GemItemLevelBonus[i]; + return std::min(std::max(itemLevel + _bonusData.ItemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL)); } @@ -2081,6 +2272,154 @@ void Item::AddBonuses(uint32 bonusListID) } } +DynamicFieldStructuredView<ItemDynamicFieldArtifactPowers> Item::GetArtifactPowers() const +{ + return GetDynamicStructuredValues<ItemDynamicFieldArtifactPowers>(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS); +} + +ItemDynamicFieldArtifactPowers const* Item::GetArtifactPower(uint32 artifactPowerId) const +{ + auto indexItr = m_artifactPowerIdToIndex.find(artifactPowerId); + if (indexItr != m_artifactPowerIdToIndex.end()) + return GetDynamicStructuredValue<ItemDynamicFieldArtifactPowers>(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS, indexItr->second); + + return nullptr; +} + +void Item::SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower, bool createIfMissing /*= false*/) +{ + auto indexItr = m_artifactPowerIdToIndex.find(artifactPower->ArtifactPowerId); + uint16 index; + if (indexItr != m_artifactPowerIdToIndex.end()) + index = indexItr->second; + else + { + if (!createIfMissing) + return; + + index = uint16(m_artifactPowerIdToIndex.size()); + m_artifactPowerIdToIndex[artifactPower->ArtifactPowerId] = index; + } + + SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS, index, artifactPower); +} + +void Item::InitArtifactPowers(uint8 artifactId) +{ + for (ArtifactPowerEntry const* artifactPower : sDB2Manager.GetArtifactPowers(artifactId)) + { + if (m_artifactPowerIdToIndex.find(artifactPower->ID) != m_artifactPowerIdToIndex.end()) + continue; + + ItemDynamicFieldArtifactPowers powerData; + memset(&powerData, 0, sizeof(powerData)); + powerData.ArtifactPowerId = artifactPower->ID; + powerData.PurchasedRank = 0; + powerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0; + SetArtifactPower(&powerData, true); + } +} + +uint32 Item::GetTotalPurchasedArtifactPowers() const +{ + uint32 purchasedRanks = 0; + for (ItemDynamicFieldArtifactPowers const& power : GetArtifactPowers()) + purchasedRanks += power.PurchasedRank; + + return purchasedRanks; +} + +void Item::ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner) +{ + if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId)) + { + for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i) + { + switch (enchant->Effect[i]) + { + case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE: + for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers()) + { + if (sArtifactPowerStore.AssertEntry(artifactPower.ArtifactPowerId)->RelicType == enchant->EffectSpellID[i]) + { + ItemDynamicFieldArtifactPowers newPower = artifactPower; + if (apply) + newPower.CurrentRankWithBonus += enchant->EffectPointsMin[i]; + else + newPower.CurrentRankWithBonus -= enchant->EffectPointsMin[i]; + + if (IsEquipped()) + if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, newPower.CurrentRankWithBonus ? newPower.CurrentRankWithBonus - 1 : 0)) + owner->ApplyArtifactPowerRank(this, artifactPowerRank, newPower.CurrentRankWithBonus != 0); + + SetArtifactPower(&newPower); + } + } + break; + case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID: + if (ItemDynamicFieldArtifactPowers const* artifactPower = GetArtifactPower(enchant->EffectSpellID[i])) + { + ItemDynamicFieldArtifactPowers newPower = *artifactPower; + if (apply) + newPower.CurrentRankWithBonus += enchant->EffectPointsMin[i]; + else + newPower.CurrentRankWithBonus -= enchant->EffectPointsMin[i]; + + if (IsEquipped()) + if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower->ArtifactPowerId, newPower.CurrentRankWithBonus ? newPower.CurrentRankWithBonus - 1 : 0)) + owner->ApplyArtifactPowerRank(this, artifactPowerRank, newPower.CurrentRankWithBonus != 0); + + SetArtifactPower(&newPower); + } + break; + default: + break; + } + } + } +} + +void Item::CopyArtifactDataFromParent(Item* parent) +{ + memcpy(_bonusData.GemItemLevelBonus, parent->GetBonus()->GemItemLevelBonus, sizeof(_bonusData.GemItemLevelBonus)); + SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, parent->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)); + SetAppearanceModId(parent->GetAppearanceModId()); +} + +void Item::GiveArtifactXp(int32 amount, Item* sourceItem, uint32 artifactCategoryId) +{ + Player const* owner = GetOwner(); + if (!owner) + return; + + if (artifactCategoryId) + { + if (ArtifactCategoryEntry const* artifactCategory = sArtifactCategoryStore.LookupEntry(artifactCategoryId)) + { + uint32 artifactKnowledgeLevel = 0; + if (sourceItem && sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL)) + artifactKnowledgeLevel = sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL) - 1; + else + artifactKnowledgeLevel = owner->GetCurrency(artifactCategory->ArtifactKnowledgeCurrencyID); + + amount = int32(amount * sDB2Manager.GetCurveValueAt(artifactCategory->ArtifactKnowledgeMultiplierCurveID, artifactKnowledgeLevel)); + if (amount >= 5000) + amount = 50 * (amount / 50); + else if (amount >= 1000) + amount = 25 * (amount / 25); + else if (amount >= 50) + amount = 5 * (amount / 5); + } + } + + ApplyModInt32Value(ITEM_FIELD_ARTIFACT_XP, amount, true); + + WorldPackets::Artifact::ArtifactXpGain artifactXpGain; + artifactXpGain.ArtifactGUID = GetGUID(); + artifactXpGain.Amount = amount; + owner->SendDirectMessage(artifactXpGain.Write()); +} + void BonusData::Initialize(ItemTemplate const* proto) { Quality = proto->GetQuality(); @@ -2099,7 +2438,10 @@ void BonusData::Initialize(ItemTemplate const* proto) ItemStatSocketCostMultiplier[i] = proto->GetItemStatSocketCostMultiplier(i); for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) + { SocketColor[i] = proto->GetSocketColor(i); + GemItemLevelBonus[i] = 0; + } AppearanceModID = 0; if (ItemModifiedAppearanceEntry const* defaultAppearance = sDB2Manager.GetDefaultItemModifiedAppearance(proto->GetId())) diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index fe86591ccc3..204eb8e44d3 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -249,6 +249,7 @@ enum ItemModifier : uint16 ITEM_MODIFIER_CHALLENGE_KEYSTONE_AFFIX_ID_2 = 20, ITEM_MODIFIER_CHALLENGE_KEYSTONE_AFFIX_ID_3 = 21, ITEM_MODIFIER_CHALLENGE_KEYSTONE_IS_CHARGED = 22, + ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL = 23, MAX_ITEM_MODIFIERS }; @@ -273,12 +274,22 @@ struct BonusData float RepairCostMultiplier; uint32 ScalingStatDistribution; + uint32 GemItemLevelBonus[MAX_ITEM_PROTO_SOCKETS]; + void Initialize(ItemTemplate const* proto); void Initialize(WorldPackets::Item::ItemInstance const& itemInstance); void AddBonus(uint32 type, int32 const (&values)[2]); }; #pragma pack(push, 1) +struct ItemDynamicFieldArtifactPowers +{ + uint32 ArtifactPowerId; + uint8 PurchasedRank; + uint8 CurrentRankWithBonus; + uint16 Padding; +}; + struct ItemDynamicFieldGems { uint32 ItemId; @@ -313,6 +324,7 @@ class TC_GAME_API Item : public Object bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry); + void LoadArtifactData(uint32 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers); // must be called after LoadFromDB to have gems (relics) initialized void AddBonuses(uint32 bonusListID); @@ -426,7 +438,8 @@ class TC_GAME_API Item : public Object int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return _bonusData.ItemStatType[index]; } int32 GetItemStatValue(uint32 index, Player const* owner) const; SocketColor GetSocketColor(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_SOCKETS); return SocketColor(_bonusData.SocketColor[index]); } - uint32 GetAppearanceModId() const { return _bonusData.AppearanceModID; } + uint32 GetAppearanceModId() const { return GetUInt32Value(ITEM_FIELD_APPEARANCE_MOD_ID); } + void SetAppearanceModId(uint32 appearanceModId) { SetUInt32Value(ITEM_FIELD_APPEARANCE_MOD_ID, appearanceModId); } uint32 GetArmor(Player const* owner) const { return GetTemplate()->GetArmor(GetItemLevel(owner)); } void GetDamage(Player const* owner, float& minDamage, float& maxDamage) const { GetTemplate()->GetDamage(GetItemLevel(owner), minDamage, maxDamage); } uint32 GetDisplayId(Player const* owner) const; @@ -480,6 +493,16 @@ class TC_GAME_API Item : public Object ObjectGuid GetChildItem() const { return m_childItem; } void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; } + DynamicFieldStructuredView<ItemDynamicFieldArtifactPowers> GetArtifactPowers() const; + ItemDynamicFieldArtifactPowers const* GetArtifactPower(uint32 artifactPowerId) const; + void SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower, bool createIfMissing = false); + + void InitArtifactPowers(uint8 artifactId); + uint32 GetTotalPurchasedArtifactPowers() const; + void ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner); + void CopyArtifactDataFromParent(Item* parent); + + void GiveArtifactXp(int32 amount, Item* sourceItem, uint32 artifactCategoryId); protected: BonusData _bonusData; @@ -496,5 +519,6 @@ class TC_GAME_API Item : public Object uint32 m_paidExtendedCost; GuidSet allowedGUIDs; ObjectGuid m_childItem; + std::unordered_map<uint32, uint16> m_artifactPowerIdToIndex; }; #endif diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index a36a4a4c246..ac9000ded5e 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -190,6 +190,7 @@ TC_GAME_API uint32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uin return randPropPointsEntry->RarePropertiesPoints[propIndex]; case ITEM_QUALITY_EPIC: case ITEM_QUALITY_LEGENDARY: + case ITEM_QUALITY_ARTIFACT: return randPropPointsEntry->EpicPropertiesPoints[propIndex]; } diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index bbf89d18dbf..4d2ec62621c 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -757,6 +757,7 @@ struct TC_GAME_API ItemTemplate uint32 GetItemLimitCategory() const { return ExtendedData->ItemLimitCategory; } HolidayIds GetHolidayID() const { return HolidayIds(ExtendedData->HolidayID); } float GetStatScalingFactor() const { return ExtendedData->StatScalingFactor; } + uint8 GetArtifactID() const { return ExtendedData->ArtifactID; } uint32 GetBaseArmor() const { return GetArmor(ExtendedData->ItemLevel); } void GetBaseDamage(float& minDamage, float& maxDamage) const { GetDamage(ExtendedData->ItemLevel, minDamage, maxDamage); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e1d5c92b80e..849aab0af79 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4012,6 +4012,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_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); @@ -7212,6 +7224,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply) _ApplyItemBonuses(item, slot, apply); ApplyItemEquipSpell(item, apply); + ApplyArtifactPowers(item, apply); ApplyEnchantment(item, apply); TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed"); @@ -7683,6 +7696,80 @@ void Player::UpdateItemSetAuras(bool formChange /*= false*/) } } +void Player::ApplyArtifactPowers(Item* item, bool apply) +{ + for (ItemDynamicFieldArtifactPowers const& artifactPower : item->GetArtifactPowers()) + { + uint8 rank = artifactPower.CurrentRankWithBonus; + if (!rank) + continue; + + ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, rank - 1); + if (!artifactPowerRank) + continue; + + ApplyArtifactPowerRank(item, artifactPowerRank, apply); + } +} + +void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply) +{ + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(artifactPowerRank->SpellID); + if (!spellInfo) + return; + + if (spellInfo->IsPassive()) + { + AuraApplication* powerAura = GetAuraApplication(artifactPowerRank->SpellID, ObjectGuid::Empty, artifact->GetGUID()); + if (powerAura) + { + if (apply) + { + for (AuraEffect* auraEffect : powerAura->GetBase()->GetAuraEffects()) + { + if (!auraEffect) + continue; + + if (powerAura->HasEffect(auraEffect->GetEffIndex())) + auraEffect->ChangeAmount(artifactPowerRank->Value ? artifactPowerRank->Value : auraEffect->GetSpellEffectInfo()->CalcValue()); + } + } + else + RemoveAura(powerAura); + } + else if (apply) + { + CustomSpellValues csv; + if (artifactPowerRank->Value) + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (spellInfo->GetEffect(i)) + csv.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), artifactPowerRank->Value); + + CastCustomSpell(artifactPowerRank->SpellID, csv, this, TRIGGERED_FULL_MASK, artifact); + } + } + else + { + if (apply && !HasSpell(artifactPowerRank->SpellID)) + { + AddTemporarySpell(artifactPowerRank->SpellID); + WorldPackets::Spells::LearnedSpells learnedSpells; + learnedSpells.SuppressMessaging = true; + learnedSpells.SpellID.push_back(artifactPowerRank->SpellID); + SendDirectMessage(learnedSpells.Write()); + } + else if (!apply) + { + RemoveTemporarySpell(artifactPowerRank->SpellID); + WorldPackets::Spells::UnlearnedSpells unlearnedSpells; + unlearnedSpells.SuppressMessaging = true; + unlearnedSpells.SpellID.push_back(artifactPowerRank->SpellID); + SendDirectMessage(unlearnedSpells.Write()); + } + } + +} + void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx) { if (!target || !target->IsAlive() || target == this) @@ -7944,6 +8031,7 @@ void Player::_RemoveAllItemMods() ApplyItemEquipSpell(m_items[i], false); ApplyEnchantment(m_items[i], false); + ApplyArtifactPowers(m_items[i], false); } } @@ -8000,6 +8088,7 @@ void Player::_ApplyAllItemMods() continue; ApplyItemEquipSpell(m_items[i], true); + ApplyArtifactPowers(m_items[i], true); ApplyEnchantment(m_items[i], true); } } @@ -11387,6 +11476,10 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (HasSpell(proto->Effects[1]->SpellID)) return EQUIP_ERR_INTERNAL_BAG_ERROR; + if (ArtifactEntry const* artifact = sArtifactStore.LookupEntry(proto->GetArtifactID())) + if (artifact->SpecID != GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID)) + return EQUIP_ERR_CANT_USE_ITEM; + return EQUIP_ERR_OK; } @@ -11515,10 +11608,12 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat { childItem->SetGuidValue(ITEM_FIELD_CREATOR, item->GetGUID()); childItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD); + item->SetChildItem(childItem->GetGUID()); } } } } + return item; } @@ -17608,7 +17703,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // must be before inventory (some items required reputation check) m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION)); - _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), time_diff); + _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), time_diff); if (IsVoidStorageUnlocked()) _LoadVoidStorage(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE)); @@ -17969,7 +18064,7 @@ void Player::LoadCorpse(PreparedQueryResult result) RemoveAtLoginFlag(AT_LOGIN_RESURRECT); } -void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) +void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, 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, @@ -17979,13 +18074,40 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, // 24 25 26 27 28 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, - // 29 30 31 32 33 34 35 36 37 38 39 + // 29 30 31 32 33 34 35 36 37 40 41 // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot //NOTE: the "order by `bag`" is important because it makes sure //the bagMap is filled before items in the bags are loaded //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?) //expected to be equipped before offhand items (@todo fixme) + // 0 1 2 3 4 + // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ? + std::unordered_map<ObjectGuid, std::tuple<uint32, uint32, std::vector<ItemDynamicFieldArtifactPowers>>> artifactData; + if (artifactsResult) + { + do + { + Field* fields = artifactsResult->Fetch(); + auto& artifactDataEntry = artifactData[ObjectGuid::Create<HighGuid::Item>(fields[0].GetUInt64())]; + std::get<0>(artifactDataEntry) = fields[1].GetUInt32(); + std::get<1>(artifactDataEntry) = fields[2].GetUInt32(); + ItemDynamicFieldArtifactPowers artifactPowerData; + artifactPowerData.ArtifactPowerId = fields[3].GetUInt32(); + artifactPowerData.PurchasedRank = fields[4].GetUInt8(); + if (ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.LookupEntry(artifactPowerData.ArtifactPowerId)) + { + if (artifactPowerData.PurchasedRank > artifactPower->MaxRank) + artifactPowerData.PurchasedRank = artifactPower->MaxRank; + + artifactPowerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0; + + std::get<2>(artifactDataEntry).push_back(artifactPowerData); + } + + } while (artifactsResult->NextRow()); + } + if (result) { uint32 zoneId = GetZoneId(); @@ -18003,8 +18125,12 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Field* fields = result->Fetch(); if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields)) { - ObjectGuid bagGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[38].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[39].GetUInt8(); + auto artifactDataItr = artifactData.find(item->GetGUID()); + if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end()) + item->LoadArtifactData(std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second)); + + ObjectGuid bagGuid = fields[40].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[40].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[41].GetUInt8(); GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item); GetSession()->GetCollectionMgr()->AddItemAppearance(item); @@ -18079,7 +18205,6 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) } - // Item's state may have changed after storing if (err == EQUIP_ERR_OK) { @@ -18116,7 +18241,12 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) for (Item* childItem : childItems) { if (Item* parent = GetItemByGuid(childItem->GetGuidValue(ITEM_FIELD_CREATOR))) + { parent->SetChildItem(childItem->GetGUID()); + childItem->CopyArtifactDataFromParent(parent); + if (childItem->IsEquipped()) + SetVisibleItemSlot(childItem->GetSlot(), childItem); + } else childItem->SetState(ITEM_REMOVED, this); } @@ -18134,7 +18264,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) do { - // SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs FROM character_void_storage WHERE playerGuid = ? + // SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs FROM character_void_storage WHERE playerGuid = ? Field* fields = result->Fetch(); uint64 itemId = fields[0].GetUInt64(); @@ -18144,8 +18274,10 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) uint32 randomProperty = fields[4].GetUInt32(); uint32 suffixFactor = fields[5].GetUInt32(); uint32 upgradeId = fields[6].GetUInt32(); + uint32 fixedScalingLevel = fields[7].GetUInt32(); + uint32 artifactKnowledgeLevel = fields[8].GetUInt32(); std::vector<uint32> bonusListIDs; - Tokenizer bonusListIdTokens(fields[7].GetString(), ' '); + Tokenizer bonusListIdTokens(fields[9].GetString(), ' '); for (char const* token : bonusListIdTokens) bonusListIDs.push_back(atoul(token)); @@ -18170,7 +18302,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result) continue; } - _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs); + _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs); WorldPackets::Item::ItemInstance voidInstance; voidInstance.Initialize(_voidStorageItems[slot]); @@ -18346,7 +18478,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - ObjectGuid ownerGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[38].GetUInt64()) : ObjectGuid::Empty; + ObjectGuid ownerGuid = fields[40].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[40].GetUInt64()) : ObjectGuid::Empty; if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); @@ -19875,7 +20007,7 @@ void Player::_SaveVoidStorage(SQLTransaction& trans) } else { - // REPLACE INTO character_inventory (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + // REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM); stmt->setUInt64(0, _voidStorageItems[i]->ItemId); stmt->setUInt64(1, GetGUID().GetCounter()); @@ -19885,10 +20017,12 @@ void Player::_SaveVoidStorage(SQLTransaction& trans) stmt->setUInt32(5, _voidStorageItems[i]->ItemRandomPropertyId); stmt->setUInt32(6, _voidStorageItems[i]->ItemSuffixFactor); stmt->setUInt32(7, _voidStorageItems[i]->ItemUpgradeId); + stmt->setUInt32(8, _voidStorageItems[i]->FixedScalingLevel); + stmt->setUInt32(9, _voidStorageItems[i]->ArtifactKnowledgeLevel); std::ostringstream bonusListIDs; for (int32 bonusListID : _voidStorageItems[i]->BonusListIDs) bonusListIDs << bonusListID << ' '; - stmt->setString(8, bonusListIDs.str()); + stmt->setString(10, bonusListIDs.str()); } trans->Append(stmt); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f25e5cbb3dc..421a15729dc 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -956,6 +956,7 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, PLAYER_LOGIN_QUERY_LOAD_REPUTATION, PLAYER_LOGIN_QUERY_LOAD_INVENTORY, + PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS, PLAYER_LOGIN_QUERY_LOAD_ACTIONS, PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT, PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE, @@ -1123,15 +1124,17 @@ struct BGData struct VoidStorageItem { - VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(0), ItemSuffixFactor(0), ItemUpgradeId(0) { } - VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 randomPropertyId, uint32 suffixFactor, uint32 upgradeId, std::vector<uint32> const& bonuses) + VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(0), ItemSuffixFactor(0), ItemUpgradeId(0), FixedScalingLevel(0), ArtifactKnowledgeLevel(0) { } + VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 randomPropertyId, uint32 suffixFactor, + uint32 upgradeId, uint32 fixedScalingLevel, uint32 artifactKnowledgeLevel, std::vector<uint32> const& bonuses) : ItemId(id), ItemEntry(entry), CreatorGuid(creator), ItemRandomPropertyId(randomPropertyId), - ItemSuffixFactor(suffixFactor), ItemUpgradeId(upgradeId) + ItemSuffixFactor(suffixFactor), ItemUpgradeId(upgradeId), FixedScalingLevel(fixedScalingLevel), ArtifactKnowledgeLevel(artifactKnowledgeLevel) { BonusListIDs.insert(BonusListIDs.end(), bonuses.begin(), bonuses.end()); } VoidStorageItem(VoidStorageItem&& vsi) : ItemId(vsi.ItemId), ItemEntry(vsi.ItemEntry), CreatorGuid(vsi.CreatorGuid), ItemRandomPropertyId(vsi.ItemRandomPropertyId), - ItemSuffixFactor(vsi.ItemSuffixFactor), ItemUpgradeId(vsi.ItemUpgradeId), BonusListIDs(std::move(vsi.BonusListIDs)) { } + ItemSuffixFactor(vsi.ItemSuffixFactor), ItemUpgradeId(vsi.ItemUpgradeId), FixedScalingLevel(vsi.FixedScalingLevel), + ArtifactKnowledgeLevel(vsi.ArtifactKnowledgeLevel), BonusListIDs(std::move(vsi.BonusListIDs)) { } uint64 ItemId; uint32 ItemEntry; @@ -1139,6 +1142,8 @@ struct VoidStorageItem uint32 ItemRandomPropertyId; uint32 ItemSuffixFactor; uint32 ItemUpgradeId; + uint32 FixedScalingLevel; + uint32 ArtifactKnowledgeLevel; std::vector<int32> BonusListIDs; }; @@ -2152,6 +2157,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool formChange = false); void UpdateEquipSpellsAtFormChange(); void UpdateItemSetAuras(bool formChange = false); + void ApplyArtifactPowers(Item* item, bool apply); + void ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply); void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx); void CastItemUseSpell(Item* item, SpellCastTargets const& targets, ObjectGuid castCount, int32* misc); @@ -2518,7 +2525,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void _LoadActions(PreparedQueryResult result); void _LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effectResult, uint32 timediff); void _LoadBoundInstances(PreparedQueryResult result); - void _LoadInventory(PreparedQueryResult result, uint32 timeDiff); + void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, uint32 timeDiff); void _LoadVoidStorage(PreparedQueryResult result); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index c8cd3645721..d665225edc1 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14214,6 +14214,12 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const { if (GetTypeId() == TYPEID_PLAYER) { + if (Aura* artifactAura = GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE)) + if (Item* artifact = ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID())) + if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID))) + if (ShapeshiftForm(artifactAppearance->ModifiesShapeshiftFormDisplay) == form) + return artifactAppearance->ShapeshiftDisplayID; + switch (form) { case FORM_CAT_FORM: diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 246a8a09818..4847723fb9c 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -31,6 +31,7 @@ #include <boost/container/flat_set.hpp> #define WORLD_TRIGGER 12999 +#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE 197886 enum SpellInterruptFlags { @@ -773,7 +774,7 @@ enum NPCFlags : uint64 UNIT_NPC_FLAG_SPELLCLICK = 0x0001000000, // cause client to send 1015 opcode (spell click) UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x0002000000, // players with mounts that have vehicle data should have it set UNIT_NPC_FLAG_MAILBOX = 0x0004000000, // mailbox - UNIT_NPC_FLAG_REFORGER = 0x0008000000, // reforging + UNIT_NPC_FLAG_ARTIFACT_POWER_RESPEC = 0x0008000000, // artifact powers reset UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x0010000000, // transmogrification UNIT_NPC_FLAG_VAULTKEEPER = 0x0020000000, // void storage UNIT_NPC_FLAG_BLACK_MARKET = 0x0080000000, // black market |
