diff options
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 48 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 8 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 45 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.h | 3 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
7 files changed, 101 insertions, 23 deletions
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index febce29419d..f426e81ded6 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -2326,15 +2326,40 @@ float Item::GetItemStatValue(uint32 index, Player const* owner) const return 0.0f; } -ItemDisenchantLootEntry const* Item::GetDisenchantLoot(Player const* owner) const +Optional<uint32> Item::GetDisenchantLootId() const { if (!_bonusData.CanDisenchant) - return nullptr; + return {}; + + if (_bonusData.DisenchantLootId) + return _bonusData.DisenchantLootId; + + // ignore temporary item level scaling (pvp or timewalking) + uint32 itemLevel = GetItemLevel(GetTemplate(), _bonusData, _bonusData.RequiredLevel, GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL), 0, 0, 0, false, 0); + + ItemDisenchantLootEntry const* disenchantLoot = GetBaseDisenchantLoot(GetTemplate(), GetQuality(), itemLevel); + if (!disenchantLoot) + return {}; + + return disenchantLoot->ID; +} + +Optional<uint16> Item::GetDisenchantSkillRequired() const +{ + if (!_bonusData.CanDisenchant) + return {}; + + // ignore temporary item level scaling (pvp or timewalking) + uint32 itemLevel = GetItemLevel(GetTemplate(), _bonusData, _bonusData.RequiredLevel, GetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL), 0, 0, 0, false, 0); - return Item::GetDisenchantLoot(GetTemplate(), GetQuality(), GetItemLevel(owner)); + ItemDisenchantLootEntry const* disenchantLoot = GetBaseDisenchantLoot(GetTemplate(), GetQuality(), itemLevel); + if (!disenchantLoot) + return {}; + + return disenchantLoot->SkillRequired; } -ItemDisenchantLootEntry const* Item::GetDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel) +ItemDisenchantLootEntry const* Item::GetBaseDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel) { if (itemTemplate->HasFlag(ITEM_FLAG_CONJURED) || itemTemplate->HasFlag(ITEM_FLAG_NO_DISENCHANT) || itemTemplate->GetBonding() == BIND_QUEST) return nullptr; @@ -2802,13 +2827,11 @@ void BonusData::Initialize(ItemTemplate const* proto) ItemLevelBonus = 0; RequiredLevel = proto->GetBaseRequiredLevel(); for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) + { ItemStatType[i] = proto->GetStatModifierBonusStat(i); - - for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) StatPercentEditor[i] = proto->GetStatPercentEditor(i); - - for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i) ItemStatSocketCostMultiplier[i] = proto->GetStatPercentageOfSocket(i); + } for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i) { @@ -2824,6 +2847,7 @@ void BonusData::Initialize(ItemTemplate const* proto) RepairCostMultiplier = 1.0f; ContentTuningId = proto->GetScalingStatContentTuning(); PlayerLevelToItemLevelCurveId = proto->GetPlayerLevelToItemLevelCurveId(); + DisenchantLootId = 0; RelicType = -1; HasFixedLevel = false; RequiredLevelOverride = 0; @@ -2846,6 +2870,7 @@ void BonusData::Initialize(ItemTemplate const* proto) _state.SuffixPriority = std::numeric_limits<int32>::max(); _state.AppearanceModPriority = std::numeric_limits<int32>::max(); + _state.DisenchantLootPriority = std::numeric_limits<int32>::max(); _state.ScalingStatDistributionPriority = std::numeric_limits<int32>::max(); _state.AzeriteTierUnlockSetPriority = std::numeric_limits<int32>::max(); _state.RequiredLevelCurvePriority = std::numeric_limits<int32>::max(); @@ -2944,6 +2969,13 @@ void BonusData::AddBonus(uint32 type, std::array<int32, 4> const& values) HasFixedLevel = type == ITEM_BONUS_SCALING_STAT_DISTRIBUTION_FIXED; } break; + case ITEM_BONUS_DISENCHANT_LOOT_ID: + if (values[1] < _state.DisenchantLootPriority) + { + DisenchantLootId = values[0]; + _state.DisenchantLootPriority = values[1]; + } + break; case ITEM_BONUS_BONDING: Bonding = ItemBondingType(values[0]); break; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 5ffb18941b9..f0e3b3216a5 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -104,6 +104,7 @@ private: { int32 SuffixPriority; int32 AppearanceModPriority; + int32 DisenchantLootPriority; int32 ScalingStatDistributionPriority; int32 AzeriteTierUnlockSetPriority; int32 RequiredLevelCurvePriority; @@ -349,10 +350,11 @@ class TC_GAME_API Item : public Object ItemModifiedAppearanceEntry const* GetItemModifiedAppearance() const; float GetRepairCostMultiplier() const { return _bonusData.RepairCostMultiplier; } uint32 GetScalingContentTuningId() const { return _bonusData.ContentTuningId; } - ItemDisenchantLootEntry const* GetDisenchantLoot(Player const* owner) const; - static ItemDisenchantLootEntry const* GetDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel); + Optional<uint32> GetDisenchantLootId() const; + Optional<uint16> GetDisenchantSkillRequired() const; + static ItemDisenchantLootEntry const* GetBaseDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel); void SetFixedLevel(uint8 level); - Trinity::IteratorPair<ItemEffectEntry const* const*> GetEffects() const { return { std::make_pair(&_bonusData.Effects[0], &_bonusData.Effects[0] + _bonusData.EffectCount) }; } + Trinity::IteratorPair<ItemEffectEntry const* const*> GetEffects() const { return { std::make_pair(_bonusData.Effects.data(), _bonusData.Effects.data() + _bonusData.EffectCount) }; } // Item Refund system void SetNotRefundable(Player* owner, bool changestate = true, CharacterDatabaseTransaction* trans = nullptr, bool addToCollection = true); diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index 6314e9d9f01..663acfb3b9c 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -482,7 +482,7 @@ bool LootRoll::TryToStart(Map* map, Loot& loot, uint32 lootListId, uint16 enchan m_voteMask = ROLL_ALL_TYPE_MASK; if (itemTemplate->HasFlag(ITEM_FLAG2_CAN_ONLY_ROLL_GREED)) m_voteMask = RollMask(m_voteMask & ~ROLL_FLAG_TYPE_NEED); - if (ItemDisenchantLootEntry const* disenchant = GetItemDisenchantLoot(); !disenchant || disenchant->SkillRequired > enchantingSkill) + if (Optional<uint16> disenchantSkillRequired = GetItemDisenchantSkillRequired(); !disenchantSkillRequired || disenchantSkillRequired > enchantingSkill) m_voteMask = RollMask(m_voteMask & ~ROLL_FLAG_TYPE_DISENCHANT); if (playerCount > 1) // check if more than one player can loot this item @@ -606,7 +606,7 @@ bool LootRoll::AllPlayerVoted(RollVoteMap::const_iterator& winnerItr) return notVoted == 0; } -ItemDisenchantLootEntry const* LootRoll::GetItemDisenchantLoot() const +Optional<uint32> LootRoll::GetItemDisenchantLootId() const { WorldPackets::Item::ItemInstance itemInstance; itemInstance.Initialize(*m_lootItem); @@ -614,11 +614,43 @@ ItemDisenchantLootEntry const* LootRoll::GetItemDisenchantLoot() const BonusData bonusData; bonusData.Initialize(itemInstance); if (!bonusData.CanDisenchant) - return nullptr; + return {}; + + if (bonusData.DisenchantLootId) + return bonusData.DisenchantLootId; ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(m_lootItem->itemid); - uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, 1, 0, 0, 0, 0, false, 0); - return Item::GetDisenchantLoot(itemTemplate, bonusData.Quality, itemLevel); + + // ignore temporary item level scaling (pvp or timewalking) + uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, bonusData.RequiredLevel, 0, 0, 0, 0, false, 0); + + ItemDisenchantLootEntry const* disenchantLoot = Item::GetBaseDisenchantLoot(itemTemplate, bonusData.Quality, itemLevel); + if (!disenchantLoot) + return {}; + + return disenchantLoot->ID; +} + +Optional<uint16> LootRoll::GetItemDisenchantSkillRequired() const +{ + WorldPackets::Item::ItemInstance itemInstance; + itemInstance.Initialize(*m_lootItem); + + BonusData bonusData; + bonusData.Initialize(itemInstance); + if (!bonusData.CanDisenchant) + return {}; + + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(m_lootItem->itemid); + + // ignore temporary item level scaling (pvp or timewalking) + uint32 itemLevel = Item::GetItemLevel(itemTemplate, bonusData, bonusData.RequiredLevel, 0, 0, 0, 0, false, 0); + + ItemDisenchantLootEntry const* disenchantLoot = Item::GetBaseDisenchantLoot(itemTemplate, bonusData.Quality, itemLevel); + if (!disenchantLoot) + return {}; + + return disenchantLoot->SkillRequired; } // terminate the roll @@ -646,9 +678,8 @@ void LootRoll::Finish(RollVoteMap::const_iterator winnerItr) if (winnerItr->second.Vote == RollVote::Disenchant) { - ItemDisenchantLootEntry const* disenchant = ASSERT_NOTNULL(GetItemDisenchantLoot()); Loot loot(m_map, m_loot->GetOwnerGUID(), LOOT_DISENCHANTING, nullptr); - loot.FillLoot(disenchant->ID, LootTemplates_Disenchant, player, true, false, LOOT_MODE_DEFAULT, ItemContext::NONE); + loot.FillLoot(*GetItemDisenchantLootId(), LootTemplates_Disenchant, player, true, false, LOOT_MODE_DEFAULT, ItemContext::NONE); if (!loot.AutoStore(player, NULL_BAG, NULL_SLOT, true)) { for (uint32 i = 0; i < loot.items.size(); ++i) diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h index 3b5cbca7fb5..f29975ebeee 100644 --- a/src/server/game/Loot/Loot.h +++ b/src/server/game/Loot/Loot.h @@ -270,7 +270,8 @@ private: void FillPacket(WorldPackets::Loot::LootItemData& lootItem) const; void Finish(RollVoteMap::const_iterator winnerItr); bool AllPlayerVoted(RollVoteMap::const_iterator& winnerItr); - ItemDisenchantLootEntry const* GetItemDisenchantLoot() const; + Optional<uint32> GetItemDisenchantLootId() const; + Optional<uint16> GetItemDisenchantSkillRequired() const; Map* m_map; RollVoteMap m_rollVoteMap; bool m_isStarted; diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 2104cc0c5ab..dc17eeaa479 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1078,6 +1078,18 @@ void LoadLootTemplates_Disenchant() lootIdSetUsed.insert(lootid); } + for (ItemBonusEntry const* itemBonus : sItemBonusStore) + { + if (itemBonus->Type != ITEM_BONUS_DISENCHANT_LOOT_ID) + continue; + + uint32 lootid = itemBonus->Value[0]; + if (!lootIdSet.contains(lootid)) + LootTemplates_Disenchant.ReportNonExistingId(lootid); + else + lootIdSetUsed.insert(lootid); + } + for (uint32 lootId : lootIdSetUsed) lootIdSet.erase(lootId); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index faeafe103b2..9ce04c387e4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7882,10 +7882,10 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= if (!itemProto) return SPELL_FAILED_CANT_BE_SALVAGED; - ItemDisenchantLootEntry const* itemDisenchantLoot = item->GetDisenchantLoot(m_caster->ToPlayer()); - if (!itemDisenchantLoot) + Optional<uint16> disenchantSkillRequired = item->GetDisenchantSkillRequired(); + if (!disenchantSkillRequired) return SPELL_FAILED_CANT_BE_SALVAGED; - if (itemDisenchantLoot->SkillRequired > player->GetSkillValue(SKILL_ENCHANTING)) + if (disenchantSkillRequired > player->GetSkillValue(SKILL_ENCHANTING)) return SPELL_FAILED_CANT_BE_SALVAGED_SKILL; break; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c74646f42c0..61c5afa05bc 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3433,7 +3433,7 @@ void Spell::EffectDisEnchant() caster->UpdateCraftSkill(m_spellInfo); itemTarget->m_loot.reset(new Loot(caster->GetMap(), itemTarget->GetGUID(), LOOT_DISENCHANTING, nullptr)); - itemTarget->m_loot->FillLoot(ASSERT_NOTNULL(itemTarget->GetDisenchantLoot(caster))->ID, LootTemplates_Disenchant, caster, true); + itemTarget->m_loot->FillLoot(*itemTarget->GetDisenchantLootId(), LootTemplates_Disenchant, caster, true); caster->SendLoot(*itemTarget->m_loot); } |