diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 3db70fd7d..a20ba8fe1 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -83,7 +83,7 @@ namespace Framework.Database PrepareStatement(CharStatements.SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime, entranceId FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?"); - PrepareStatement(CharStatements.SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel FROM character_aura WHERE guid = ?"); + PrepareStatement(CharStatements.SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_AURA_EFFECTS, "SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer FROM character_queststatus WHERE guid = ? AND status <> 0"); @@ -322,8 +322,8 @@ namespace Framework.Database PrepareStatement(CharStatements.DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?"); // Auras - PrepareStatement(CharStatements.INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemLevel) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.INS_AURA_EFFECT, "INSERT INTO character_aura_effect (guid, casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index f99892d42..cb58bc3c3 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -359,7 +359,7 @@ namespace Game.DataStorage BarberShopCostBaseGameTable = GameTableReader.Read("BarberShopCostBase.txt"); BaseMPGameTable = GameTableReader.Read("BaseMp.txt"); CombatRatingsGameTable = GameTableReader.Read("CombatRatings.txt"); - CombatRatingsMultByILvlGameTable = GameTableReader.Read("CombatRatingsMultByILvl.txt"); + CombatRatingsMultByILvlGameTable = GameTableReader.Read("CombatRatingsMultByILvl.txt"); ItemSocketCostPerLevelGameTable = GameTableReader.Read("ItemSocketCostPerLevel.txt"); HpPerStaGameTable = GameTableReader.Read("HpPerSta.txt"); NpcDamageByClassGameTable[0] = GameTableReader.Read("NpcDamageByClass.txt"); @@ -380,6 +380,7 @@ namespace Game.DataStorage NpcTotalHpGameTable[6] = GameTableReader.Read("NpcTotalHpExp6.txt"); NpcTotalHpGameTable[7] = GameTableReader.Read("NpcTotalHpExp7.txt"); SpellScalingGameTable = GameTableReader.Read("SpellScaling.txt"); + StaminaMultByILvlGameTable = GameTableReader.Read("StaminaMultByILvl.txt"); XpGameTable = GameTableReader.Read("xp.txt"); Log.outInfo(LogFilter.ServerLoading, "Initialized {0} DBC GameTables data stores in {1} ms", LoadedFileCount, Time.GetMSTimeDiffToNow(oldMSTime)); @@ -641,13 +642,14 @@ namespace Game.DataStorage public static GameTable BarberShopCostBaseGameTable; public static GameTable BaseMPGameTable; public static GameTable CombatRatingsGameTable; - public static GameTable CombatRatingsMultByILvlGameTable; + public static GameTable CombatRatingsMultByILvlGameTable; public static GameTable HpPerStaGameTable; public static GameTable ItemSocketCostPerLevelGameTable; public static GameTable[] NpcDamageByClassGameTable = new GameTable[(int)Expansion.Max]; public static GameTable NpcManaCostScalerGameTable; public static GameTable[] NpcTotalHpGameTable = new GameTable[(int)Expansion.Max]; public static GameTable SpellScalingGameTable; + public static GameTable StaminaMultByILvlGameTable; public static GameTable XpGameTable; #endregion @@ -747,6 +749,29 @@ namespace Game.DataStorage return 0.0f; } + + public static float GetIlvlStatMultiplier(GtGenericMultByILvlRecord row, InventoryType invType) + { + switch (invType) + { + case InventoryType.Neck: + case InventoryType.Finger: + return row.JewelryMultiplier; + case InventoryType.Trinket: + return row.TrinketMultiplier; + case InventoryType.Weapon: + case InventoryType.Shield: + case InventoryType.Ranged: + case InventoryType.Weapon2Hand: + case InventoryType.WeaponMainhand: + case InventoryType.WeaponOffhand: + case InventoryType.Holdable: + case InventoryType.RangedRight: + return row.WeaponMultiplier; + default: + return row.ArmorMultiplier; + } + } #endregion } } diff --git a/Source/Game/DataStorage/Structs/GameTablesRecords.cs b/Source/Game/DataStorage/Structs/GameTablesRecords.cs index 4aeadb18a..153a4d0e6 100644 --- a/Source/Game/DataStorage/Structs/GameTablesRecords.cs +++ b/Source/Game/DataStorage/Structs/GameTablesRecords.cs @@ -90,7 +90,7 @@ namespace Game.DataStorage public float Unused12; } - public sealed class GtCombatRatingsMultByILvlRecord + public sealed class GtGenericMultByILvlRecord { public float ArmorMultiplier; public float WeaponMultiplier; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 6c39ca1de..2134df96b 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -487,7 +487,8 @@ namespace Game.Entities int maxDuration = auraResult.Read(6); int remainTime = auraResult.Read(7); byte remainCharges = auraResult.Read(8); - int castItemLevel = auraResult.Read(9); + uint castItemId = auraResult.Read(9); + int castItemLevel = auraResult.Read(10); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId); if (spellInfo == null) @@ -518,7 +519,7 @@ namespace Game.Entities AuraLoadEffectInfo info = effectInfo[key]; ObjectGuid castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellInfo.Id, GetMap().GenerateLowGuid(HighGuid.Cast)); - Aura aura = Aura.TryCreate(spellInfo, castId, key.EffectMask, this, null, info.BaseAmounts, null, casterGuid, itemGuid, castItemLevel); + Aura aura = Aura.TryCreate(spellInfo, castId, key.EffectMask, this, null, info.BaseAmounts, null, casterGuid, itemGuid, castItemId, castItemLevel); if (aura != null) { if (!aura.CanBeSaved()) @@ -1694,6 +1695,7 @@ namespace Game.Entities stmt.AddValue(index++, aura.GetMaxDuration()); stmt.AddValue(index++, aura.GetDuration()); stmt.AddValue(index++, aura.GetCharges()); + stmt.AddValue(index++, aura.GetCastItemId()); stmt.AddValue(index, aura.GetCastItemLevel()); trans.Append(stmt); diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 20e12f8ce..b57723d9e 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -4002,33 +4002,9 @@ namespace Game.Entities uint itemLevel = item.GetItemLevel(this); float combatRatingMultiplier = 1.0f; - GtCombatRatingsMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(itemLevel); + GtGenericMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(itemLevel); if (ratingMult != null) - { - switch (proto.GetInventoryType()) - { - case InventoryType.Weapon: - case InventoryType.Shield: - case InventoryType.Ranged: - case InventoryType.Weapon2Hand: - case InventoryType.WeaponMainhand: - case InventoryType.WeaponOffhand: - case InventoryType.Holdable: - case InventoryType.RangedRight: - combatRatingMultiplier = ratingMult.WeaponMultiplier; - break; - case InventoryType.Trinket: - combatRatingMultiplier = ratingMult.TrinketMultiplier; - break; - case InventoryType.Neck: - case InventoryType.Finger: - combatRatingMultiplier = ratingMult.JewelryMultiplier; - break; - default: - combatRatingMultiplier = ratingMult.ArmorMultiplier; - break; - } - } + combatRatingMultiplier = CliDB.GetIlvlStatMultiplier(ratingMult, proto.GetInventoryType()); // req. check at equip, but allow use for extended range if range limit max level, set proper level for (byte i = 0; i < ItemConst.MaxStats; ++i) @@ -4066,6 +4042,10 @@ namespace Game.Entities //ApplyStatBuffMod(Stats.Spirit, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatSpirit, UnitModifierType.BasePCTExcludeCreate)), apply); //break; case ItemModType.Stamina: //modify stamina + GtGenericMultByILvlRecord staminaMult = CliDB.StaminaMultByILvlGameTable.GetRow(itemLevel); + if (staminaMult != null) + val = (int)(val * CliDB.GetIlvlStatMultiplier(staminaMult, proto.GetInventoryType())); + HandleStatModifier(UnitMods.StatStamina, UnitModifierType.BaseValue, (float)val, apply); ApplyStatBuffMod(Stats.Stamina, MathFunctions.CalculatePct(val, GetModifierValue(UnitMods.StatStamina, UnitModifierType.BasePCTExcludeCreate)), apply); break; diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 22047bff0..dac5ac97e 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -33,16 +33,16 @@ namespace Game.Entities // function uses real base points (typically value - 1) - public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, int? basePoints = null, int itemLevel = -1) + public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, int? basePoints = null, uint castItemId = 0, int itemLevel = -1) { SpellEffectInfo effect = spellProto.GetEffect(GetMap().GetDifficultyID(), effect_index); - return effect != null ? effect.CalcValue(this, basePoints, target) : 0; + return effect != null ? effect.CalcValue(this, basePoints, target, castItemId, itemLevel) : 0; } - public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, out float variance, int? basePoints = null, int itemLevel = -1) + public int CalculateSpellDamage(Unit target, SpellInfo spellProto, uint effect_index, out float variance, int? basePoints = null, uint castItemId = 0, int itemLevel = -1) { SpellEffectInfo effect = spellProto.GetEffect(GetMap().GetDifficultyID(), effect_index); variance = 0.0f; - return effect != null ? effect.CalcValue(out variance, this, basePoints, target, itemLevel) : 0; + return effect != null ? effect.CalcValue(out variance, this, basePoints, target, castItemId, itemLevel) : 0; } public int SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) @@ -4142,7 +4142,7 @@ namespace Game.Entities } } } - public Aura _TryStackingOrRefreshingExistingAura(SpellInfo newAura, uint effMask, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, int castItemLevel = -1) + public Aura _TryStackingOrRefreshingExistingAura(SpellInfo newAura, uint effMask, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, uint castItemId = 0, int castItemLevel = -1) { Cypher.Assert(!casterGUID.IsEmpty() || caster); @@ -4157,6 +4157,7 @@ namespace Game.Entities if (castItem != null) { castItemGuid = castItem.GetGUID(); + castItemId = castItem.GetEntry(); Player owner = castItem.GetOwner(); if (owner) castItemLevel = (int)castItem.GetItemLevel(owner); @@ -4197,6 +4198,7 @@ namespace Game.Entities if (castItemGuid != foundAura.GetCastItemGUID()) { foundAura.SetCastItemGUID(castItemGuid); + foundAura.SetCastItemId(castItemId); foundAura.SetCastItemLevel(castItemLevel); } diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index bc3101cff..82081ffe8 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -284,12 +284,13 @@ namespace Game.Spells { const int UPDATE_TARGET_MAP_INTERVAL = 500; - public Aura(SpellInfo spellproto, ObjectGuid castId, WorldObject owner, Unit caster, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, int castItemLevel) + public Aura(SpellInfo spellproto, ObjectGuid castId, WorldObject owner, Unit caster, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) { m_spellInfo = spellproto; m_castGuid = castId; m_casterGuid = !casterGUID.IsEmpty() ? casterGUID : caster.GetGUID(); m_castItemGuid = castItem != null ? castItem.GetGUID() : castItemGuid; + m_castItemId = castItem != null ? castItem.GetEntry() : castItemId; m_castItemLevel = castItemLevel; m_spellXSpellVisualId = caster ? caster.GetCastSpellXSpellVisualId(spellproto) : spellproto.GetSpellXSpellVisualId(); m_applyTime = Time.UnixTime; @@ -2242,6 +2243,7 @@ namespace Game.Spells public ObjectGuid GetCastGUID() { return m_castGuid; } public ObjectGuid GetCasterGUID() { return m_casterGuid; } public ObjectGuid GetCastItemGUID() { return m_castItemGuid; } + public uint GetCastItemId() { return m_castItemId; } public int GetCastItemLevel() { return m_castItemLevel; } public uint GetSpellXSpellVisualId() { return m_spellXSpellVisualId; } public WorldObject GetOwner() { return m_owner; } @@ -2261,6 +2263,11 @@ namespace Game.Spells m_castItemGuid = guid; } + public void SetCastItemId(uint id) + { + m_castItemId = id; + } + public void SetCastItemLevel(int level) { m_castItemLevel = level; @@ -2390,12 +2397,12 @@ namespace Game.Spells } return (effMask & availableEffectMask); } - public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, int castItemLevel = -1) + public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount = null, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, uint castItemId = 0, int castItemLevel = -1) { bool throwway; - return TryRefreshStackOrCreate(spellproto, castId, tryEffMask, owner, caster, out throwway, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemGuid, castItemLevel); + return TryRefreshStackOrCreate(spellproto, castId, tryEffMask, owner, caster, out throwway, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemGuid, castItemId, castItemLevel); } - public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, out bool refresh, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, int castItemLevel = -1) + public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, out bool refresh, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default, bool resetPeriodicTimer = true, ObjectGuid castItemGuid = default, uint castItemId = 0, int castItemLevel = -1) { Cypher.Assert(spellproto != null); Cypher.Assert(owner != null); @@ -2406,7 +2413,7 @@ namespace Game.Spells uint effMask = BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (effMask == 0) return null; - Aura foundAura = owner.ToUnit()._TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemGuid, castItemLevel); + Aura foundAura = owner.ToUnit()._TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer, castItemGuid, castItemId, castItemLevel); if (foundAura != null) { // we've here aura, which script triggered removal after modding stack amount @@ -2418,9 +2425,9 @@ namespace Game.Spells return foundAura; } else - return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); } - public static Aura TryCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default, ObjectGuid castItemGuid = default, int castItemLevel = -1) + public static Aura TryCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem = null, ObjectGuid casterGUID = default, ObjectGuid castItemGuid = default, uint castItemId = 0, int castItemLevel = -1) { Cypher.Assert(spellproto != null); Cypher.Assert(owner != null); @@ -2429,9 +2436,9 @@ namespace Game.Spells uint effMask = BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (effMask == 0) return null; - return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); } - public static Aura Create(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, int castItemLevel) + public static Aura Create(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) { Cypher.Assert(effMask != 0); Cypher.Assert(spellproto != null); @@ -2461,10 +2468,10 @@ namespace Game.Spells { case TypeId.Unit: case TypeId.Player: - aura = new UnitAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemLevel); + aura = new UnitAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; case TypeId.DynamicObject: - aura = new DynObjAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemLevel); + aura = new DynObjAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; default: Cypher.Assert(false); @@ -2482,6 +2489,7 @@ namespace Game.Spells ObjectGuid m_castGuid; ObjectGuid m_casterGuid; ObjectGuid m_castItemGuid; + uint m_castItemId; int m_castItemLevel; uint m_spellXSpellVisualId; long m_applyTime; @@ -2518,8 +2526,8 @@ namespace Game.Spells public class UnitAura : Aura { - public UnitAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, int castItemLevel) - : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemLevel) + public UnitAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) + : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { m_AuraDRGroup = DiminishingGroup.None; LoadScripts(); @@ -2629,8 +2637,8 @@ namespace Game.Spells public class DynObjAura : Aura { - public DynObjAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, int castItemLevel) - : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemLevel) + public DynObjAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) + : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { LoadScripts(); Cypher.Assert(GetDynobjOwner() != null); diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 222b6b5e2..83d682db6 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -32,12 +32,12 @@ namespace Game.Spells { public class AuraEffect { - public AuraEffect(Aura abase, uint effindex, int? baseAmount, Unit caster) + public AuraEffect(Aura baseAura, uint effindex, int? baseAmount, Unit caster) { - auraBase = abase; - m_spellInfo = abase.GetSpellInfo(); - _effectInfo = abase.GetSpellEffectInfo(effindex); - m_baseAmount = baseAmount.HasValue ? baseAmount.Value : _effectInfo.CalcBaseValue(caster, abase.GetAuraType() == AuraObjectType.Unit ? abase.GetOwner().ToUnit() : null, abase.GetCastItemLevel()); + auraBase = baseAura; + m_spellInfo = baseAura.GetSpellInfo(); + _effectInfo = baseAura.GetSpellEffectInfo(effindex); + m_baseAmount = baseAmount.HasValue ? baseAmount.Value : _effectInfo.CalcBaseValue(caster, baseAura.GetAuraType() == AuraObjectType.Unit ? baseAura.GetOwner().ToUnit() : null, baseAura.GetCastItemId(), baseAura.GetCastItemLevel()); m_donePct = 1.0f; m_effIndex = (byte)effindex; m_canBeRecalculated = true; @@ -76,7 +76,7 @@ namespace Game.Spells int amount = 0; if (!m_spellInfo.HasAttribute(SpellAttr8.MasterySpecialization) || MathFunctions.fuzzyEq(GetSpellEffectInfo().BonusCoefficient, 0.0f)) - amount = GetSpellEffectInfo().CalcValue(caster, m_baseAmount, GetBase().GetOwner().ToUnit(), GetBase().GetCastItemLevel()); + amount = GetSpellEffectInfo().CalcValue(caster, m_baseAmount, GetBase().GetOwner().ToUnit(), GetBase().GetCastItemId(), GetBase().GetCastItemLevel()); else if (caster != null && caster.IsTypeId(TypeId.Player)) amount = (int)(caster.ToPlayer().m_activePlayerData.Mastery * GetSpellEffectInfo().BonusCoefficient); diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 593de142c..4acddc185 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2073,12 +2073,12 @@ namespace Game.Spells foreach (SpellEffectInfo auraSpellEffect in GetEffects()) if (auraSpellEffect != null) basePoints[auraSpellEffect.EffectIndex] = (m_spellValue.CustomBasePointsMask & (1 << (int)auraSpellEffect.EffectIndex)) != 0 ? - m_spellValue.EffectBasePoints[auraSpellEffect.EffectIndex] : auraSpellEffect.CalcBaseValue(m_originalCaster, unit, m_castItemLevel); + m_spellValue.EffectBasePoints[auraSpellEffect.EffectIndex] : auraSpellEffect.CalcBaseValue(m_originalCaster, unit, m_castItemEntry, m_castItemLevel); bool refresh = false; bool resetPeriodicTimer = !_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontResetPeriodicTimer); m_spellAura = Aura.TryRefreshStackOrCreate(m_spellInfo, m_castId, (byte)effectMask, unit, - m_originalCaster, out refresh, basePoints, m_CastItem, ObjectGuid.Empty, resetPeriodicTimer, ObjectGuid.Empty, m_castItemLevel); + m_originalCaster, out refresh, basePoints, m_CastItem, ObjectGuid.Empty, resetPeriodicTimer, ObjectGuid.Empty, m_castItemEntry, m_castItemLevel); if (m_spellAura != null) { // Set aura stack amount to desired value @@ -7121,7 +7121,7 @@ namespace Game.Spells if ((m_spellValue.CustomBasePointsMask & (1 << (int)i)) != 0) basePoint = m_spellValue.EffectBasePoints[i]; - return m_caster.CalculateSpellDamage(target, m_spellInfo, i, basePoint, m_castItemLevel); + return m_caster.CalculateSpellDamage(target, m_spellInfo, i, basePoint, m_castItemEntry, m_castItemLevel); } int CalculateDamage(uint i, Unit target, out float variance) { @@ -7129,7 +7129,7 @@ namespace Game.Spells if ((m_spellValue.CustomBasePointsMask & (1 << (int)i)) != 0) basePoint = m_spellValue.EffectBasePoints[i]; - return m_caster.CalculateSpellDamage(target, m_spellInfo, i, out variance, basePoint, m_castItemLevel); + return m_caster.CalculateSpellDamage(target, m_spellInfo, i, out variance, basePoint, m_castItemEntry, m_castItemLevel); } public SpellState GetState() { @@ -7566,7 +7566,7 @@ namespace Game.Spells Cypher.Assert(effects.Length <= SpellConst.MaxEffects); foreach (SpellEffectInfo effect in effects) if (effect != null) - EffectBasePoints[effect.EffectIndex] = effect.CalcBaseValue(caster, null, -1); + EffectBasePoints[effect.EffectIndex] = effect.CalcBaseValue(caster, null, 0, -1); CustomBasePointsMask = 0; MaxAffectedTargets = proto.MaxAffectedTargets; diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index b084f074e..4e850603c 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -1223,7 +1223,7 @@ namespace Game.Spells if (!dynObj.CreateDynamicObject(caster.GetMap().GenerateLowGuid(HighGuid.DynamicObject), caster, m_spellInfo, destTarget, radius, DynamicObjectType.AreaSpell, m_SpellVisual)) return; - Aura aura = Aura.TryCreate(m_spellInfo, m_castId, SpellConst.MaxEffectMask, dynObj, caster, m_spellValue.EffectBasePoints, null, ObjectGuid.Empty, ObjectGuid.Empty, m_castItemLevel); + Aura aura = Aura.TryCreate(m_spellInfo, m_castId, SpellConst.MaxEffectMask, dynObj, caster, m_spellValue.EffectBasePoints, null, ObjectGuid.Empty, ObjectGuid.Empty, m_castItemEntry, m_castItemLevel); if (aura != null) { m_spellAura = aura; diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 6b838f93d..79dd58628 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -3905,18 +3905,18 @@ namespace Game.Spells return IsAreaAuraEffect() || Effect == SpellEffectName.ApplyAura; } - public int CalcValue(Unit caster = null, int? bp = null, Unit target = null, int itemLevel = -1) + public int CalcValue(Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1) { float throwAway; - return CalcValue(out throwAway, caster, bp, target, itemLevel); + return CalcValue(out throwAway, caster, bp, target, castItemId, itemLevel); } - public int CalcValue(out float variance, Unit caster = null, int? bp = null, Unit target = null, int itemLevel = -1) + public int CalcValue(out float variance, Unit caster = null, int? bp = null, Unit target = null, uint castItemId = 0, int itemLevel = -1) { variance = 0.0f; float basePointsPerLevel = RealPointsPerLevel; // TODO: this needs to be a float, not rounded - int basePoints = CalcBaseValue(caster, target, itemLevel); + int basePoints = CalcBaseValue(caster, target, castItemId, itemLevel); float value = bp.HasValue ? bp.Value : BasePoints; float comboDamage = PointsPerResource; @@ -3964,7 +3964,7 @@ namespace Game.Spells return (int)Math.Round(value); } - public int CalcBaseValue(Unit caster, Unit target, int itemLevel) + public int CalcBaseValue(Unit caster, Unit target, uint itemId, int itemLevel) { if (Scaling.Coefficient != 0.0f) { @@ -4011,10 +4011,34 @@ namespace Game.Spells if (_spellInfo.Scaling._Class == -7) { - // todo: get inventorytype here - GtCombatRatingsMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel); + GtGenericMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel); if (ratingMult != null) - tempValue *= ratingMult.ArmorMultiplier; + { + ItemSparseRecord itemSparse = CliDB.ItemSparseStorage.LookupByKey(itemId); + if (itemSparse != null) + tempValue *= CliDB.GetIlvlStatMultiplier(ratingMult, itemSparse.inventoryType); + } + } + + if (IsAura(AuraType.ModRating)) + { + GtGenericMultByILvlRecord ratingMult = CliDB.CombatRatingsMultByILvlGameTable.GetRow(effectiveItemLevel); + if (ratingMult != null) + { + ItemSparseRecord itemSparse = CliDB.ItemSparseStorage.LookupByKey(itemId); + if (itemSparse != null) + tempValue *= CliDB.GetIlvlStatMultiplier(ratingMult, itemSparse.inventoryType); + } + else if (IsAura(AuraType.ModStat) && MiscValue == (int)Stats.Stamina) + { + GtGenericMultByILvlRecord staminaMult = CliDB.StaminaMultByILvlGameTable.GetRow(effectiveItemLevel); + if (staminaMult != null) + { + ItemSparseRecord itemSparse = CliDB.ItemSparseStorage.LookupByKey(itemId); + if (itemSparse != null) + tempValue *= CliDB.GetIlvlStatMultiplier(staminaMult, itemSparse.inventoryType); + } + } } } @@ -4172,6 +4196,7 @@ namespace Game.Spells case SpellEffectName.ApplyAreaAuraOwner: case SpellEffectName.ApllyAuraOnPet: case SpellEffectName.Unk202: + case SpellEffectName.ApplyAreaAuraPartyNonrandom: switch (ApplyAuraName) { case AuraType.PeriodicDamage: diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 098ea47c8..ee50bbdf9 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -469,6 +469,7 @@ CREATE TABLE `character_aura` ( `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', `remainCharges` tinyint(3) unsigned NOT NULL DEFAULT '0', + `castItemId` int(10) unsigned NOT NULL DEFAULT '0', `castItemLevel` int(11) NOT NULL DEFAULT '-1', PRIMARY KEY (`guid`,`casterGuid`,`itemGuid`,`spell`,`effectMask`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System'; @@ -3660,7 +3661,8 @@ INSERT INTO `updates` VALUES ('2019_10_26_01_characters.sql','59D5860930D02AB77D2AAA704C564957A9143760','RELEASED','2019-10-26 22:04:46',0), ('2019_11_03_00_characters.sql','DC789597F85B890E9A7901B4443DAD9CAEE2A02A','RELEASED','2019-11-03 14:13:27',0), ('2019_11_12_00_characters.sql','D4C642B4D48DAE9F56329BDE51C258323A132A91','RELEASED','2019-11-12 16:31:29',0), -('2019_11_22_00_characters.sql','95DFA71DBD75542C098CD86E9C0051C9690902F0','RELEASED','2019-11-20 15:10:12',0); +('2019_11_22_00_characters.sql','95DFA71DBD75542C098CD86E9C0051C9690902F0','RELEASED','2019-11-20 15:10:12',0), +('2019_11_30_00_characters.sql','D0678E62B651AECA60C2DD6989BF80BD999AD12B','RELEASED','2019-11-29 22:42:01',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2019_11_30_00_characters.sql b/sql/updates/characters/master/2019_11_30_00_characters.sql new file mode 100644 index 000000000..70279def1 --- /dev/null +++ b/sql/updates/characters/master/2019_11_30_00_characters.sql @@ -0,0 +1 @@ +ALTER TABLE `character_aura` ADD `castItemId` int(10) unsigned NOT NULL DEFAULT '0' AFTER `remainCharges`;