aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-09-24 14:40:23 +0200
committerShauren <shauren.trinity@gmail.com>2024-09-24 14:40:23 +0200
commit3238175a62750ea5127feb69ce86d0c3c05dfc52 (patch)
tree0236bf8ffdd36edbf836cc7596bb64f49eda7b1b
parentd3985a046020e21c8aef5b0a930c517e686bf701 (diff)
Core/Items: Implemented ITEM_BONUS_DISENCHANT_LOOT_ID
-rw-r--r--src/server/game/Entities/Item/Item.cpp48
-rw-r--r--src/server/game/Entities/Item/Item.h8
-rw-r--r--src/server/game/Loot/Loot.cpp45
-rw-r--r--src/server/game/Loot/Loot.h3
-rw-r--r--src/server/game/Loot/LootMgr.cpp12
-rw-r--r--src/server/game/Spells/Spell.cpp6
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
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);
}