From 57b2c5b55009fb253f120910c55e77ade999afa8 Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Sun, 8 Jun 2025 15:09:36 -0400 Subject: [PATCH] Core/Items: Fixed item spell charge slot indexing Port From (https://github.com/TrinityCore/TrinityCore/commit/c85d12fc3f0576163d4ffa91bb38f66894305349) --- Source/Game/AuctionHouse/AuctionManager.cs | 2 +- Source/Game/Entities/Item/Item.cs | 52 +++++++++++++++++----- Source/Game/Globals/ObjectManager.cs | 11 ++--- Source/Game/Spells/Spell.cs | 24 +++------- Source/Game/Spells/SpellEffects.cs | 3 +- Source/Game/Spells/SpellManager.cs | 9 ---- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/Source/Game/AuctionHouse/AuctionManager.cs b/Source/Game/AuctionHouse/AuctionManager.cs index 4e1a7ac91..ca17bf167 100644 --- a/Source/Game/AuctionHouse/AuctionManager.cs +++ b/Source/Game/AuctionHouse/AuctionManager.cs @@ -1657,7 +1657,7 @@ namespace Game else { auctionItem.Item = new ItemInstance(Items[0]); - auctionItem.Charges = new[] { Items[0].GetSpellCharges(0), Items[0].GetSpellCharges(1), Items[0].GetSpellCharges(2), Items[0].GetSpellCharges(3), Items[0].GetSpellCharges(4) }.Max(); + auctionItem.Charges = Items[0].GetSpellCharges(); for (EnchantmentSlot enchantmentSlot = 0; enchantmentSlot < EnchantmentSlot.MaxInspected; enchantmentSlot++) { uint enchantId = Items[0].GetEnchantmentId(enchantmentSlot); diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 54d5f08fb..711199172 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -54,9 +54,9 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.MaxDurability), itemProto.MaxDurability); SetDurability(itemProto.MaxDurability); - for (int i = 0; i < itemProto.Effects.Count; ++i) - if (itemProto.Effects[i].LegacySlotIndex < 5) - SetSpellCharges(itemProto.Effects[i].LegacySlotIndex, itemProto.Effects[i].Charges); + foreach (var effect in GetEffects()) + if (effect != null) + SetSpellCharges(effect, effect.Charges); SetExpiration(itemProto.GetDuration()); SetCreatePlayedTime(0); @@ -126,6 +126,42 @@ namespace Game.Entities SetState(ItemUpdateState.Changed, owner); // save new time in database } + int FindSpellChargesSlot(BonusData bonusData, ItemEffectRecord effect) + { + int MaxSpellChargesSlot = m_itemData.SpellCharges.GetSize(); + + if (effect == null) + { + // return fist effect that has charges + for (int i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i) + if (bonusData.Effects[i] != null && bonusData.Effects[i].Charges != 0) + return i; + + return MaxSpellChargesSlot; + } + + for (int i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i) + if (bonusData.Effects[i] == effect) + return i; + + return MaxSpellChargesSlot; + } + + public int GetSpellCharges(ItemEffectRecord effect = null) + { + int slot = FindSpellChargesSlot(_bonusData, effect); + if (slot < m_itemData.SpellCharges.GetSize()) + return m_itemData.SpellCharges[slot]; + + return 0; + } + public void SetSpellCharges(ItemEffectRecord effect, int value) + { + int slot = FindSpellChargesSlot(_bonusData, effect); + if (slot < m_itemData.SpellCharges.GetSize()) + SetUpdateFieldValue(ref m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.SpellCharges, slot), value); + } + public virtual void SaveToDB(SQLTransaction trans) { PreparedStatement stmt; @@ -145,7 +181,7 @@ namespace Game.Entities StringBuilder ss = new(); for (byte i = 0; i < m_itemData.SpellCharges.GetSize() && i < _bonusData.EffectCount; ++i) - ss.AppendFormat("{0} ", GetSpellCharges(i)); + ss.AppendFormat("{0} ", m_itemData.SpellCharges[i]); stmt.AddValue(++index, ss.ToString()); stmt.AddValue(++index, (uint)m_itemData.DynamicFlags); @@ -466,10 +502,7 @@ namespace Game.Entities // load charges after bonuses, they can add more item effects var tokens = new StringArray(fields.Read(6), ' '); for (byte i = 0; i < m_itemData.SpellCharges.GetSize() && i < _bonusData.EffectCount && i < tokens.Length; ++i) - { - if (int.TryParse(tokens[i], out int value)) - SetSpellCharges(i, value); - } + SetUpdateFieldValue(ref m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.SpellCharges, i), int.TryParse(tokens[i], out int value) ? value : 0); SetModifier(ItemModifier.TransmogAppearanceAllSpecs, fields.Read(20)); SetModifier(ItemModifier.TransmogAppearanceSpec1, fields.Read(21)); @@ -2621,9 +2654,6 @@ namespace Game.Entities public string GetText() { return m_text; } public void SetText(string text) { m_text = text; } - public int GetSpellCharges(int index = 0) { return m_itemData.SpellCharges[index]; } - public void SetSpellCharges(int index, int value) { SetUpdateFieldValue(ref m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.SpellCharges, index), value); } - public ItemUpdateState GetState() { return uState; } public bool IsInUpdateQueue() { return uQueuePos != -1; } diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 20b488721..71697d7f4 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -5019,6 +5019,9 @@ namespace Game } } + foreach (var item in ItemTemplateStorage.Values) + item.Effects.Sort((x, y) => x.LegacySlotIndex.CompareTo(y.LegacySlotIndex)); + Log.outInfo(LogFilter.ServerLoading, "Loaded {0} item templates in {1} ms", sparseCount, Time.GetMSTimeDiffToNow(oldMSTime)); } @@ -9918,8 +9921,7 @@ namespace Game data.time = TimeSpan.FromMilliseconds(result.Read(9)); - Tuple key = Tuple.Create(summonerId, summonerType, group); - _tempSummonDataStorage.Add(key, data); + _tempSummonDataStorage.Add((summonerId, summonerType, group), data); ++count; @@ -11319,8 +11321,7 @@ namespace Game public List GetSummonGroup(uint summonerId, SummonerType summonerType, byte group) { - Tuple key = Tuple.Create(summonerId, summonerType, group); - return _tempSummonDataStorage.LookupByKey(key); + return _tempSummonDataStorage.LookupByKey((summonerId, summonerType, group)); } public bool IsReservedName(string name) @@ -11568,7 +11569,7 @@ namespace Game Dictionary _repOnKillStorage = new(); Dictionary _repSpilloverTemplateStorage = new(); MultiMap _mailLevelRewardStorage = new(); - MultiMap, TempSummonData> _tempSummonDataStorage = new(); + MultiMap<(uint, SummonerType, byte), TempSummonData> _tempSummonDataStorage = new(); Dictionary _playerChoices = new(); Dictionary _pageTextStorage = new(); List _reservedNamesStorage = new(); diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 0177409de..e82254754 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -4674,16 +4674,13 @@ namespace Game.Spells foreach (ItemEffectRecord itemEffect in m_CastItem.GetEffects()) { - if (itemEffect.LegacySlotIndex >= m_CastItem.m_itemData.SpellCharges.GetSize()) - continue; - // item has limited charges if (itemEffect.Charges != 0) { if (itemEffect.Charges < 0) expendable = true; - int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex); + int charges = m_CastItem.GetSpellCharges(itemEffect); // item has charges left for this slot if (charges != 0 && itemEffect.SpellID == m_spellInfo.Id) @@ -4694,7 +4691,7 @@ namespace Game.Spells ++charges; if (proto.GetMaxStackSize() == 1) - m_CastItem.SetSpellCharges(itemEffect.LegacySlotIndex, charges); + m_CastItem.SetSpellCharges(itemEffect, charges); m_CastItem.SetState(ItemUpdateState.Changed, m_caster.ToPlayer()); } @@ -4905,11 +4902,8 @@ namespace Game.Spells { foreach (ItemEffectRecord itemEffect in m_CastItem.GetEffects()) { - if (itemEffect.LegacySlotIndex >= m_CastItem.m_itemData.SpellCharges.GetSize()) - continue; - // CastItem will be used up and does not count as reagent - int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex); + int charges = m_CastItem.GetSpellCharges(itemEffect); if (itemEffect.Charges < 0 && Math.Abs(charges) < 2) { ++itemcount; @@ -6714,9 +6708,8 @@ namespace Game.Spells return SpellCastResult.ItemNotReady; foreach (ItemEffectRecord itemEffect in m_CastItem.GetEffects()) - if (itemEffect.LegacySlotIndex < m_CastItem.m_itemData.SpellCharges.GetSize() && itemEffect.Charges != 0) - if (m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex) == 0) - return SpellCastResult.NoChargesRemain; + if (itemEffect.Charges != 0 && m_CastItem.GetSpellCharges(itemEffect) == 0) + return SpellCastResult.NoChargesRemain; // consumable cast item checks if (proto.GetClass() == ItemClass.Consumable && m_targets.GetUnitTarget() != null) @@ -6821,11 +6814,8 @@ namespace Game.Spells foreach (ItemEffectRecord itemEffect in m_CastItem.GetEffects()) { - if (itemEffect.LegacySlotIndex >= m_CastItem.m_itemData.SpellCharges.GetSize()) - continue; - // CastItem will be used up and does not count as reagent - int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex); + int charges = m_CastItem.GetSpellCharges(itemEffect); if (itemEffect.Charges < 0 && Math.Abs(charges) < 2) { ++itemcount; @@ -7173,7 +7163,7 @@ namespace Game.Spells if (item != null) { foreach (ItemEffectRecord itemEffect in item.GetEffects()) - if (itemEffect.LegacySlotIndex <= item.m_itemData.SpellCharges.GetSize() && itemEffect.Charges != 0 && item.GetSpellCharges(itemEffect.LegacySlotIndex) == itemEffect.Charges) + if (itemEffect.Charges != 0 && item.GetSpellCharges(itemEffect) == itemEffect.Charges) return SpellCastResult.ItemAtMaxCharges; } break; diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 894e6f9b2..0c71410de 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -4900,8 +4900,7 @@ namespace Game.Spells if (item != null) { foreach (ItemEffectRecord itemEffect in item.GetEffects()) - if (itemEffect.LegacySlotIndex <= item.m_itemData.SpellCharges.GetSize()) - item.SetSpellCharges(itemEffect.LegacySlotIndex, itemEffect.Charges); + item.SetSpellCharges(itemEffect, itemEffect.Charges); item.SetState(ItemUpdateState.Changed, player); } diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index 5e222f248..73d8d11a0 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -4384,15 +4384,6 @@ namespace Game.Entities }); }); - // Summon Living Air - ApplySpellFix([102207], spellInfo => - { - ApplySpellEffectFix(spellInfo, 0, spellEffectInfo => - { - spellEffectInfo.TargetA = new SpellImplicitTargetInfo(Targets.DestTargetRandom); - }); - }); - // END OF THE WANDERING ISLE SPELLS //