Core/Items: Implemented new bonus type (extra ItemEffect)

Port From (https://github.com/TrinityCore/TrinityCore/commit/63fba4751142d7a16d6316e9fb5ad844da088509)
This commit is contained in:
hondacrx
2020-06-10 13:25:01 -04:00
parent 3cea73ffb1
commit d09ddf2032
8 changed files with 113 additions and 125 deletions
+3 -1
View File
@@ -347,8 +347,10 @@ namespace Framework.Constants
RelicType = 17,
OverrideRequiredLevel = 18,
AzeriteTierUnlockSet = 19,
ScrappingLootId = 20,
OverrideCanDisenchant = 21,
OverrideCanScrap = 22
OverrideCanScrap = 22,
ItemEffectId = 23,
}
public enum ItemContext : byte
+36 -27
View File
@@ -70,10 +70,8 @@ namespace Game.Entities
SetDurability(itemProto.MaxDurability);
for (int i = 0; i < itemProto.Effects.Count; ++i)
{
if (i < 5)
SetSpellCharges(i, itemProto.Effects[i].Charges);
}
if (itemProto.Effects[i].LegacySlotIndex < 5)
SetSpellCharges(itemProto.Effects[i].LegacySlotIndex, itemProto.Effects[i].Charges);
SetExpiration(itemProto.GetDuration());
SetCreatePlayedTime(0);
@@ -162,7 +160,7 @@ namespace Game.Entities
stmt.AddValue(++index, (uint)m_itemData.Expiration);
StringBuilder ss = new StringBuilder();
for (byte i = 0; i < ItemConst.MaxSpells; ++i)
for (byte i = 0; i < m_itemData.SpellCharges.GetSize() && i < _bonusData.EffectCount; ++i)
ss.AppendFormat("{0} ", GetSpellCharges(i));
stmt.AddValue(++index, ss.ToString());
@@ -423,16 +421,6 @@ namespace Game.Entities
need_save = true;
}
var tokens = new StringArray(fields.Read<string>(6), ' ');
if (tokens.Length == ItemConst.MaxProtoSpells)
{
for (byte i = 0; i < ItemConst.MaxProtoSpells; ++i)
{
if (int.TryParse(tokens[i], out int value))
SetSpellCharges(i, value);
}
}
SetItemFlags((ItemFieldFlags)itemFlags);
uint durability = fields.Read<uint>(10);
@@ -466,6 +454,14 @@ namespace Game.Entities
}
SetBonuses(bonusListIDs);
// load charges after bonuses, they can add more item effects
var tokens = new StringArray(fields.Read<string>(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);
}
SetModifier(ItemModifier.TransmogAppearanceAllSpecs, fields.Read<uint>(19));
SetModifier(ItemModifier.TransmogAppearanceSpec1, fields.Read<uint>(20));
SetModifier(ItemModifier.TransmogAppearanceSpec2, fields.Read<uint>(21));
@@ -505,14 +501,14 @@ namespace Game.Entities
// Enchants must be loaded after all other bonus/scaling data
var enchantmentTokens = new StringArray(fields.Read<string>(8), ' ');
if (enchantmentTokens.Length == (int)EnchantmentSlot.Max * (int)EnchantmentOffset.Max)
if (enchantmentTokens.Length == (int)EnchantmentSlot.Max * 3)
{
for (int i = 0; i < (int)EnchantmentSlot.Max; ++i)
{
ItemEnchantment enchantmentField = m_itemData.ModifyValue(m_itemData.Enchantment, i);
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.ID), uint.Parse(enchantmentTokens[i * (int)EnchantmentOffset.Max + 0]));
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.Duration), uint.Parse(enchantmentTokens[i * (int)EnchantmentOffset.Max + 1]));
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.Charges), short.Parse(enchantmentTokens[i * (int)EnchantmentOffset.Max + 2]));
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.ID), uint.Parse(enchantmentTokens[i * 3 + 0]));
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.Duration), uint.Parse(enchantmentTokens[i * 3 + 1]));
SetUpdateFieldValue(enchantmentField.ModifyValue(enchantmentField.Charges), short.Parse(enchantmentTokens[i * 3 + 2]));
}
}
@@ -2527,6 +2523,13 @@ namespace Game.Entities
public ObjectGuid GetChildItem() { return m_childItem; }
public void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
public ItemEffectRecord[] GetEffects() { return _bonusData.Effects[0.._bonusData.EffectCount]; }
public ItemEffectRecord GetEffect(int i)
{
Cypher.Assert(i < _bonusData.EffectCount, $"Attempted to get effect at index {i} but item has only {_bonusData.EffectCount} effects!");
return _bonusData.Effects[i];
}
//Static
public static bool ItemCanGoIntoBag(ItemTemplate pProto, ItemTemplate pBagProto)
{
@@ -2657,14 +2660,6 @@ namespace Game.Entities
public uint count;
}
public enum EnchantmentOffset
{
Id = 0,
Duration = 1,
Charges = 2, // now here not only charges, but something new in wotlk
Max = 3
}
public class ItemSetEffect
{
public uint ItemSetID;
@@ -2713,6 +2708,13 @@ namespace Game.Entities
if (azeriteEmpoweredItem != null)
AzeriteTierUnlockSetId = azeriteEmpoweredItem.AzeriteTierUnlockSetID;
EffectCount = 0;
foreach (ItemEffectRecord itemEffect in proto.Effects)
Effects[EffectCount++] = itemEffect;
for (int i = EffectCount; i < Effects.Length; ++i)
Effects[i] = null;
CanDisenchant = !proto.GetFlags().HasAnyFlag(ItemFlags.NoDisenchant);
CanScrap = proto.GetFlags4().HasAnyFlag(ItemFlags4.Scrapable);
@@ -2835,6 +2837,11 @@ namespace Game.Entities
case ItemBonusType.OverrideCanScrap:
CanScrap = values[0] != 0;
break;
case ItemBonusType.ItemEffectId:
ItemEffectRecord itemEffect = CliDB.ItemEffectStorage.LookupByKey(values[0]);
if (itemEffect != null)
Effects[EffectCount++] = itemEffect;
break;
}
}
@@ -2858,6 +2865,8 @@ namespace Game.Entities
public int RequiredLevelOverride;
public uint AzeriteTierUnlockSetId;
public uint Suffix;
public ItemEffectRecord[] Effects = new ItemEffectRecord[13];
public int EffectCount;
public bool CanDisenchant;
public bool CanScrap;
public bool HasFixedLevel;
+6 -19
View File
@@ -4265,24 +4265,14 @@ namespace Game.Entities
if (item == null)
return;
ItemTemplate proto = item.GetTemplate();
if (proto == null)
return;
for (byte i = 0; i < proto.Effects.Count; ++i)
foreach (ItemEffectRecord effectData in item.GetEffects())
{
var spellData = proto.Effects[i];
// no spell
if (spellData.SpellID == 0)
continue;
// wrong triggering type
if (apply && spellData.TriggerType != ItemSpelltriggerType.OnEquip)
if (apply && effectData.TriggerType != ItemSpelltriggerType.OnEquip)
continue;
// check if it is valid spell
SpellInfo spellproto = Global.SpellMgr.GetSpellInfo((uint)spellData.SpellID);
SpellInfo spellproto = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID);
if (spellproto == null)
continue;
@@ -4290,7 +4280,7 @@ namespace Game.Entities
&& Global.DB2Mgr.GetHeirloomByItemId(item.GetEntry()) != null)
continue;
if (spellData.ChrSpecializationID != 0 && spellData.ChrSpecializationID != GetPrimarySpecialization())
if (effectData.ChrSpecializationID != 0 && effectData.ChrSpecializationID != GetPrimarySpecialization())
continue;
ApplyEquipSpell(spellproto, item, apply, formChange);
@@ -4340,15 +4330,12 @@ namespace Game.Entities
void ApplyEquipCooldown(Item pItem)
{
ItemTemplate proto = pItem.GetTemplate();
if (proto.GetFlags().HasAnyFlag(ItemFlags.NoEquipCooldown))
if (pItem.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.NoEquipCooldown))
return;
DateTime now = GameTime.GetGameTimeSteadyPoint();
for (byte i = 0; i < proto.Effects.Count; ++i)
foreach (ItemEffectRecord effectData in pItem.GetEffects())
{
var effectData = proto.Effects[i];
// apply proc cooldown to equip auras if we have any
if (effectData.TriggerType == ItemSpelltriggerType.OnEquip)
{
+16 -30
View File
@@ -1499,19 +1499,18 @@ namespace Game.Entities
public void CastItemUseSpell(Item item, SpellCastTargets targets, ObjectGuid castCount, uint[] misc)
{
ItemTemplate proto = item.GetTemplate();
// special learning case
if (proto.Effects.Count >= 2)
if (item.GetBonus().EffectCount >= 2)
{
if (proto.Effects[0].SpellID == 483 || proto.Effects[0].SpellID == 55884)
if (item.GetEffect(0).SpellID == 483 || item.GetEffect(0).SpellID == 55884)
{
uint learn_spell_id = (uint)proto.Effects[0].SpellID;
uint learning_spell_id = (uint)proto.Effects[1].SpellID;
uint learn_spell_id = (uint)item.GetEffect(0).SpellID;
uint learning_spell_id = (uint)item.GetEffect(1).SpellID;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(learn_spell_id);
if (spellInfo == null)
{
Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring ", proto.GetId(), learn_spell_id);
Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring ", item.GetEntry(), learn_spell_id);
SendEquipError(InventoryResult.InternalBagError, item);
return;
}
@@ -1532,22 +1531,16 @@ namespace Game.Entities
}
// item spells casted at use
for (byte i = 0; i < proto.Effects.Count; ++i)
foreach (ItemEffectRecord effectData in item.GetEffects())
{
var spellData = proto.Effects[i];
// no spell
if (spellData.SpellID == 0)
continue;
// wrong triggering type
if (spellData.TriggerType != ItemSpelltriggerType.OnUse)
if (effectData.TriggerType != ItemSpelltriggerType.OnUse)
continue;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spellData.SpellID);
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring", proto.GetId(), spellData.SpellID);
Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring", item.GetEntry(), effectData.SpellID);
continue;
}
@@ -1791,13 +1784,12 @@ namespace Game.Entities
void ApplyItemObtainSpells(Item item, bool apply)
{
ItemTemplate itemTemplate = item.GetTemplate();
for (byte i = 0; i < itemTemplate.Effects.Count; ++i)
foreach (ItemEffectRecord effect in item.GetEffects())
{
if (itemTemplate.Effects[i].TriggerType != ItemSpelltriggerType.OnObtain) // On obtain trigger
if (effect.TriggerType != ItemSpelltriggerType.OnObtain) // On obtain trigger
continue;
int spellId = itemTemplate.Effects[i].SpellID;
int spellId = effect.SpellID;
if (spellId <= 0)
continue;
@@ -3331,22 +3323,16 @@ namespace Game.Entities
bool canTrigger = damageInfo.GetHitMask().HasAnyFlag(ProcFlagsHit.Normal | ProcFlagsHit.Critical | ProcFlagsHit.Absorb);
if (canTrigger)
{
for (byte i = 0; i < proto.Effects.Count; ++i)
foreach (ItemEffectRecord effectData in item.GetEffects())
{
var spellData = proto.Effects[i];
// no spell
if (spellData.SpellID == 0)
continue;
// wrong triggering type
if (spellData.TriggerType != ItemSpelltriggerType.ChanceOnHit)
if (effectData.TriggerType != ItemSpelltriggerType.ChanceOnHit)
continue;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spellData.SpellID);
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID);
if (spellInfo == null)
{
Log.outError(LogFilter.Player, "WORLD: unknown Item spellid {0}", spellData.SpellID);
Log.outError(LogFilter.Player, "WORLD: unknown Item spellid {0}", effectData.SpellID);
continue;
}
+2 -2
View File
@@ -1052,10 +1052,10 @@ namespace Game
if (!item)
return;
if (item.GetTemplate().Effects.Count < 2)
if (item.GetBonus().EffectCount < 2)
return;
uint spellToLearn = (uint)item.GetTemplate().Effects[1].SpellID;
uint spellToLearn = (uint)item.GetEffect(1).SpellID;
var entry = Global.SpellMgr.GetBattlePetSpecies(spellToLearn);
if (entry != null)
+2 -2
View File
@@ -90,9 +90,9 @@ namespace Game
if (user.IsInCombat())
{
for (int i = 0; i < proto.Effects.Count; ++i)
foreach (ItemEffectRecord effect in item.GetEffects())
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)proto.Effects[i].SpellID);
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effect.SpellID);
if (spellInfo != null)
{
if (!spellInfo.CanBeUsedInCombat())
+45 -41
View File
@@ -4051,34 +4051,34 @@ namespace Game.Spells
bool expendable = false;
bool withoutCharges = false;
for (int i = 0; i < proto.Effects.Count && i < 5; ++i)
foreach (ItemEffectRecord itemEffect in m_CastItem.GetEffects())
{
if (proto.Effects[i].SpellID != 0)
if (itemEffect.LegacySlotIndex >= m_CastItem.m_itemData.SpellCharges.GetSize())
continue;
// item has limited charges
if (itemEffect.Charges != 0)
{
// item has limited charges
if (proto.Effects[i].Charges != 0)
if (itemEffect.Charges < 0)
expendable = true;
int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex);
// item has charges left
if (charges != 0)
{
if (proto.Effects[i].Charges < 0)
expendable = true;
if (charges > 0)
--charges;
else
++charges;
int charges = m_CastItem.GetSpellCharges(i);
// item has charges left
if (charges != 0)
{
if (charges > 0)
--charges;
else
++charges;
if (proto.GetMaxStackSize() == 1)
m_CastItem.SetSpellCharges(i, charges);
m_CastItem.SetState(ItemUpdateState.Changed, m_caster.ToPlayer());
}
// all charges used
withoutCharges = (charges == 0);
if (proto.GetMaxStackSize() == 1)
m_CastItem.SetSpellCharges(itemEffect.LegacySlotIndex, charges);
m_CastItem.SetState(ItemUpdateState.Changed, m_caster.ToPlayer());
}
// all charges used
withoutCharges = (charges == 0);
}
}
@@ -4215,10 +4215,8 @@ namespace Game.Spells
if (!m_caster.IsTypeId(TypeId.Player))
return;
ItemTemplate castItemTemplate = m_CastItem?.GetTemplate();
// do not take reagents for these item casts
if (castItemTemplate != null && Convert.ToBoolean(castItemTemplate.GetFlags() & ItemFlags.NoReagentCost))
if (m_CastItem != null && m_CastItem.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.NoReagentCost))
return;
Player p_caster = m_caster.ToPlayer();
@@ -4234,13 +4232,16 @@ namespace Game.Spells
uint itemcount = m_spellInfo.ReagentCount[x];
// if CastItem is also spell reagent
if (castItemTemplate != null && castItemTemplate.GetId() == itemid)
if (m_CastItem != null && m_CastItem.GetEntry() == itemid)
{
for (int s = 0; s < castItemTemplate.Effects.Count && s < 5; ++s)
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(s);
if (castItemTemplate.Effects[s].Charges < 0 && Math.Abs(charges) < 2)
int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex);
if (itemEffect.Charges < 0 && Math.Abs(charges) < 2)
{
++itemcount;
break;
@@ -5826,9 +5827,9 @@ namespace Game.Spells
if (proto == null)
return SpellCastResult.ItemNotReady;
for (int i = 0; i < proto.Effects.Count && i < 5; ++i)
if (proto.Effects[i].Charges > 0)
if (m_CastItem.GetSpellCharges(i) == 0)
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;
// consumable cast item checks
@@ -5931,11 +5932,15 @@ namespace Game.Spells
ItemTemplate proto = m_CastItem.GetTemplate();
if (proto == null)
return SpellCastResult.ItemNotReady;
for (int s = 0; s < proto.Effects.Count && s < 5; ++s)
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(s);
if (proto.Effects[s].Charges < 0 && Math.Abs(charges) < 2)
int charges = m_CastItem.GetSpellCharges(itemEffect.LegacySlotIndex);
if (itemEffect.Charges < 0 && Math.Abs(charges) < 2)
{
++itemcount;
break;
@@ -6060,10 +6065,9 @@ namespace Game.Spells
return SpellCastResult.Lowlevel;
bool isItemUsable = false;
ItemTemplate proto = targetItem.GetTemplate();
for (byte e = 0; e < proto.Effects.Count; ++e)
foreach (ItemEffectRecord itemEffect in targetItem.GetEffects())
{
if (proto.Effects[e].SpellID != 0 && proto.Effects[e].TriggerType == ItemSpelltriggerType.OnUse)
if (itemEffect.SpellID != 0 && itemEffect.TriggerType == ItemSpelltriggerType.OnUse)
{
isItemUsable = true;
break;
@@ -6238,8 +6242,8 @@ namespace Game.Spells
Item item = player.GetItemByEntry(itemId);
if (item != null)
{
for (int x = 0; x < proto.Effects.Count && x < 5; ++x)
if (proto.Effects[x].Charges != 0 && item.GetSpellCharges(x) == proto.Effects[x].Charges)
foreach (ItemEffectRecord itemEffect in item.GetEffects())
if (itemEffect.LegacySlotIndex <= item.m_itemData.SpellCharges.GetSize() && itemEffect.Charges != 0 && item.GetSpellCharges(itemEffect.LegacySlotIndex) == itemEffect.Charges)
return SpellCastResult.ItemAtMaxCharges;
}
break;
+3 -3
View File
@@ -5275,9 +5275,9 @@ namespace Game.Spells
Item item = player.GetItemByEntry(effectInfo.ItemType);
if (item != null)
{
ItemTemplate proto = item.GetTemplate();
for (int x = 0; x < proto.Effects.Count && x < 5; ++x)
item.SetSpellCharges(x, proto.Effects[x].Charges);
foreach (ItemEffectRecord itemEffect in item.GetEffects())
if (itemEffect.LegacySlotIndex <= item.m_itemData.SpellCharges.GetSize())
item.SetSpellCharges(itemEffect.LegacySlotIndex, itemEffect.Charges);
item.SetState(ItemUpdateState.Changed, player);
}