diff options
author | Shauren <shauren.trinity@gmail.com> | 2025-01-26 12:58:06 +0100 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2025-01-26 12:59:30 +0100 |
commit | 3eb4ccc9a0b3d315d53c566455a748c7cf795ac2 (patch) | |
tree | 1c2fd22fde7bf967a35cebe6cb6ff78672a1856d | |
parent | b61960c1a952b929c95a80b1269800ef30878e3d (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
-rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 46 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 7 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 32 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 3 |
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); } |