aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2025-01-26 12:58:06 +0100
committerOvahlord <dreadkiller@gmx.de>2025-01-26 12:59:30 +0100
commit3eb4ccc9a0b3d315d53c566455a748c7cf795ac2 (patch)
tree1c2fd22fde7bf967a35cebe6cb6ff78672a1856d /src
parentb61960c1a952b929c95a80b1269800ef30878e3d (diff)
Core/Items: Fixed item spell charge slot indexing
Closes #30585 (cherry picked from commit c85d12fc3f0576163d4ffa91bb38f66894305349) # Conflicts: # src/server/game/Entities/Item/Item.h # src/server/game/Globals/ObjectMgr.cpp
Diffstat (limited to 'src')
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp2
-rw-r--r--src/server/game/Entities/Item/Item.cpp46
-rw-r--r--src/server/game/Entities/Item/Item.h7
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp7
-rw-r--r--src/server/game/Spells/Spell.cpp32
-rw-r--r--src/server/game/Spells/SpellEffects.cpp3
6 files changed, 64 insertions, 33 deletions
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index e67b53d4c02..616d71c2877 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -167,7 +167,7 @@ void AuctionPosting::BuildAuctionItem(WorldPackets::AuctionHouse::AuctionItem* a
{
auctionItem->Item.emplace();
auctionItem->Item->Initialize(Items[0]);
- auctionItem->Charges = std::max({ Items[0]->GetSpellCharges(0), Items[0]->GetSpellCharges(1), Items[0]->GetSpellCharges(2), Items[0]->GetSpellCharges(3), Items[0]->GetSpellCharges(4) });
+ auctionItem->Charges = Items[0]->GetSpellCharges();
for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++)
{
uint32 enchantId = Items[0]->GetEnchantmentId(EnchantmentSlot(i));
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index cbb85531c34..79d5af6e708 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -342,9 +342,8 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext contex
SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::MaxDurability), itemProto->MaxDurability);
SetDurability(itemProto->MaxDurability);
- for (std::size_t i = 0; i < itemProto->Effects.size(); ++i)
- if (itemProto->Effects[i]->LegacySlotIndex < 5)
- SetSpellCharges(itemProto->Effects[i]->LegacySlotIndex, itemProto->Effects[i]->Charges);
+ for (ItemEffectEntry const* effect : GetEffects())
+ SetSpellCharges(effect, effect->Charges);
SetExpiration(itemProto->GetDuration());
SetCreatePlayedTime(0);
@@ -391,6 +390,43 @@ void Item::UpdateDuration(Player* owner, uint32 diff)
SetState(ITEM_CHANGED, owner); // save new time in database
}
+static uint32 FindSpellChargesSlot(BonusData const& bonusData, ItemEffectEntry const* effect)
+{
+ static constexpr uint32 MaxSpellChargesSlot = UF::size<decltype(UF::ItemData::SpellCharges)>();
+
+ if (!effect)
+ {
+ // return fist effect that has charges
+ for (uint32 i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i)
+ if (bonusData.Effects[i] && bonusData.Effects[i]->Charges != 0)
+ return i;
+
+ return MaxSpellChargesSlot;
+ }
+
+ for (uint32 i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i)
+ if (bonusData.Effects[i] == effect)
+ return i;
+
+ return MaxSpellChargesSlot;
+}
+
+int32 Item::GetSpellCharges(ItemEffectEntry const* effect /*= nullptr*/) const
+{
+ uint32 slot = FindSpellChargesSlot(_bonusData, effect);
+ if (slot < m_itemData->SpellCharges.size())
+ return m_itemData->SpellCharges[slot];
+
+ return 0;
+}
+
+void Item::SetSpellCharges(ItemEffectEntry const* effect, int32 value)
+{
+ uint32 slot = FindSpellChargesSlot(_bonusData, effect);
+ if (slot < m_itemData->SpellCharges.size())
+ SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::SpellCharges, slot), value);
+}
+
void Item::SaveToDB(CharacterDatabaseTransaction trans)
{
bool isInTransaction = bool(trans);
@@ -413,7 +449,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans)
std::ostringstream ssSpells;
for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount; ++i)
- ssSpells << GetSpellCharges(i) << ' ';
+ ssSpells << m_itemData->SpellCharges[i] << ' ';
stmt->setString(++index, ssSpells.str());
stmt->setUInt32(++index, m_itemData->DynamicFlags);
@@ -726,7 +762,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
// load charges after bonuses, they can add more item effects
std::vector<std::string_view> tokens = Trinity::Tokenize(fields[6].GetStringView(), ' ', false);
for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount && i < tokens.size(); ++i)
- SetSpellCharges(i, Trinity::StringTo<int32>(tokens[i]).value_or(0));
+ SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::SpellCharges, i), Trinity::StringTo<int32>(tokens[i]).value_or(0));
SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS, fields[20].GetUInt32());
SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[21].GetUInt32());
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 29505d684d5..1634a7441d6 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -24,7 +24,6 @@
#include "ItemDefines.h"
#include "ItemEnchantmentMgr.h"
#include "ItemTemplate.h"
-#include "IteratorPair.h"
class SpellInfo;
class Bag;
@@ -259,8 +258,8 @@ class TC_GAME_API Item : public Object
void SetCreateTime(int64 createTime) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::CreateTime), createTime); }
// spell charges (signed but stored as unsigned)
- int32 GetSpellCharges(uint8 index/*0..5*/ = 0) const { return m_itemData->SpellCharges[index]; }
- void SetSpellCharges(uint8 index/*0..5*/, int32 value) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::SpellCharges, index), value); }
+ int32 GetSpellCharges(ItemEffectEntry const* effect = nullptr) const;
+ void SetSpellCharges(ItemEffectEntry const* effect, int32 value);
std::unique_ptr<Loot> m_loot;
bool m_lootGenerated;
@@ -300,7 +299,7 @@ class TC_GAME_API Item : public Object
static ItemDisenchantLootEntry const* GetDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel);
void SetFixedLevel(uint8 level);
void SetReforgeId(uint32 itemReforceRecId);
- Trinity::IteratorPair<ItemEffectEntry const* const*> GetEffects() const { return { std::make_pair(&_bonusData.Effects[0], &_bonusData.Effects[0] + _bonusData.EffectCount) }; }
+ std::span<ItemEffectEntry const* const> GetEffects() const { return { _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/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 6de875906ee..05cf9899c35 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3109,8 +3109,13 @@ void ObjectMgr::LoadItemTemplates()
// Load item effects (spells)
if (std::vector<ItemEffectEntry const*> const* itemEffects = sDB2Manager.GetItemEffectsForItemId(sparse->ID))
+ {
for (ItemEffectEntry const* itemEffect : *itemEffects)
- itemTemplate.Effects.push_back(itemEffect);
+ {
+ auto itr = std::ranges::lower_bound(itemTemplate.Effects, itemEffect->LegacySlotIndex, {}, &ItemEffectEntry::LegacySlotIndex);
+ itemTemplate.Effects.insert(itr, itemEffect);
+ }
+ }
}
TC_LOG_INFO("server.loading", ">> Loaded {} item templates in {} ms", _itemTemplateStore.size(), GetMSTimeDiffToNow(oldMSTime));
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index ed72a1d3366..c830fedee22 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5346,23 +5346,24 @@ void Spell::TakeCastItem()
for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
- if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
- continue;
-
// item has limited charges
if (itemEffect->Charges)
{
if (itemEffect->Charges < 0)
expendable = true;
- int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect);
// item has charges left for this slot
if (charges && itemEffect->SpellID == int32(m_spellInfo->Id))
{
- (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
+ if (charges > 0)
+ --charges;
+ else
+ ++charges;
+
if (proto->GetMaxStackSize() == 1)
- m_CastItem->SetSpellCharges(itemEffect->LegacySlotIndex, charges);
+ m_CastItem->SetSpellCharges(itemEffect, charges);
m_CastItem->SetState(ITEM_CHANGED, player);
}
@@ -5607,11 +5608,8 @@ void Spell::TakeReagents()
{
for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
- if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
- continue;
-
// CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect);
if (itemEffect->Charges < 0 && abs(charges) < 2)
{
++itemcount;
@@ -7310,9 +7308,8 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*=
return SPELL_FAILED_ITEM_NOT_READY;
for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
- if (itemEffect->LegacySlotIndex < m_CastItem->m_itemData->SpellCharges.size() && itemEffect->Charges)
- if (m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex) == 0)
- return SPELL_FAILED_NO_CHARGES_REMAIN;
+ if (itemEffect->Charges && m_CastItem->GetSpellCharges(itemEffect) == 0)
+ return SPELL_FAILED_NO_CHARGES_REMAIN;
// consumable cast item checks
if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && m_targets.GetUnitTarget())
@@ -7414,11 +7411,8 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*=
for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
- if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
- continue;
-
// CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect);
if (itemEffect->Charges < 0 && abs(charges) < 2)
{
++itemcount;
@@ -7757,9 +7751,7 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*=
if (Item* item = player->GetItemByEntry(itemId))
for (ItemEffectEntry const* itemEffect : item->GetEffects())
- if (itemEffect->LegacySlotIndex <= item->m_itemData->SpellCharges.size()
- && itemEffect->Charges != 0
- && item->GetSpellCharges(itemEffect->LegacySlotIndex) == itemEffect->Charges)
+ if (itemEffect->Charges != 0 && item->GetSpellCharges(itemEffect) == itemEffect->Charges)
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
break;
}
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 0d838ce2ee4..17638a92c08 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5128,8 +5128,7 @@ void Spell::EffectRechargeItem()
if (Item* item = player->GetItemByEntry(effectInfo->ItemType))
{
for (ItemEffectEntry const* itemEffect : item->GetEffects())
- if (itemEffect->LegacySlotIndex <= item->m_itemData->SpellCharges.size())
- item->SetSpellCharges(itemEffect->LegacySlotIndex, itemEffect->Charges);
+ item->SetSpellCharges(itemEffect, itemEffect->Charges);
item->SetState(ITEM_CHANGED, player);
}