diff --git a/Source/Framework/Constants/SmartAIConst.cs b/Source/Framework/Constants/SmartAIConst.cs index 56bf62e5c..168936936 100644 --- a/Source/Framework/Constants/SmartAIConst.cs +++ b/Source/Framework/Constants/SmartAIConst.cs @@ -169,7 +169,7 @@ namespace Framework.Constants PassengerRemoved = 28, // Cooldownmin, Cooldownmax Charmed = 29, // onRemove (0 - on apply, 1 - on remove) CharmedTarget = 30, // None - SpellhitTarget = 31, // Spellid, School, Cooldownmin, Cooldownmax + SpellHitTarget = 31, // Spellid, School, Cooldownmin, Cooldownmax Damaged = 32, // Mindmg, Maxdmg, Cooldownmin, Cooldownmax DamagedTarget = 33, // Mindmg, Maxdmg, Cooldownmin, Cooldownmax Movementinform = 34, // Movementtype(Any), Pointid diff --git a/Source/Framework/Constants/Spells/SpellAuraConst.cs b/Source/Framework/Constants/Spells/SpellAuraConst.cs index 7630b30fd..8eee68dc9 100644 --- a/Source/Framework/Constants/Spells/SpellAuraConst.cs +++ b/Source/Framework/Constants/Spells/SpellAuraConst.cs @@ -442,8 +442,8 @@ namespace Framework.Constants ModMaxPower = 418, // NYI ModBaseManaPct = 419, ModBattlePetXpPct = 420, - ModAbsorbEffectsAmountPct = 421, // NYI - Unk422 = 422, + ModAbsorbEffectsDonePct = 421, // NYI + ModAbsorbEffectsTakenPct = 422, //NYI Unk423 = 423, Unk424 = 424, Unk425 = 425, diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index dce16c78d..f5fc2c116 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -32,6 +32,8 @@ namespace Framework.Constants public const int EffectAll = 255; public const float TrajectoryMissileSize = 3.0f; + + public const int MaxPowersPerSpell = 4; } @@ -2323,7 +2325,7 @@ namespace Framework.Constants UnitNearbyParty = 3, UnitNearbyAlly = 4, UnitPet = 5, - UnitEnemy = 6, + UnitTargetEnemy = 6, UnitSrcAreaEntry = 7, UnitDestAreaEntry = 8, DestHome = 9, @@ -2333,11 +2335,11 @@ namespace Framework.Constants DestDb = 17, DestCaster = 18, UnitCasterAreaParty = 20, - UnitAlly = 21, + UnitTargetAlly = 21, SrcCaster = 22, GameobjectTarget = 23, UnitConeEnemy24 = 24, - UnitAny = 25, + UnitTargetAny = 25, GameobjectItemTarget = 26, UnitMaster = 27, DestDynobjEnemy = 28, @@ -2347,9 +2349,9 @@ namespace Framework.Constants DestCasterSummon = 32, // Front Left, Doesn'T Use Radius UnitSrcAreaParty = 33, UnitDestAreaParty = 34, - UnitParty = 35, + UnitTargetParty = 35, DestCasterUnk36 = 36, - UnitLastAreaParty = 37, + UnitLastTargetAreaParty = 37, UnitNearbyEntry = 38, DestCasterFishing = 39, GameobjectNearbyEntry = 40, @@ -2365,7 +2367,7 @@ namespace Framework.Constants DestCasterLeft = 50, GameobjectSrcArea = 51, GameobjectDestArea = 52, - DestEnemy = 53, + DestTargetEnemy = 53, UnitConeEnemy54 = 54, DestCasterFrontLeap = 55, // For A Leap Spell UnitCasterAreaRaid = 56, diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 4a7b40ce8..33f132f3d 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, castItemId, castItemLevel FROM character_aura WHERE guid = ?"); + PrepareStatement(CharStatements.SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, 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"); @@ -339,8 +339,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, castItemId, castItemLevel) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, 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 (?, ?, ?, ?, ?, ?, ?, ?)"); @@ -708,7 +708,7 @@ namespace Framework.Database PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?"); PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?"); PrepareStatement(CharStatements.INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)"); - PrepareStatement(CharStatements.SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?"); + PrepareStatement(CharStatements.SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges FROM pet_aura WHERE guid = ?"); PrepareStatement(CharStatements.SEL_PET_AURA_EFFECT, "SELECT casterGuid, spell, effectMask, effectIndex, amount, baseAmount FROM pet_aura_effect WHERE guid = ?"); PrepareStatement(CharStatements.SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?"); PrepareStatement(CharStatements.SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()"); @@ -723,8 +723,8 @@ namespace Framework.Database PrepareStatement(CharStatements.INS_PET_SPELL_CHARGES, "INSERT INTO pet_spell_charges (guid, categoryId, rechargeStart, rechargeEnd) VALUES (?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_PET_SPELL_BY_SPELL, "DELETE FROM pet_spell WHERE guid = ? and spell = ?"); PrepareStatement(CharStatements.INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)"); - PrepareStatement(CharStatements.INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, maxDuration, remainTime, remainCharges) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " + "VALUES (?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND id = ?"); diff --git a/Source/Game/AI/CoreAI/CombatAI.cs b/Source/Game/AI/CoreAI/CombatAI.cs index e6b03af09..14c05a872 100644 --- a/Source/Game/AI/CoreAI/CombatAI.cs +++ b/Source/Game/AI/CoreAI/CombatAI.cs @@ -28,7 +28,7 @@ namespace Game.AI public override void InitializeAI() { for (var i = 0; i < SharedConst.MaxCreatureSpells; ++i) - if (me.m_spells[i] != 0 && Global.SpellMgr.GetSpellInfo(me.m_spells[i]) != null) + if (me.m_spells[i] != 0 && Global.SpellMgr.HasSpellInfo(me.m_spells[i], me.GetMap().GetDifficultyID())) spells.Add(me.m_spells[i]); base.InitializeAI(); @@ -42,18 +42,22 @@ namespace Game.AI public override void JustDied(Unit killer) { foreach (var id in spells) - if (AISpellInfo[id].condition == AICondition.Die) + { + AISpellInfoType info = GetAISpellInfo(id, me.GetMap().GetDifficultyID()); + if (info.condition == AICondition.Die) me.CastSpell(killer, id, true); + } } public override void EnterCombat(Unit victim) { foreach (var id in spells) { - if (AISpellInfo[id].condition == AICondition.Aggro) + AISpellInfoType info = GetAISpellInfo(id, me.GetMap().GetDifficultyID()); + if (info.condition == AICondition.Aggro) me.CastSpell(victim, id, false); - else if (AISpellInfo[id].condition == AICondition.Combat) - _events.ScheduleEvent(id, AISpellInfo[id].cooldown + RandomHelper.Rand32() % AISpellInfo[id].cooldown); + else if (info.condition == AICondition.Combat) + _events.ScheduleEvent(id, info.cooldown + RandomHelper.Rand32() % info.cooldown); } } @@ -71,10 +75,11 @@ namespace Game.AI if (spellId != 0) { DoCast(spellId); - _events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + RandomHelper.Rand32() % AISpellInfo[spellId].cooldown); + AISpellInfoType info = GetAISpellInfo(spellId, me.GetMap().GetDifficultyID()); + _events.ScheduleEvent(spellId, info.cooldown + RandomHelper.Rand32() % info.cooldown); } - - DoMeleeAttackIfReady(); + else + DoMeleeAttackIfReady(); } public override void SpellInterrupted(uint spellId, uint unTimeMs) @@ -112,8 +117,12 @@ namespace Game.AI m_attackDist = 30.0f; foreach (var id in spells) - if (AISpellInfo[id].condition == AICondition.Combat && m_attackDist > AISpellInfo[id].maxRange) - m_attackDist = AISpellInfo[id].maxRange; + { + AISpellInfoType info = GetAISpellInfo(id, me.GetMap().GetDifficultyID()); + if (info.condition == AICondition.Combat && m_attackDist > info.maxRange) + m_attackDist = info.maxRange; + } + if (m_attackDist == 30.0f) m_attackDist = SharedConst.MeleeRange; } @@ -132,12 +141,12 @@ namespace Game.AI uint count = 0; foreach (var id in spells) { - - if (AISpellInfo[id].condition == AICondition.Aggro) + AISpellInfoType info = GetAISpellInfo(id, me.GetMap().GetDifficultyID()); + if (info.condition == AICondition.Aggro) me.CastSpell(victim, id, false); - else if (AISpellInfo[id].condition == AICondition.Combat) + else if (info.condition == AICondition.Combat) { - uint cooldown = AISpellInfo[id].realCooldown; + uint cooldown = info.realCooldown; if (count == spell) { DoCast(spells[spell]); @@ -169,7 +178,8 @@ namespace Game.AI { DoCast(spellId); uint casttime = (uint)me.GetCurrentSpellCastTime(spellId); - _events.ScheduleEvent(spellId, (casttime != 0 ? casttime : 500) + AISpellInfo[spellId].realCooldown); + AISpellInfoType info = GetAISpellInfo(spellId, me.GetMap().GetDifficultyID()); + _events.ScheduleEvent(spellId, (casttime != 0 ? casttime : 500) + info.realCooldown); } } @@ -184,7 +194,7 @@ namespace Game.AI if (me.m_spells[0] == 0) Log.outError(LogFilter.ScriptsAi, "ArcherAI set for creature (entry = {0}) with spell1=0. AI will do nothing", me.GetEntry()); - var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0]); + var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0], me.GetMap().GetDifficultyID()); m_minRange = spellInfo != null ? spellInfo.GetMinRange(false) : 0; if (m_minRange == 0) @@ -234,7 +244,7 @@ namespace Game.AI if (me.m_spells[0] == 0) Log.outError(LogFilter.Server, "TurretAI set for creature (entry = {0}) with spell1=0. AI will do nothing", me.GetEntry()); - var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0]); + var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0], me.GetMap().GetDifficultyID()); m_minRange = spellInfo != null ? spellInfo.GetMinRange(false) : 0; me.m_CombatDistance = spellInfo != null ? spellInfo.GetMaxRange(false) : 0; me.m_SightDistance = me.m_CombatDistance; diff --git a/Source/Game/AI/CoreAI/CreatureAI.cs b/Source/Game/AI/CoreAI/CreatureAI.cs index 55d95a076..3f6c83912 100644 --- a/Source/Game/AI/CoreAI/CreatureAI.cs +++ b/Source/Game/AI/CoreAI/CreatureAI.cs @@ -492,6 +492,9 @@ namespace Game.AI public uint cooldown; public uint realCooldown; public float maxRange; + + public byte Targets; // set of enum SelectTarget + public byte Effects; // set of enum SelectEffect } public enum AITarget diff --git a/Source/Game/AI/CoreAI/PetAI.cs b/Source/Game/AI/CoreAI/PetAI.cs index 000c09d00..ee2356005 100644 --- a/Source/Game/AI/CoreAI/PetAI.cs +++ b/Source/Game/AI/CoreAI/PetAI.cs @@ -138,7 +138,7 @@ namespace Game.AI if (spellID == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellID, me.GetMap().GetDifficultyID()); if (spellInfo == null) continue; diff --git a/Source/Game/AI/CoreAI/TotemAI.cs b/Source/Game/AI/CoreAI/TotemAI.cs index 787515ecf..6755f8b24 100644 --- a/Source/Game/AI/CoreAI/TotemAI.cs +++ b/Source/Game/AI/CoreAI/TotemAI.cs @@ -42,7 +42,7 @@ namespace Game.AI return; // Search spell - var spellInfo = Global.SpellMgr.GetSpellInfo(me.ToTotem().GetSpell()); + var spellInfo = Global.SpellMgr.GetSpellInfo(me.ToTotem().GetSpell(), me.GetMap().GetDifficultyID()); if (spellInfo == null) return; diff --git a/Source/Game/AI/CoreAI/UnitAI.cs b/Source/Game/AI/CoreAI/UnitAI.cs index 61efe9037..8553846db 100644 --- a/Source/Game/AI/CoreAI/UnitAI.cs +++ b/Source/Game/AI/CoreAI/UnitAI.cs @@ -31,7 +31,7 @@ namespace Game.AI { me = _unit; } - + public virtual void AttackStart(Unit victim) { if (victim != null && me.Attack(victim, true)) @@ -99,7 +99,7 @@ namespace Game.AI if (me.HasUnitState(UnitState.Casting) || !me.IsAttackReady()) return true; - var spellInfo = Global.SpellMgr.GetSpellInfo(spell); + var spellInfo = Global.SpellMgr.GetSpellInfo(spell, me.GetMap().GetDifficultyID()); if (spellInfo != null) { if (me.IsWithinCombatRange(me.GetVictim(), spellInfo.GetMaxRange(false))) @@ -156,18 +156,18 @@ namespace Game.AI { case SelectAggroTarget.Nearest: case SelectAggroTarget.TopAggro: - { - return targetList.First(); - } + { + return targetList.First(); + } case SelectAggroTarget.Farthest: case SelectAggroTarget.BottomAggro: - { - return targetList.Last(); - } + { + return targetList.Last(); + } case SelectAggroTarget.Random: - { - return targetList.SelectRandom(); - } + { + return targetList.SelectRandom(); + } default: break; } @@ -179,7 +179,7 @@ namespace Game.AI { return SelectTargetList(new DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType); } - + // Select the targets satifying the predicate. // predicate shall extend std.unary_function public List SelectTargetList(ISelector selector, uint maxTargets, SelectAggroTarget targetType) @@ -215,7 +215,8 @@ namespace Game.AI { Unit target = null; - switch (AISpellInfo[spellId].target) + AISpellInfoType info = GetAISpellInfo(spellId, me.GetMap().GetDifficultyID()); + switch (info.target) { default: case AITarget.Self: @@ -226,7 +227,7 @@ namespace Game.AI break; case AITarget.Enemy: { - var spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID()); if (spellInfo != null) { bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); @@ -240,7 +241,7 @@ namespace Game.AI break; case AITarget.Debuff: { - var spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + var spellInfo = Global.SpellMgr.GetSpellInfo(spellId, me.GetMap().GetDifficultyID()); if (spellInfo != null) { bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); @@ -289,12 +290,11 @@ namespace Game.AI public static void FillAISpellInfo() { - var spellStorage = Global.SpellMgr.GetSpellInfoStorage(); - AISpellInfo = new AISpellInfoType[spellStorage.Keys.Max() + 1]; + //AISpellInfo = new AISpellInfoType[spellStorage.Keys.Max() + 1]; - foreach (var spellInfo in spellStorage.Values) + Global.SpellMgr.ForEachSpellInfo(spellInfo => { - AISpellInfoType AIInfo = AISpellInfo[spellInfo.Id]; + AISpellInfoType AIInfo = new AISpellInfoType(); if (spellInfo.HasAttribute(SpellAttr0.CastableWhileDead)) AIInfo.condition = AICondition.Die; else if (spellInfo.IsPassive() || spellInfo.GetDuration() == -1) @@ -312,14 +312,14 @@ namespace Game.AI } else { - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; var targetType = effect.TargetA.GetTarget(); - if (targetType == Targets.UnitEnemy || targetType == Targets.DestEnemy) + if (targetType == Targets.UnitTargetEnemy || targetType == Targets.DestTargetEnemy) { if (AIInfo.target < AITarget.Victim) AIInfo.target = AITarget.Victim; @@ -332,7 +332,7 @@ namespace Game.AI if (effect.Effect == SpellEffectName.ApplyAura) { - if (targetType == Targets.UnitEnemy) + if (targetType == Targets.UnitTargetEnemy) { if (AIInfo.target < AITarget.Debuff) AIInfo.target = AITarget.Debuff; @@ -347,7 +347,82 @@ namespace Game.AI } AIInfo.realCooldown = spellInfo.RecoveryTime + spellInfo.StartRecoveryTime; AIInfo.maxRange = spellInfo.GetMaxRange(false) * 3 / 4; - } + + AIInfo.Effects = 0; + AIInfo.Targets = 0; + + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) + { + if (effect == null) + continue; + + // Spell targets self. + if (effect.TargetA.GetTarget() == Targets.UnitCaster) + AIInfo.Targets |= 1 << ((int)SelectTargetType.Self - 1); + + // Spell targets a single enemy. + if (effect.TargetA.GetTarget() == Targets.UnitTargetEnemy || + effect.TargetA.GetTarget() == Targets.DestTargetEnemy) + AIInfo.Targets |= 1 << ((int)SelectTargetType.SingleEnemy - 1); + + // Spell targets AoE at enemy. + if (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || + effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || + effect.TargetA.GetTarget() == Targets.SrcCaster || + effect.TargetA.GetTarget() == Targets.DestDynobjEnemy) + AIInfo.Targets |= 1 << ((int)SelectTargetType.AoeEnemy - 1); + + // Spell targets an enemy. + if (effect.TargetA.GetTarget() == Targets.UnitTargetEnemy || + effect.TargetA.GetTarget() == Targets.DestTargetEnemy || + effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || + effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || + effect.TargetA.GetTarget() == Targets.SrcCaster || + effect.TargetA.GetTarget() == Targets.DestDynobjEnemy) + AIInfo.Targets |= 1 << ((int)SelectTargetType.AnyEnemy - 1); + + // Spell targets a single friend (or self). + if (effect.TargetA.GetTarget() == Targets.UnitCaster || + effect.TargetA.GetTarget() == Targets.UnitTargetAlly || + effect.TargetA.GetTarget() == Targets.UnitTargetParty) + AIInfo.Targets |= 1 << ((int)SelectTargetType.SingleFriend - 1); + + // Spell targets AoE friends. + if (effect.TargetA.GetTarget() == Targets.UnitCasterAreaParty || + effect.TargetA.GetTarget() == Targets.UnitLastTargetAreaParty || + effect.TargetA.GetTarget() == Targets.SrcCaster) + AIInfo.Targets |= 1 << ((int)SelectTargetType.AoeFriend - 1); + + // Spell targets any friend (or self). + if (effect.TargetA.GetTarget() == Targets.UnitCaster || + effect.TargetA.GetTarget() == Targets.UnitTargetAlly || + effect.TargetA.GetTarget() == Targets.UnitTargetParty || + effect.TargetA.GetTarget() == Targets.UnitCasterAreaParty || + effect.TargetA.GetTarget() == Targets.UnitLastTargetAreaParty || + effect.TargetA.GetTarget() == Targets.SrcCaster) + AIInfo.Targets |= 1 << ((int)SelectTargetType.AnyFriend - 1); + + // Make sure that this spell includes a damage effect. + if (effect.Effect == SpellEffectName.SchoolDamage || + effect.Effect == SpellEffectName.Instakill || + effect.Effect == SpellEffectName.EnvironmentalDamage || + effect.Effect == SpellEffectName.HealthLeech) + AIInfo.Effects |= 1 << ((int)SelectEffect.Damage - 1); + + // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal). + if (effect.Effect == SpellEffectName.Heal || + effect.Effect == SpellEffectName.HealMaxHealth || + effect.Effect == SpellEffectName.HealMechanical || + (effect.Effect == SpellEffectName.ApplyAura && effect.ApplyAuraName == AuraType.PeriodicHeal)) + AIInfo.Effects |= 1 << ((int)SelectEffect.Healing - 1); + + // Make sure that this spell applies an aura. + if (effect.Effect == SpellEffectName.ApplyAura) + AIInfo.Effects |= 1 << ((int)SelectEffect.Aura - 1); + } + + AISpellInfo[(spellInfo.Id, spellInfo.Difficulty)] = AIInfo; + }); } public virtual bool CanAIAttack(Unit victim) { return true; } @@ -411,7 +486,12 @@ namespace Game.AI // Called when the dialog status between a player and the creature is requested. public virtual QuestGiverStatus GetDialogStatus(Player player) { return QuestGiverStatus.ScriptedNoStatus; } - public static AISpellInfoType[] AISpellInfo; + public AISpellInfoType GetAISpellInfo(uint spellId, Difficulty difficulty) + { + return AISpellInfo.LookupByKey((spellId, difficulty)); + } + + public static Dictionary<(uint id, Difficulty difficulty), AISpellInfoType> AISpellInfo = new Dictionary<(uint id, Difficulty difficulty), AISpellInfoType>(); protected Unit me { get; private set; } } @@ -493,7 +573,7 @@ namespace Game.AI public SpellTargetSelector(Unit caster, uint spellId) { _caster = caster; - _spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + _spellInfo = Global.SpellMgr.GetSpellInfo(spellId, caster.GetMap().GetDifficultyID()); Cypher.Assert(_spellInfo != null); } diff --git a/Source/Game/AI/PlayerAI/PlayerAI.cs b/Source/Game/AI/PlayerAI/PlayerAI.cs index 522a43811..dbb833a81 100644 --- a/Source/Game/AI/PlayerAI/PlayerAI.cs +++ b/Source/Game/AI/PlayerAI/PlayerAI.cs @@ -487,7 +487,7 @@ namespace Game.AI if (knownRank == 0) return null; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(knownRank); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(knownRank, me.GetMap().GetDifficultyID()); if (spellInfo == null) return null; diff --git a/Source/Game/AI/ScriptedAI/ScriptedAI.cs b/Source/Game/AI/ScriptedAI/ScriptedAI.cs index 9f7baf9d8..4ad76ae80 100644 --- a/Source/Game/AI/ScriptedAI/ScriptedAI.cs +++ b/Source/Game/AI/ScriptedAI/ScriptedAI.cs @@ -136,7 +136,8 @@ namespace Game.AI //Check if each spell is viable(set it to null if not) for (uint i = 0; i < SharedConst.MaxCreatureSpells; i++) { - SpellInfo tempSpell = Global.SpellMgr.GetSpellInfo(me.m_spells[i]); + SpellInfo tempSpell = Global.SpellMgr.GetSpellInfo(me.m_spells[i], me.GetMap().GetDifficultyID()); + AISpellInfoType aiSpell = GetAISpellInfo(me.m_spells[i], me.GetMap().GetDifficultyID()); //This spell doesn't exist if (tempSpell == null) @@ -144,11 +145,11 @@ namespace Game.AI // Targets and Effects checked first as most used restrictions //Check the spell targets if specified - if (targets != 0 && !Convert.ToBoolean(Global.ScriptMgr.spellSummaryStorage[me.m_spells[i]].Targets & (1 << ((int)targets - 1)))) + if (targets != 0 && !Convert.ToBoolean(aiSpell.Targets & (1 << ((int)targets - 1)))) continue; //Check the type of spell if we are looking for a specific spell type - if (effect != 0 && !Convert.ToBoolean(Global.ScriptMgr.spellSummaryStorage[me.m_spells[i]].Effects & (1 << ((int)effect - 1)))) + if (effect != 0 && !Convert.ToBoolean(aiSpell.Effects & (1 << ((int)effect - 1)))) continue; //Check for school if specified diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index 637a798d9..b2e33cc0a 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -656,7 +656,7 @@ namespace Game.AI public override void SpellHitTarget(Unit target, SpellInfo spell) { - GetScript().ProcessEventsFor(SmartEvents.SpellhitTarget, target, 0, 0, false, spell); + GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target, 0, 0, false, spell); } public override void DamageTaken(Unit attacker, ref uint damage) diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index f2936c1dc..0644c149c 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -102,7 +102,7 @@ namespace Game.AI } case SmartScriptType.Spell: { - if (!Global.SpellMgr.HasSpellInfo((uint)temp.entryOrGuid)) + if (!Global.SpellMgr.HasSpellInfo((uint)temp.entryOrGuid, Difficulty.None)) { Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAIFromDB: Scene id ({0}) does not exist, skipped loading.", temp.entryOrGuid); continue; @@ -505,10 +505,10 @@ namespace Game.AI return false; break; case SmartEvents.SpellHit: - case SmartEvents.SpellhitTarget: + case SmartEvents.SpellHitTarget: if (e.Event.spellHit.spell != 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Event.spellHit.spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Event.spellHit.spell, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Spell entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.Event.spellHit.spell); @@ -571,6 +571,15 @@ namespace Game.AI return false; break; case SmartEvents.VictimCasting: + if (e.Event.targetCasting.spellId > 0 && !Global.SpellMgr.HasSpellInfo(e.Event.targetCasting.spellId, Difficulty.None)) + { + Log.outError(LogFilter.Sql, $"SmartAIMgr: Entry {e.entryOrGuid} SourceType {e.GetScriptType()} Event {e.event_id} Action {e.GetActionType()} uses non-existent Spell entry {e.Event.spellHit.spell}, skipped."); + return false; + } + + if (!IsMinMaxValid(e, e.Event.minMax.repeatMin, e.Event.minMax.repeatMax)) + return false; + break; case SmartEvents.PassengerBoarded: case SmartEvents.PassengerRemoved: if (!IsMinMaxValid(e, e.Event.minMax.repeatMin, e.Event.minMax.repeatMax)) @@ -912,8 +921,8 @@ namespace Game.AI if (!IsSpellValid(e, e.Action.cast.spell)) return false; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Action.cast.spell); - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Action.cast.spell, Difficulty.None); + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && (effect.IsEffect(SpellEffectName.KillCredit) || effect.IsEffect(SpellEffectName.KillCredit2))) { @@ -1437,7 +1446,7 @@ namespace Game.AI } bool IsSpellValid(SmartScriptHolder e, uint entry) { - if (!Global.SpellMgr.HasSpellInfo(entry)) + if (!Global.SpellMgr.HasSpellInfo(entry, Difficulty.None)) { Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Entry {0} SourceType {1} Event {2} Action {3} uses non-existent Spell entry {4}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry); return false; @@ -1599,7 +1608,7 @@ namespace Game.AI { SmartEvents.PassengerRemoved, SmartScriptTypeMaskId.Creature }, { SmartEvents.Charmed, SmartScriptTypeMaskId.Creature }, { SmartEvents.CharmedTarget, SmartScriptTypeMaskId.Creature }, - { SmartEvents.SpellhitTarget, SmartScriptTypeMaskId.Creature }, + { SmartEvents.SpellHitTarget, SmartScriptTypeMaskId.Creature }, { SmartEvents.Damaged, SmartScriptTypeMaskId.Creature }, { SmartEvents.DamagedTarget, SmartScriptTypeMaskId.Creature }, { SmartEvents.Movementinform, SmartScriptTypeMaskId.Creature }, diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index 8857d3686..bf2ea2df5 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -501,7 +501,7 @@ namespace Game.AI // unless target is outside spell range, out of mana, or LOS. bool _allowMove = false; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Action.cast.spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(e.Action.cast.spell, me.GetMap().GetDifficultyID()); var costs = spellInfo.CalcPowerCost(me, spellInfo.GetSchoolMask()); bool hasPower = true; foreach (var cost in costs) @@ -3438,7 +3438,7 @@ namespace Game.AI RecalcTimer(e, e.Event.kill.cooldownMin, e.Event.kill.cooldownMax); break; } - case SmartEvents.SpellhitTarget: + case SmartEvents.SpellHitTarget: case SmartEvents.SpellHit: { if (spell == null) diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index 2f6bf9ca5..fc6f040bd 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -3046,14 +3046,14 @@ namespace Game.Achievements case CriteriaDataType.SAura: case CriteriaDataType.TAura: { - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(Aura.SpellId); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(Aura.SpellId, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Sql, "Table `criteria_data` (Entry: {0} Type: {1}) for data type {2} has wrong spell id in value1 ({3}), ignored.", criteria.Id, criteria.Entry.Type, DataType, Aura.SpellId); return false; } - SpellEffectInfo effect = spellEntry.GetEffect(Difficulty.None, Aura.EffectIndex); + SpellEffectInfo effect = spellEntry.GetEffect(Aura.EffectIndex); if (effect == null) { Log.outError(LogFilter.Sql, "Table `criteria_data` (Entry: {0} Type: {1}) for data type {2} has wrong spell effect index in value2 ({3}), ignored.", diff --git a/Source/Game/Chat/Commands/CastCommands.cs b/Source/Game/Chat/Commands/CastCommands.cs index 2aa55d887..d580fbed6 100644 --- a/Source/Game/Chat/Commands/CastCommands.cs +++ b/Source/Game/Chat/Commands/CastCommands.cs @@ -228,7 +228,7 @@ namespace Game.Chat static bool CheckSpellExistsAndIsValid(CommandHandler handler, uint spellId) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) { handler.SendSysMessage(CypherStrings.CommandNospellfound); diff --git a/Source/Game/Chat/Commands/DisableCommands.cs b/Source/Game/Chat/Commands/DisableCommands.cs index 1f5af4b47..443519b18 100644 --- a/Source/Game/Chat/Commands/DisableCommands.cs +++ b/Source/Game/Chat/Commands/DisableCommands.cs @@ -45,7 +45,7 @@ namespace Game.Chat.Commands { case DisableType.Spell: { - if (!Global.SpellMgr.HasSpellInfo(entry)) + if (!Global.SpellMgr.HasSpellInfo(entry, Difficulty.None)) { handler.SendSysMessage(CypherStrings.CommandNospellfound); return false; diff --git a/Source/Game/Chat/Commands/LearnCommands.cs b/Source/Game/Chat/Commands/LearnCommands.cs index 1c8cde747..38e5f69a4 100644 --- a/Source/Game/Chat/Commands/LearnCommands.cs +++ b/Source/Game/Chat/Commands/LearnCommands.cs @@ -41,13 +41,13 @@ namespace Game.Chat.Commands // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint spell = handler.ExtractSpellIdFromLink(args); - if (spell == 0 || !Global.SpellMgr.HasSpellInfo(spell)) + if (spell == 0 || !Global.SpellMgr.HasSpellInfo(spell, Difficulty.None)) return false; string all = args.NextString(); bool allRanks = !string.IsNullOrEmpty(all) && all == "all"; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell, Difficulty.None); if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer())) { handler.SendSysMessage(CypherStrings.CommandSpellBroken, spell); @@ -78,15 +78,13 @@ namespace Game.Chat.Commands [Command("gm", RBACPermissions.CommandLearnAllGm)] static bool HandleLearnAllGMCommand(StringArguments args, CommandHandler handler) { - foreach (var spellInfo in Global.SpellMgr.GetSpellInfoStorage().Values) + foreach (var skillSpell in Global.SpellMgr.GetSkillLineAbilityMapBounds((uint)SkillType.Internal)) { + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(skillSpell.Spell, Difficulty.None); if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer(), false)) continue; - if (!spellInfo.IsAbilityOfSkillType(SkillType.Internal)) - continue; - - handler.GetSession().GetPlayer().LearnSpell(spellInfo.Id, false); + handler.GetSession().GetPlayer().LearnSpell(skillSpell.Spell, false); } handler.SendSysMessage(CypherStrings.LearningGmSkills); @@ -228,7 +226,7 @@ namespace Game.Chat.Commands if (skillLine.ClassMask != 0 && (skillLine.ClassMask & classmask) == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(skillLine.Spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(skillLine.Spell, Difficulty.None); if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, player, false)) continue; @@ -257,7 +255,7 @@ namespace Game.Chat.Commands foreach (var entry in CliDB.SkillLineAbilityStorage.Values) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(entry.Spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(entry.Spell, Difficulty.None); if (spellInfo == null) continue; @@ -295,7 +293,7 @@ namespace Game.Chat.Commands if (playerClass != talentInfo.ClassID) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer(), false)) continue; diff --git a/Source/Game/Chat/Commands/LookupCommands.cs b/Source/Game/Chat/Commands/LookupCommands.cs index 9d9cbec04..3c89068ec 100644 --- a/Source/Game/Chat/Commands/LookupCommands.cs +++ b/Source/Game/Chat/Commands/LookupCommands.cs @@ -1065,84 +1065,87 @@ namespace Game.Chat bool found = false; uint count = 0; - // Search in Spell.dbc - foreach (var spellInfo in Global.SpellMgr.GetSpellInfoStorage().Values) + // Search in SpellName.dbc + foreach (SpellNameRecord spellName in CliDB.SpellNameStorage.Values) { - LocaleConstant locale = handler.GetSessionDbcLocale(); - string name = spellInfo.SpellName[locale]; - if (name.IsEmpty()) - continue; - - if (!name.Like(namePart)) + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellName.Id, Difficulty.None); + if (spellInfo != null) { - locale = 0; - for (; locale < LocaleConstant.Total; ++locale) + LocaleConstant locale = handler.GetSessionDbcLocale(); + string name = spellInfo.SpellName[locale]; + if (name.IsEmpty()) + continue; + + if (!name.Like(namePart)) { - if (locale == handler.GetSessionDbcLocale()) - continue; + locale = 0; + for (; locale < LocaleConstant.Total; ++locale) + { + if (locale == handler.GetSessionDbcLocale()) + continue; - name = spellInfo.SpellName[locale]; - if (name.IsEmpty()) - continue; + name = spellInfo.SpellName[locale]; + if (name.IsEmpty()) + continue; - if (name.Like(namePart)) - break; - } - } - - if (locale < LocaleConstant.Total) - { - if (maxlookup != 0 && count++ == maxlookup) - { - handler.SendSysMessage(CypherStrings.CommandLookupMaxResults, maxlookup); - return true; + if (name.Like(namePart)) + break; + } } - bool known = target && target.HasSpell(spellInfo.Id); - SpellEffectInfo effect = spellInfo.GetEffect(0); - bool learn = (effect.Effect == SpellEffectName.LearnSpell); + if (locale < LocaleConstant.Total) + { + if (maxlookup != 0 && count++ == maxlookup) + { + handler.SendSysMessage(CypherStrings.CommandLookupMaxResults, maxlookup); + return true; + } - SpellInfo learnSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + bool known = target && target.HasSpell(spellInfo.Id); + SpellEffectInfo effect = spellInfo.GetEffect(0); + bool learn = (effect.Effect == SpellEffectName.LearnSpell); - bool talent = spellInfo.HasAttribute(SpellCustomAttributes.IsTalent); - bool passive = spellInfo.IsPassive(); - bool active = target && target.HasAura(spellInfo.Id); + SpellInfo learnSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, spellInfo.Difficulty); - // unit32 used to prevent interpreting public byte as char at output - // find rank of learned spell for learning spell, or talent rank - uint rank = learn && learnSpellInfo != null ? learnSpellInfo.GetRank() : spellInfo.GetRank(); + bool talent = spellInfo.HasAttribute(SpellCustomAttributes.IsTalent); + bool passive = spellInfo.IsPassive(); + bool active = target && target.HasAura(spellInfo.Id); - // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format - StringBuilder ss = new StringBuilder(); - if (handler.GetSession() != null) - ss.Append(spellInfo.Id + " - |cffffffff|Hspell:" + spellInfo.Id + "|h[" + name); - else - ss.Append(spellInfo.Id + " - " + name); + // unit32 used to prevent interpreting public byte as char at output + // find rank of learned spell for learning spell, or talent rank + uint rank = learn && learnSpellInfo != null ? learnSpellInfo.GetRank() : spellInfo.GetRank(); - // include rank in link name - if (rank != 0) - ss.Append(handler.GetCypherString(CypherStrings.SpellRank) + rank); + // send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format + StringBuilder ss = new StringBuilder(); + if (handler.GetSession() != null) + ss.Append(spellInfo.Id + " - |cffffffff|Hspell:" + spellInfo.Id + "|h[" + name); + else + ss.Append(spellInfo.Id + " - " + name); - if (handler.GetSession() != null) - ss.Append("]|h|r"); + // include rank in link name + if (rank != 0) + ss.Append(handler.GetCypherString(CypherStrings.SpellRank) + rank); - if (talent) - ss.Append(handler.GetCypherString(CypherStrings.Talent)); - if (passive) - ss.Append(handler.GetCypherString(CypherStrings.Passive)); - if (learn) - ss.Append(handler.GetCypherString(CypherStrings.Learn)); - if (known) - ss.Append(handler.GetCypherString(CypherStrings.Known)); - if (active) - ss.Append(handler.GetCypherString(CypherStrings.Active)); + if (handler.GetSession() != null) + ss.Append("]|h|r"); - handler.SendSysMessage(ss.ToString()); + if (talent) + ss.Append(handler.GetCypherString(CypherStrings.Talent)); + if (passive) + ss.Append(handler.GetCypherString(CypherStrings.Passive)); + if (learn) + ss.Append(handler.GetCypherString(CypherStrings.Learn)); + if (known) + ss.Append(handler.GetCypherString(CypherStrings.Known)); + if (active) + ss.Append(handler.GetCypherString(CypherStrings.Active)); - if (!found) - found = true; + handler.SendSysMessage(ss.ToString()); + + if (!found) + found = true; + } } - } if (!found) handler.SendSysMessage(CypherStrings.CommandNospellfound); @@ -1161,7 +1164,7 @@ namespace Game.Chat uint id = args.NextUInt32(); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(id, Difficulty.None); if (spellInfo != null) { LocaleConstant locale = handler.GetSessionDbcLocale(); @@ -1176,7 +1179,7 @@ namespace Game.Chat SpellEffectInfo effect = spellInfo.GetEffect(0); bool learn = (effect.Effect == SpellEffectName.LearnSpell); - SpellInfo learnSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo learnSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty.None); bool talent = spellInfo.HasAttribute(SpellCustomAttributes.IsTalent); bool passive = spellInfo.IsPassive(); diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index 04514456d..938c18035 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -1009,7 +1009,7 @@ namespace Game.Chat if (player.IsInFlight() || player.IsInCombat()) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SPELL_UNSTUCK_ID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SPELL_UNSTUCK_ID, Difficulty.None); if (spellInfo == null) return false; @@ -2065,11 +2065,11 @@ namespace Game.Chat if (spellid == 0) return false; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid, attacker.GetMap().GetDifficultyID()); if (spellInfo == null) return false; - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(attacker, target, spellid, spellInfo.GetSpellXSpellVisualId(attacker), spellInfo.SchoolMask); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(attacker, target, spellInfo, spellInfo.GetSpellXSpellVisualId(attacker), spellInfo.SchoolMask); damageInfo.damage = damage_; attacker.DealDamageMods(damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); target.DealSpellDamage(damageInfo, true); diff --git a/Source/Game/Chat/Commands/PetCommands.cs b/Source/Game/Chat/Commands/PetCommands.cs index f0df6c20d..2a09af61c 100644 --- a/Source/Game/Chat/Commands/PetCommands.cs +++ b/Source/Game/Chat/Commands/PetCommands.cs @@ -107,7 +107,7 @@ namespace Game.Chat } uint spellId = handler.ExtractSpellIdFromLink(args); - if (spellId == 0 || !Global.SpellMgr.HasSpellInfo(spellId)) + if (spellId == 0 || !Global.SpellMgr.HasSpellInfo(spellId, Difficulty.None)) return false; // Check if pet already has it @@ -118,7 +118,7 @@ namespace Game.Chat } // Check if spell is valid - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo)) { handler.SendSysMessage(CypherStrings.CommandSpellBroken, spellId); diff --git a/Source/Game/Chat/Commands/SpellCommands.cs b/Source/Game/Chat/Commands/SpellCommands.cs index 06d4798c9..beb25197d 100644 --- a/Source/Game/Chat/Commands/SpellCommands.cs +++ b/Source/Game/Chat/Commands/SpellCommands.cs @@ -57,7 +57,7 @@ namespace Game.Chat if (spellIid == 0) return false; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellIid); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellIid, target.GetMap().GetDifficultyID()); if (spellInfo == null) { handler.SendSysMessage(CypherStrings.UnknownSpell, owner == handler.GetSession().GetPlayer() ? handler.GetCypherString(CypherStrings.You) : nameLink); @@ -72,7 +72,7 @@ namespace Game.Chat } [CommandNonGroup("aura", RBACPermissions.CommandAura)] - static bool Auracommand(StringArguments args, CommandHandler handler) + static bool HandleAuraCommand(StringArguments args, CommandHandler handler) { Unit target = handler.GetSelectedUnit(); if (!target) @@ -85,11 +85,11 @@ namespace Game.Chat // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form uint spellId = handler.ExtractSpellIdFromLink(args); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, target.GetMap().GetDifficultyID()); if (spellInfo != null) { ObjectGuid castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, target.GetMapId(), spellId, target.GetMap().GenerateLowGuid(HighGuid.Cast)); - Aura.TryRefreshStackOrCreate(spellInfo, castId, SpellConst.MaxEffectMask, target, target); + Aura.TryRefreshStackOrCreate(spellInfo, castId, SpellConst.MaxEffectMask, target, target, target.GetMap().GetDifficultyID()); } return true; diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index 9345ff1b3..2cd600d08 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -275,7 +275,7 @@ namespace Game.Combat threat *= threatEntry.pctMod; // Energize is not affected by Mods - foreach (SpellEffectInfo effect in threatSpell.GetEffectsForDifficulty(hatedUnit.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in threatSpell.GetEffects()) if (effect != null && (effect.Effect == SpellEffectName.Energize || effect.ApplyAuraName == AuraType.PeriodicEnergize)) return threat; diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 3db7878bc..faa6a7e3c 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -576,101 +576,103 @@ namespace Game bool AddToSpellImplicitTargetConditions(Condition cond) { - uint conditionEffMask = cond.SourceGroup; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)cond.SourceEntry); - Cypher.Assert(spellInfo != null); - List sharedMasks = new List(); - for (byte i = 0; i < SpellConst.MaxEffects; ++i) + Global.SpellMgr.ForEachSpellInfoDifficulty((uint)cond.SourceEntry, spellInfo => { - SpellEffectInfo effect = spellInfo.GetEffect(i); - if (effect == null) - continue; - - // check if effect is already a part of some shared mask - bool found = false; - foreach (var value in sharedMasks) + uint conditionEffMask = cond.SourceGroup; + List sharedMasks = new List(); + for (byte i = 0; i < SpellConst.MaxEffects; ++i) { - if (((1 << i) & value) != 0) - { - found = true; - break; - } - } - if (found) - continue; - - // build new shared mask with found effect - uint sharedMask = (uint)(1 << i); - List cmp = effect.ImplicitTargetConditions; - for (byte effIndex = (byte)(i + 1); effIndex < SpellConst.MaxEffects; ++effIndex) - { - SpellEffectInfo inner = spellInfo.GetEffect(effIndex); - if (inner == null) - continue; - if (inner.ImplicitTargetConditions == cmp) - sharedMask |= (uint)(1 << effIndex); - } - sharedMasks.Add(sharedMask); - } - - foreach (var value in sharedMasks) - { - // some effect indexes should have same data - uint commonMask = (value & conditionEffMask); - if (commonMask != 0) - { - byte firstEffIndex = 0; - for (; firstEffIndex < SpellConst.MaxEffects; ++firstEffIndex) - if (((1 << firstEffIndex) & value) != 0) - break; - - if (firstEffIndex >= SpellConst.MaxEffects) - return false; - - SpellEffectInfo effect = spellInfo.GetEffect(firstEffIndex); + SpellEffectInfo effect = spellInfo.GetEffect(i); if (effect == null) continue; - // get shared data - List sharedList = effect.ImplicitTargetConditions; - - // there's already data entry for that sharedMask - if (sharedList != null) + // check if effect is already a part of some shared mask + bool found = false; + foreach (var value in sharedMasks) { - // we have overlapping masks in db - if (conditionEffMask != value) + if (((1 << i) & value) != 0) { - Log.outError(LogFilter.Sql, "{0} in `condition` table, has incorrect SourceGroup {1} (spell effectMask) set - " + - "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond.ToString(), cond.SourceGroup); - return false; + found = true; + break; } } - // no data for shared mask, we can create new submask - else - { - // add new list, create new shared mask - sharedList = new List(); - bool assigned = false; - for (byte i = firstEffIndex; i < SpellConst.MaxEffects; ++i) - { - SpellEffectInfo eff = spellInfo.GetEffect(i); - if (eff == null) - continue; + if (found) + continue; - if (((1 << i) & commonMask) != 0) + // build new shared mask with found effect + uint sharedMask = (uint)(1 << i); + List cmp = effect.ImplicitTargetConditions; + for (byte effIndex = (byte)(i + 1); effIndex < SpellConst.MaxEffects; ++effIndex) + { + SpellEffectInfo inner = spellInfo.GetEffect(effIndex); + if (inner == null) + continue; + + if (inner.ImplicitTargetConditions == cmp) + sharedMask |= (uint)(1 << effIndex); + } + sharedMasks.Add(sharedMask); + } + + foreach (var value in sharedMasks) + { + // some effect indexes should have same data + uint commonMask = (value & conditionEffMask); + if (commonMask != 0) + { + byte firstEffIndex = 0; + for (; firstEffIndex < SpellConst.MaxEffects; ++firstEffIndex) + if (((1 << firstEffIndex) & value) != 0) + break; + + if (firstEffIndex >= SpellConst.MaxEffects) + return; + + SpellEffectInfo effect = spellInfo.GetEffect(firstEffIndex); + if (effect == null) + continue; + + // get shared data + List sharedList = effect.ImplicitTargetConditions; + + // there's already data entry for that sharedMask + if (sharedList != null) + { + // we have overlapping masks in db + if (conditionEffMask != value) { - eff.ImplicitTargetConditions = sharedList; - assigned = true; + Log.outError(LogFilter.Sql, "{0} in `condition` table, has incorrect SourceGroup {1} (spell effectMask) set - " + + "effect masks are overlapping (all SourceGroup values having given bit set must be equal) - ignoring.", cond.ToString(), cond.SourceGroup); + return; } } + // no data for shared mask, we can create new submask + else + { + // add new list, create new shared mask + sharedList = new List(); + bool assigned = false; + for (byte i = firstEffIndex; i < SpellConst.MaxEffects; ++i) + { + SpellEffectInfo eff = spellInfo.GetEffect(i); + if (eff == null) + continue; - if (!assigned) - break; + if (((1 << i) & commonMask) != 0) + { + eff.ImplicitTargetConditions = sharedList; + assigned = true; + } + } + + if (!assigned) + break; + } + sharedList.Add(cond); + break; } - sharedList.Add(cond); - break; } - } + }); return true; } @@ -929,7 +931,7 @@ namespace Game } case ConditionSourceType.SpellImplicitTarget: { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)cond.SourceEntry); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)cond.SourceEntry, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "{0} SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond.ToString()); @@ -949,7 +951,7 @@ namespace Game if (((1 << i) & cond.SourceGroup) == 0) continue; - SpellEffectInfo effect = spellInfo.GetEffect(Difficulty.None, i); + SpellEffectInfo effect = spellInfo.GetEffect(i); if (effect == null) continue; @@ -998,7 +1000,7 @@ namespace Game case ConditionSourceType.Spell: case ConditionSourceType.SpellProc: { - SpellInfo spellProto = Global.SpellMgr.GetSpellInfo((uint)cond.SourceEntry); + SpellInfo spellProto = Global.SpellMgr.GetSpellInfo((uint)cond.SourceEntry, Difficulty.None); if (spellProto == null) { Log.outError(LogFilter.Sql, "{0} SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond.ToString()); @@ -1020,7 +1022,7 @@ namespace Game return false; } - if (!Global.SpellMgr.HasSpellInfo((uint)cond.SourceEntry)) + if (!Global.SpellMgr.HasSpellInfo((uint)cond.SourceEntry, Difficulty.None)) { Log.outError(LogFilter.Sql, "{0} SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond.ToString()); return false; @@ -1033,7 +1035,7 @@ namespace Game return false; } - if (!Global.SpellMgr.HasSpellInfo((uint)cond.SourceEntry)) + if (!Global.SpellMgr.HasSpellInfo((uint)cond.SourceEntry, Difficulty.None)) { Log.outError(LogFilter.Sql, "{0} SourceEntry in `condition` table does not exist in `spell.dbc`, ignoring.", cond.ToString()); return false; @@ -1093,7 +1095,7 @@ namespace Game { case ConditionTypes.Aura: { - if (!Global.SpellMgr.HasSpellInfo(cond.ConditionValue1)) + if (!Global.SpellMgr.HasSpellInfo(cond.ConditionValue1, Difficulty.None)) { Log.outError(LogFilter.Sql, "{0} has non existing spell (Id: {1}), skipped", cond.ToString(), cond.ConditionValue1); return false; @@ -1268,7 +1270,7 @@ namespace Game } case ConditionTypes.Spell: { - if (!Global.SpellMgr.HasSpellInfo(cond.ConditionValue1)) + if (!Global.SpellMgr.HasSpellInfo(cond.ConditionValue1, Difficulty.None)) { Log.outError(LogFilter.Sql, "{0} has non existing spell (Id: {1}), skipped", cond.ToString(true), cond.ConditionValue1); return false; diff --git a/Source/Game/Conditions/DisableManager.cs b/Source/Game/Conditions/DisableManager.cs index 0fc6ca6d7..8526a5f87 100644 --- a/Source/Game/Conditions/DisableManager.cs +++ b/Source/Game/Conditions/DisableManager.cs @@ -73,7 +73,7 @@ namespace Game switch (type) { case DisableType.Spell: - if (!(Global.SpellMgr.HasSpellInfo(entry) || flags.HasAnyFlag(DisableFlags.SpellDeprecatedSpell))) + if (!(Global.SpellMgr.HasSpellInfo(entry, Difficulty.None) || flags.HasAnyFlag(DisableFlags.SpellDeprecatedSpell))) { Log.outError(LogFilter.Sql, "Spell entry {0} from `disables` doesn't exist in dbc, skipped.", entry); continue; diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index a682c6f36..cb0088a88 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -473,30 +473,6 @@ namespace Game.DataStorage foreach (SpellClassOptionsRecord classOption in CliDB.SpellClassOptionsStorage.Values) _spellFamilyNames.Add(classOption.SpellClassSet); - foreach (SpellPowerRecord power in CliDB.SpellPowerStorage.Values) - { - SpellPowerDifficultyRecord powerDifficulty = CliDB.SpellPowerDifficultyStorage.LookupByKey(power.Id); - if (powerDifficulty != null) - { - if (!_spellPowerDifficulties.ContainsKey(power.SpellID)) - _spellPowerDifficulties[power.SpellID] = new Dictionary>(); - - if (!_spellPowerDifficulties[power.SpellID].ContainsKey(powerDifficulty.DifficultyID)) - _spellPowerDifficulties[power.SpellID][powerDifficulty.DifficultyID] = new List(); - - _spellPowerDifficulties[power.SpellID][powerDifficulty.DifficultyID].Insert(powerDifficulty.OrderIndex, power); - } - else - { - if (!_spellPowers.ContainsKey(power.SpellID)) - _spellPowers[power.SpellID] = new List(); - - _spellPowers[power.SpellID].Insert(power.OrderIndex, power); - } - } - - CliDB.SpellPowerStorage.Clear(); - foreach (SpellProcsPerMinuteModRecord ppmMod in CliDB.SpellProcsPerMinuteModStorage.Values) _spellProcsPerMinuteMods.Add(ppmMod.SpellProcsPerMinuteID, ppmMod); @@ -1745,53 +1721,6 @@ namespace Game.DataStorage return _spellFamilyNames.Contains((byte)family); } - public List GetSpellPowers(uint spellId, Difficulty difficulty = Difficulty.None) - { - return GetSpellPowers(spellId, difficulty, out _); - } - - public List GetSpellPowers(uint spellId, Difficulty difficulty, out bool hasDifficultyPowers) - { - SpellPowerRecord[] powers = new SpellPowerRecord[0]; - hasDifficultyPowers = false; - - var difficultyDic = _spellPowerDifficulties.LookupByKey(spellId); - if (difficultyDic != null) - { - hasDifficultyPowers = true; - - DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficulty); - while (difficultyEntry != null) - { - var powerDifficultyList = difficultyDic.LookupByKey(difficultyEntry.Id); - if (powerDifficultyList != null) - { - if (powerDifficultyList.Count > powers.Length) - Array.Resize(ref powers, powerDifficultyList.Count); - - foreach (SpellPowerRecord difficultyPower in powerDifficultyList) - if (powers[difficultyPower.OrderIndex] == null) - powers[difficultyPower.OrderIndex] = difficultyPower; - } - - difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); - } - } - - var record = _spellPowers.LookupByKey(spellId); - if (record != null) - { - if (record.Count > powers.Length) - Array.Resize(ref powers, record.Count); - - foreach (SpellPowerRecord power in record) - if (powers[power.OrderIndex] == null) - powers[power.OrderIndex] = power; - } - - return powers.ToList(); - } - public List GetSpellProcsPerMinuteMods(uint spellprocsPerMinuteId) { return _spellProcsPerMinuteMods.LookupByKey(spellprocsPerMinuteId); @@ -2180,8 +2109,6 @@ namespace Game.DataStorage MultiMap _specializationSpellsBySpec = new MultiMap(); List> _specsBySpecSet = new List>(); List _spellFamilyNames = new List(); - Dictionary> _spellPowers = new Dictionary>(); - Dictionary>> _spellPowerDifficulties = new Dictionary>>(); MultiMap _spellProcsPerMinuteMods = new MultiMap(); List[][][] _talentsByPosition = new List[(int)Class.Max][][]; List _toys = new List(); diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index 3a502b23b..a875faddd 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -539,9 +539,9 @@ namespace Game.Entities switch (action.TargetType) { case AreaTriggerActionUserTypes.Friend: - return caster._IsValidAssistTarget(unit, Global.SpellMgr.GetSpellInfo(action.Param)); + return caster._IsValidAssistTarget(unit, Global.SpellMgr.GetSpellInfo(action.Param, caster.GetMap().GetDifficultyID())); case AreaTriggerActionUserTypes.Enemy: - return caster._IsValidAttackTarget(unit, Global.SpellMgr.GetSpellInfo(action.Param)); + return caster._IsValidAttackTarget(unit, Global.SpellMgr.GetSpellInfo(action.Param, caster.GetMap().GetDifficultyID())); case AreaTriggerActionUserTypes.Raid: return caster.IsInRaidWith(unit); case AreaTriggerActionUserTypes.Party: diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 3240bf8ff..cfe5aa122 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -1760,7 +1760,7 @@ namespace Game.Entities return false; bool immunedToAllEffects = true; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null || !effect.IsEffect()) continue; @@ -1780,7 +1780,7 @@ namespace Game.Entities public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster) { - SpellEffectInfo effect = spellInfo.GetEffect(GetMap().GetDifficultyID(), index); + SpellEffectInfo effect = spellInfo.GetEffect(index); if (effect == null) return true; @@ -1816,7 +1816,7 @@ namespace Game.Entities { if (m_spells[i] == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(m_spells[i]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(m_spells[i], GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Unit, "WORLD: unknown spell id {0}", m_spells[i]); @@ -1824,7 +1824,7 @@ namespace Game.Entities } bool bcontinue = true; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && ((effect.Effect == SpellEffectName.SchoolDamage) || (effect.Effect == SpellEffectName.Instakill) || (effect.Effect == SpellEffectName.EnvironmentalDamage) || (effect.Effect == SpellEffectName.HealthLeech))) @@ -1865,7 +1865,7 @@ namespace Game.Entities { if (m_spells[i] == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(m_spells[i]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(m_spells[i], GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Unit, "WORLD: unknown spell id {0}", m_spells[i]); @@ -1873,7 +1873,7 @@ namespace Game.Entities } bool bcontinue = true; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && effect.Effect == SpellEffectName.Heal) { @@ -2209,7 +2209,7 @@ namespace Game.Entities { foreach (var id in cainfo.auras) { - SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(id); + SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(id, GetMap().GetDifficultyID()); if (AdditionalSpellInfo == null) { Log.outError(LogFilter.Sql, "Creature ({0}) has wrong spell {1} defined in `auras` field.", GetGUID().ToString(), id); @@ -2593,7 +2593,7 @@ namespace Game.Entities if (spellID == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellID, GetMap().GetDifficultyID()); if (spellInfo != null) { if (spellInfo.GetRecoveryTime() == 0 // No cooldown @@ -2771,7 +2771,7 @@ namespace Game.Entities SpellInfo spellInfo = focusSpell.GetSpellInfo(); // don't use spell focus for vehicle spells - if (spellInfo.HasAura(Difficulty.None, AuraType.ControlVehicle)) + if (spellInfo.HasAura(AuraType.ControlVehicle)) return; if ((!target || target == this) && focusSpell.GetCastTime() == 0) // instant cast, untargeted (or self-targeted) spell doesn't need any facing updates diff --git a/Source/Game/Entities/Creature/Gossip.cs b/Source/Game/Entities/Creature/Gossip.cs index 5c3788bc7..1d047f58b 100644 --- a/Source/Game/Entities/Creature/Gossip.cs +++ b/Source/Game/Entities/Creature/Gossip.cs @@ -442,18 +442,12 @@ namespace Game.Misc packet.SuggestedPartyMembers = quest.SuggestedPlayers; // RewardSpell can teach multiple spells in trigger spell effects. But not all effects must be SPELL_EFFECT_LEARN_SPELL. See example spell 33950 - if (quest.RewardSpell != 0) + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell, Difficulty.None); + if (spellInfo != null) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell); - if (spellInfo.HasEffect(SpellEffectName.LearnSpell)) - { - var effects = spellInfo.GetEffectsForDifficulty(Difficulty.None); - foreach (var spellEffectInfo in effects) - { - if (spellEffectInfo.IsEffect(SpellEffectName.LearnSpell)) - packet.LearnSpells.Add(spellEffectInfo.TriggerSpell); - } - } + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) + if (effect.IsEffect(SpellEffectName.LearnSpell)) + packet.LearnSpells.Add(effect.TriggerSpell); } quest.BuildQuestRewards(packet.Rewards, _session.GetPlayer()); diff --git a/Source/Game/Entities/Creature/Trainer.cs b/Source/Game/Entities/Creature/Trainer.cs index dfb34ea87..61c9d1495 100644 --- a/Source/Game/Entities/Creature/Trainer.cs +++ b/Source/Game/Entities/Creature/Trainer.cs @@ -15,7 +15,7 @@ namespace Game.Entities public Array ReqAbility = new Array(3); public byte ReqLevel; - public bool IsCastable() { return Global.SpellMgr.GetSpellInfo(SpellId).HasEffect(SpellEffectName.LearnSpell); } + public bool IsCastable() { return Global.SpellMgr.GetSpellInfo(SpellId, Difficulty.None).HasEffect(SpellEffectName.LearnSpell); } } public class Trainer @@ -98,7 +98,7 @@ namespace Game.Entities if (state != TrainerSpellState.Available) return false; - SpellInfo trainerSpellInfo = Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId); + SpellInfo trainerSpellInfo = Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId, Difficulty.None); if (trainerSpellInfo.IsPrimaryProfessionFirstRank() && player.GetFreePrimaryProfessionPoints() == 0) return false; @@ -129,7 +129,7 @@ namespace Game.Entities // check ranks bool hasLearnSpellEffect = false; bool knowsAllLearnedSpells = true; - foreach (SpellEffectInfo spellEffect in Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId).GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo spellEffect in Global.SpellMgr.GetSpellInfo(trainerSpell.SpellId, Difficulty.None).GetEffects()) { if (spellEffect == null || !spellEffect.IsEffect(SpellEffectName.LearnSpell)) continue; diff --git a/Source/Game/Entities/DynamicObject.cs b/Source/Game/Entities/DynamicObject.cs index e8f2a02f6..5de8eeb72 100644 --- a/Source/Game/Entities/DynamicObject.cs +++ b/Source/Game/Entities/DynamicObject.cs @@ -239,7 +239,7 @@ namespace Game.Entities public SpellInfo GetSpellInfo() { - return Global.SpellMgr.GetSpellInfo(GetSpellId()); + return Global.SpellMgr.GetSpellInfo(GetSpellId(), GetMap().GetDifficultyID()); } public override void BuildValuesCreate(WorldPacket data, Player target) diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index b5aef8d75..63c28ac49 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -1215,7 +1215,7 @@ namespace Game.Entities if (trapInfo == null || trapInfo.type != GameObjectTypes.Trap) return; - SpellInfo trapSpell = Global.SpellMgr.GetSpellInfo(trapInfo.Trap.spell); + SpellInfo trapSpell = Global.SpellMgr.GetSpellInfo(trapInfo.Trap.spell, GetMap().GetDifficultyID()); if (trapSpell == null) // checked at load already return; @@ -1945,7 +1945,7 @@ namespace Game.Entities if (spellId == 0) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) { if (!user.IsTypeId(TypeId.Player) || !Global.OutdoorPvPMgr.HandleCustomSpell(user.ToPlayer(), spellId, this)) @@ -1972,12 +1972,12 @@ namespace Game.Entities public void CastSpell(Unit target, uint spellId, TriggerCastFlags triggered) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) return; bool self = false; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && effect.TargetA.GetTarget() == Targets.UnitCaster) { diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 0c7c7d961..7cf3cf72e 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -2340,7 +2340,7 @@ namespace Game.Entities if (eff.SetBonuses.Contains(itemSetSpell)) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "WORLD: unknown spell id {0} in items set {1} effects", itemSetSpell.SpellID, setid); @@ -2392,7 +2392,7 @@ namespace Game.Entities if (!eff.SetBonuses.Contains(itemSetSpell)) continue; - player.ApplyEquipSpell(Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID), null, false); + player.ApplyEquipSpell(Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID, Difficulty.None), null, false); eff.SetBonuses.Remove(itemSetSpell); } diff --git a/Source/Game/Entities/Object/Update/UpdateFields.cs b/Source/Game/Entities/Object/Update/UpdateFields.cs index 154956613..2e4bb8f2c 100644 --- a/Source/Game/Entities/Object/Update/UpdateFields.cs +++ b/Source/Game/Entities/Object/Update/UpdateFields.cs @@ -2093,10 +2093,10 @@ namespace Game.Entities CreatureTemplate cinfo = unit.ToCreature().GetCreatureTemplate(); // this also applies for transform auras - SpellInfo transform = Global.SpellMgr.GetSpellInfo(unit.GetTransForm()); + SpellInfo transform = Global.SpellMgr.GetSpellInfo(unit.GetTransForm(), unit.GetMap().GetDifficultyID()); if (transform != null) { - foreach (SpellEffectInfo effect in transform.GetEffectsForDifficulty(unit.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in transform.GetEffects()) { if (effect != null && effect.IsAura(AuraType.Transform)) { diff --git a/Source/Game/Entities/Pet.cs b/Source/Game/Entities/Pet.cs index e055ccd66..4c099635e 100644 --- a/Source/Game/Entities/Pet.cs +++ b/Source/Game/Entities/Pet.cs @@ -146,7 +146,7 @@ namespace Game.Entities return false; uint summonSpellId = result.Read(14); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(summonSpellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(summonSpellId, owner.GetMap().GetDifficultyID()); bool isTemporarySummon = spellInfo != null && spellInfo.GetDuration() > 0; if (current && isTemporarySummon) @@ -887,15 +887,22 @@ namespace Game.Entities AuraKey key = new AuraKey(casterGuid, itemGuid, result.Read(1), result.Read(2)); uint recalculateMask = result.Read(3); - byte stackCount = result.Read(4); - int maxDuration = result.Read(5); - int remainTime = result.Read(6); - byte remainCharges = result.Read(7); + Difficulty difficulty = (Difficulty)result.Read(4); + byte stackCount = result.Read(5); + int maxDuration = result.Read(6); + int remainTime = result.Read(7); + byte remainCharges = result.Read(8); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId, difficulty); if (spellInfo == null) { - Log.outError(LogFilter.Pet, "Unknown aura (spellid {0}), ignore.", key.SpellId); + Log.outError(LogFilter.Pet, "Pet._LoadAuras: Unknown aura (spellid {0}), ignore.", key.SpellId); + continue; + } + + if (difficulty != Difficulty.None && !CliDB.DifficultyStorage.ContainsKey(difficulty)) + { + Log.outError(LogFilter.Pet, $"Pet._LoadAuras: Unknown difficulty {difficulty} (spellid {key.SpellId}), ignore."); continue; } @@ -919,7 +926,7 @@ namespace Game.Entities var 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); + Aura aura = Aura.TryCreate(spellInfo, castId, key.EffectMask, this, null, difficulty, info.BaseAmounts, null, casterGuid); if (aura != null) { if (!aura.CanBeSaved()) @@ -969,6 +976,7 @@ namespace Game.Entities stmt.AddValue(index++, key.SpellId); stmt.AddValue(index++, key.EffectMask); stmt.AddValue(index++, recalculateMask); + stmt.AddValue(index++, aura.GetCastDifficulty()); stmt.AddValue(index++, aura.GetStackAmount()); stmt.AddValue(index++, aura.GetMaxDuration()); stmt.AddValue(index++, aura.GetDuration()); @@ -996,7 +1004,7 @@ namespace Game.Entities bool AddSpell(uint spellId, ActiveStates active = ActiveStates.Decide, PetSpellState state = PetSpellState.New, PetSpellType type = PetSpellType.Normal) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) { // do pet spell book cleanup @@ -1062,7 +1070,7 @@ namespace Game.Entities if (pair.Value.state == PetSpellState.Removed) continue; - SpellInfo oldRankSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Key); + SpellInfo oldRankSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); if (oldRankSpellInfo == null) continue; @@ -1156,7 +1164,7 @@ namespace Game.Entities { for (byte i = 0; i < SharedConst.MaxCreatureSpellDataSlots; ++i) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(defSpells.spellid[i]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(defSpells.spellid[i], Difficulty.None); if (spellInfo == null) continue; @@ -1254,7 +1262,7 @@ namespace Game.Entities GetCharmInfo().SetActionBar(i, 0, ActiveStates.Passive); else if (ab.GetActiveState() == ActiveStates.Enabled) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ab.GetAction()); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ab.GetAction(), Difficulty.None); if (spellInfo != null) ToggleAutocast(spellInfo, true); } @@ -1518,7 +1526,7 @@ namespace Game.Entities { foreach (var specSpell in specSpells) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(specSpell.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(specSpell.SpellID, Difficulty.None); if (spellInfo == null || spellInfo.SpellLevel > GetLevel()) continue; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index e10e64846..33503ba06 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -499,20 +499,27 @@ namespace Game.Entities itemGuid.SetRawValue(auraResult.Read(1)); AuraKey key = new AuraKey(casterGuid, itemGuid, auraResult.Read(2), auraResult.Read(3)); uint recalculateMask = auraResult.Read(4); - byte stackCount = auraResult.Read(5); - int maxDuration = auraResult.Read(6); - int remainTime = auraResult.Read(7); - byte remainCharges = auraResult.Read(8); - uint castItemId = auraResult.Read(9); - int castItemLevel = auraResult.Read(10); + Difficulty difficulty = (Difficulty)auraResult.Read(5); + byte stackCount = auraResult.Read(6); + int maxDuration = auraResult.Read(7); + int remainTime = auraResult.Read(8); + byte remainCharges = auraResult.Read(9); + uint castItemId = auraResult.Read(10); + int castItemLevel = auraResult.Read(11); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId, difficulty); if (spellInfo == null) { Log.outError(LogFilter.Player, "Unknown aura (spellid {0}), ignore.", key.SpellId); continue; } + if (difficulty != Difficulty.None && !CliDB.DifficultyStorage.ContainsKey(difficulty)) + { + Log.outError(LogFilter.Player, $"Player._LoadAuras: Player '{GetName()}' ({GetGUID()}) has an invalid aura difficulty {difficulty} (SpellID: {key.SpellId}), ignoring."); + continue; + } + // negative effects should continue counting down after logout if (remainTime != -1 && !spellInfo.IsPositive()) { @@ -535,7 +542,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, castItemId, castItemLevel); + Aura aura = Aura.TryCreate(spellInfo, castId, key.EffectMask, this, null, difficulty, info.BaseAmounts, null, casterGuid, itemGuid, castItemId, castItemLevel); if (aura != null) { if (!aura.CanBeSaved()) @@ -1738,6 +1745,7 @@ namespace Game.Entities stmt.AddValue(index++, key.SpellId); stmt.AddValue(index++, key.EffectMask); stmt.AddValue(index++, recalculateMask); + stmt.AddValue(index++, aura.GetCastDifficulty()); stmt.AddValue(index++, aura.GetStackAmount()); stmt.AddValue(index++, aura.GetMaxDuration()); stmt.AddValue(index++, aura.GetDuration()); diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 85255940f..ae94f5684 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -1634,7 +1634,7 @@ namespace Game.Entities if (pProto != null && IsInCombat() && (pProto.GetClass() == ItemClass.Weapon || pProto.GetInventoryType() == InventoryType.Relic) && m_weaponChangeTimer == 0) { uint cooldownSpell = (uint)(GetClass() == Class.Rogue ? 6123 : 6119); - var spellProto = Global.SpellMgr.GetSpellInfo(cooldownSpell); + var spellProto = Global.SpellMgr.GetSpellInfo(cooldownSpell, Difficulty.None); if (spellProto == null) Log.outError(LogFilter.Player, "Weapon switch cooldown spell {0} couldn't be found in Spell.dbc", cooldownSpell); @@ -4272,11 +4272,11 @@ namespace Game.Entities continue; // check if it is valid spell - SpellInfo spellproto = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID); + SpellInfo spellproto = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID, Difficulty.None); if (spellproto == null) continue; - if (spellproto.HasAura(GetMap().GetDifficultyID(), AuraType.ModXpPct) && !GetSession().GetCollectionMgr().CanApplyHeirloomXpBonus(item.GetEntry(), GetLevel()) + if (spellproto.HasAura(AuraType.ModXpPct) && !GetSession().GetCollectionMgr().CanApplyHeirloomXpBonus(item.GetEntry(), GetLevel()) && Global.DB2Mgr.GetHeirloomByItemId(item.GetEntry()) != null) continue; @@ -4336,10 +4336,11 @@ namespace Game.Entities DateTime now = GameTime.GetGameTimeSteadyPoint(); foreach (ItemEffectRecord effectData in pItem.GetEffects()) { + SpellInfo effectSpellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID, Difficulty.None); // apply proc cooldown to equip auras if we have any if (effectData.TriggerType == ItemSpelltriggerType.OnEquip) { - SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry((uint)effectData.SpellID); + SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(effectSpellInfo); if (procEntry == null) continue; @@ -4358,7 +4359,7 @@ namespace Game.Entities continue; // Don't replace longer cooldowns by equip cooldown if we have any. - if (GetSpellHistory().GetRemainingCooldown(Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID)) > 30 * Time.InMilliseconds) + if (GetSpellHistory().GetRemainingCooldown(effectSpellInfo) > 30 * Time.InMilliseconds) continue; GetSpellHistory().AddCooldown((uint)effectData.SpellID, pItem.GetEntry(), TimeSpan.FromSeconds(30)); @@ -5468,7 +5469,7 @@ namespace Game.Entities public void ApplyArtifactPowerRank(Item artifact, ArtifactPowerRankRecord artifactPowerRank, bool apply) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(artifactPowerRank.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(artifactPowerRank.SpellID, Difficulty.None); if (spellInfo == null) return; @@ -5597,7 +5598,7 @@ namespace Game.Entities void ApplyAzeriteEssencePower(AzeriteItem item, AzeriteEssencePowerRecord azeriteEssencePower, bool major, bool apply) { - SpellInfo powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MinorPowerDescription); + SpellInfo powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MinorPowerDescription, Difficulty.None); if (powerSpell != null) { if (apply) @@ -5608,7 +5609,7 @@ namespace Game.Entities if (major) { - powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MajorPowerDescription); + powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MajorPowerDescription, Difficulty.None); if (powerSpell != null) { if (powerSpell.IsPassive()) diff --git a/Source/Game/Entities/Player/Player.PvP.cs b/Source/Game/Entities/Player/Player.PvP.cs index b45bc0595..78b343f9b 100644 --- a/Source/Game/Entities/Player/Player.PvP.cs +++ b/Source/Game/Entities/Player/Player.PvP.cs @@ -379,7 +379,7 @@ namespace Game.Entities bool AddPvpTalent(PvpTalentRecord talent, byte activeTalentGroup, byte slot) { //ASSERT(talent); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) does not exist."); @@ -406,7 +406,7 @@ namespace Game.Entities void RemovePvpTalent(PvpTalentRecord talent) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); if (spellInfo == null) return; diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index bfd82ae9a..654fa6b3d 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -93,13 +93,13 @@ namespace Game.Entities return; } - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spell_id, Difficulty.None); if (spellInfo == null) return; // check learned spells state bool found = false; - foreach (SpellEffectInfo eff in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo eff in spellInfo.GetEffects()) { if (eff != null && eff.Effect == SpellEffectName.LearnSpell && !HasSpell(eff.TriggerSpell)) { @@ -784,16 +784,16 @@ namespace Game.Entities if (quest.SourceSpellID > 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.SourceSpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.SourceSpellID, GetMap().GetDifficultyID()); Unit caster = this; if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnAccept) && !spellInfo.HasTargetType(Targets.UnitCaster) && !spellInfo.HasTargetType(Targets.DestCasterSummon)) { Unit unit = questGiver.ToUnit(); if (unit != null) - unit.CastSpell(this, quest.SourceSpellID, true); + caster = unit; } - caster.CastSpell(this, quest.SourceSpellID, true); + caster.CastSpell(this, spellInfo, true); } SetQuestSlot(log_slot, quest_id, qtime); @@ -1092,7 +1092,7 @@ namespace Game.Entities // cast spells after mark quest complete (some spells have quest completed state requirements in spell_area data) if (quest.RewardSpell > 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardSpell, GetMap().GetDifficultyID()); Unit caster = this; if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnComplete) && !spellInfo.HasTargetType(Targets.UnitCaster)) { @@ -1101,7 +1101,7 @@ namespace Game.Entities caster = unit; } - caster.CastSpell(this, quest.RewardSpell, true); + caster.CastSpell(this, spellInfo, true); } else { @@ -1109,7 +1109,7 @@ namespace Game.Entities { if (quest.RewardDisplaySpell[i] > 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardDisplaySpell[i]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(quest.RewardDisplaySpell[i], GetMap().GetDifficultyID()); Unit caster = this; if (questGiver != null && questGiver.IsTypeMask(TypeMask.Unit) && !quest.HasFlag(QuestFlags.PlayerCastOnComplete) && !spellInfo.HasTargetType(Targets.UnitCaster)) { @@ -1118,7 +1118,7 @@ namespace Game.Entities caster = unit; } - caster.CastSpell(this, quest.RewardDisplaySpell[i], true); + caster.CastSpell(this, spellInfo, true); } } } diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index ff3e56ff2..70cb6ed3f 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -309,7 +309,7 @@ namespace Game.Entities { foreach (uint spellId in overrides) { - SpellInfo newInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo newInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (newInfo != null) return GetCastSpellInfo(newInfo); } @@ -338,7 +338,7 @@ namespace Game.Entities for (int j = 0; j < specSpells.Count; ++j) { SpecializationSpellsRecord specSpell = specSpells[j]; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(specSpell.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(specSpell.SpellID, Difficulty.None); if (spellInfo == null || spellInfo.SpellLevel > GetLevel()) continue; @@ -1027,7 +1027,7 @@ namespace Game.Entities { if (proto.Effects[idx].SpellID != 0 && proto.Effects[idx].TriggerType == ItemSpelltriggerType.OnUse) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)proto.Effects[idx].SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)proto.Effects[idx].SpellID, Difficulty.None); if (spellInfo != null) GetSpellHistory().SendCooldownEvent(spellInfo, m_lastPotionId); } @@ -1267,7 +1267,7 @@ namespace Game.Entities uint SkillValue = GetPureSkillValue((SkillType)_spell_idx.SkillupSkillLineID); // Alchemy Discoveries here - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(spellid); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(spellid, Difficulty.None); if (spellEntry != null && spellEntry.Mechanic == Mechanics.Discovery) { uint discoveredSpell = SkillDiscovery.GetSkillDiscoverySpell(_spell_idx.SkillupSkillLineID, spellid, this); @@ -1507,7 +1507,7 @@ namespace Game.Entities 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); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(learn_spell_id, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring ", item.GetEntry(), learn_spell_id); @@ -1537,7 +1537,7 @@ namespace Game.Entities if (effectData.TriggerType != ItemSpelltriggerType.OnUse) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "Player.CastItemUseSpell: Item (Entry: {0}) in have wrong spell id {1}, ignoring", item.GetEntry(), effectData.SpellID); @@ -1571,7 +1571,7 @@ namespace Game.Entities if (pEnchant.Effect[s] != ItemEnchantmentType.UseSpell) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pEnchant.EffectArg[s]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pEnchant.EffectArg[s], Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "Player.CastItemUseSpell Enchant {0}, cast unknown spell {1}", enchant_id, pEnchant.EffectArg[s]); @@ -1609,7 +1609,7 @@ namespace Game.Entities if (ability.SkillLine != skillId) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ability.Spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ability.Spell, Difficulty.None); if (spellInfo == null) continue; @@ -1855,7 +1855,7 @@ namespace Game.Entities if (pair.Value.State == PlayerSpellState.Removed || pair.Value.Disabled) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); if (spellInfo == null || !spellInfo.IsPassive() || spellInfo.EquippedItemClass < 0) continue; @@ -2107,7 +2107,7 @@ namespace Game.Entities uint nextSpell = Global.SpellMgr.GetNextSpellInChain(spellId); if (nextSpell != 0) { - SpellInfo spellInfo1 = Global.SpellMgr.GetSpellInfo(nextSpell); + SpellInfo spellInfo1 = Global.SpellMgr.GetSpellInfo(nextSpell, Difficulty.None); if (HasSpell(nextSpell) && !spellInfo1.HasAttribute(SpellCustomAttributes.IsTalent)) RemoveSpell(nextSpell, disabled, false); } @@ -2149,7 +2149,7 @@ namespace Game.Entities } // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo != null && spellInfo.IsPrimaryProfessionFirstRank()) { uint freeProfs = GetFreePrimaryProfessionPoints() + 1; @@ -2283,7 +2283,7 @@ namespace Game.Entities // passive spells which apply aura and have an item requirement are to be added manually, instead of casted if (spellInfo.EquippedItemClass >= 0) { - foreach (SpellEffectInfo effectInfo in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effectInfo in spellInfo.GetEffects()) { if (effectInfo != null && effectInfo.IsAura()) { @@ -2309,7 +2309,7 @@ namespace Game.Entities bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) { // do character spell book cleanup (all characters) @@ -2476,7 +2476,7 @@ namespace Game.Entities if (_spell.Value.State == PlayerSpellState.Removed) continue; - SpellInfo i_spellInfo = Global.SpellMgr.GetSpellInfo(_spell.Key); + SpellInfo i_spellInfo = Global.SpellMgr.GetSpellInfo(_spell.Key, Difficulty.None); if (i_spellInfo == null) continue; @@ -2708,7 +2708,7 @@ namespace Game.Entities public void ApplySpellMod(uint spellId, SpellModOp op, ref int basevalue, Spell spell = null) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) return; @@ -2807,7 +2807,7 @@ namespace Game.Entities public void ApplySpellMod(uint spellId, SpellModOp op, ref uint basevalue, Spell spell = null) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) return; @@ -2906,7 +2906,7 @@ namespace Game.Entities public void ApplySpellMod(uint spellId, SpellModOp op, ref float basevalue, Spell spell = null) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) return; @@ -3117,7 +3117,7 @@ namespace Game.Entities foreach (ItemSetSpellRecord itemSetSpell in eff.SetBonuses) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(itemSetSpell.SpellID, Difficulty.None); if (itemSetSpell.ChrSpecID != 0 && itemSetSpell.ChrSpecID != GetPrimarySpecialization()) ApplyEquipSpell(spellInfo, null, false, false); // item set aura is not for current spec @@ -3137,7 +3137,7 @@ namespace Game.Entities // remove cooldowns on spells that have < 10 min CD GetSpellHistory().ResetCooldowns(p => { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(p.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(p.Key, Difficulty.None); return spellInfo.RecoveryTime < 10 * Time.Minute * Time.InMilliseconds && spellInfo.CategoryRecoveryTime < 10 * Time.Minute * Time.InMilliseconds; }, true); @@ -3329,7 +3329,7 @@ namespace Game.Entities if (effectData.TriggerType != ItemSpelltriggerType.ChanceOnHit) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effectData.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "WORLD: unknown Item spellid {0}", effectData.SpellID); @@ -3387,7 +3387,7 @@ namespace Game.Entities if (entry != null && entry.AttributesMask.HasAnyFlag(EnchantProcAttributes.WhiteHit) && damageInfo.GetSpellInfo() != null) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pEnchant.EffectArg[s]); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pEnchant.EffectArg[s], Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Player, "Player.CastItemCombatSpell(GUID: {0}, name: {1}, enchant: {2}): unknown spell {3} is casted, ignoring...", @@ -3435,8 +3435,8 @@ namespace Game.Entities for (byte i = 0; i < SpellConst.MaxEffects; ++i) { - if (spellInfo.GetEffect(Difficulty.None, i).IsEffect()) - values.Add(SpellValueMod.BasePoint0 + i, MathFunctions.CalculatePct(spellInfo.GetEffect(Difficulty.None, i).CalcValue(this), effectPct)); + if (spellInfo.GetEffect(i).IsEffect()) + values.Add(SpellValueMod.BasePoint0 + i, MathFunctions.CalculatePct(spellInfo.GetEffect(i).CalcValue(this), effectPct)); } } @@ -3478,7 +3478,7 @@ namespace Game.Entities foreach (var spellId in smap.Keys) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) continue; diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index 54c3deeff..a15161ae3 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -58,7 +58,7 @@ namespace Game.Entities public bool AddTalent(TalentRecord talent, byte spec, bool learning) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Spells, "Player.AddTalent: Spell (ID: {0}) does not exist.", talent.SpellID); @@ -84,14 +84,14 @@ namespace Game.Entities public void RemoveTalent(TalentRecord talent) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); if (spellInfo == null) return; RemoveSpell(talent.SpellID, true); // search for spells that the talent teaches and unlearn them - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect != null && effect.TriggerSpell > 0 && effect.Effect == SpellEffectName.LearnSpell) RemoveSpell(effect.TriggerSpell, true); @@ -294,14 +294,14 @@ namespace Game.Entities if (talentInfo.SpellID == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellInfo == null) continue; RemoveSpell(talentInfo.SpellID, true); // search for spells that the talent teaches and unlearn them - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect != null && effect.TriggerSpell > 0 && effect.Effect == SpellEffectName.LearnSpell) RemoveSpell(effect.TriggerSpell, true); @@ -311,14 +311,14 @@ namespace Game.Entities foreach (var talentInfo in CliDB.PvpTalentStorage.Values) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellInfo == null) continue; RemoveSpell(talentInfo.SpellID, true); // search for spells that the talent teaches and unlearn them - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect != null && effect.TriggerSpell > 0 && effect.Effect == SpellEffectName.LearnSpell) RemoveSpell(effect.TriggerSpell, true); @@ -575,7 +575,7 @@ namespace Game.Entities continue; } - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Player, "Player {0} has unknown talent spell: {1}", GetName(), talentInfo.SpellID); @@ -597,7 +597,7 @@ namespace Game.Entities continue; } - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Player, $"Player.SendTalentsInfoData: Player '{GetName()}' ({GetGUID()}) has unknown pvp talent spell: {talentInfo.SpellID}"); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 9cd129a52..6b5568c18 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -1182,7 +1182,7 @@ namespace Game.Entities for (uint i = 0; i < SharedConst.MaxCreatureSpells; ++i) { uint spellId = vehicle.m_spells[i]; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) continue; @@ -1193,7 +1193,7 @@ namespace Game.Entities } if (spellInfo.IsPassive()) - vehicle.CastSpell(vehicle, spellId, true); + vehicle.CastSpell(vehicle, spellInfo, true); petSpells.ActionButtons[i] = UnitActionBarEntry.MAKE_UNIT_ACTION_BUTTON(spellId, i + 8); } @@ -1429,7 +1429,7 @@ namespace Game.Entities switch ((ActionButtonType)type) { case ActionButtonType.Spell: - if (Global.SpellMgr.GetSpellInfo(action) == null) + if (!Global.SpellMgr.HasSpellInfo(action, Difficulty.None)) { Log.outError(LogFilter.Player, "Spell action {0} not added into button {1} for player {2} (GUID: {3}): spell not exist", action, button, GetName(), GetGUID()); return false; @@ -3723,7 +3723,7 @@ namespace Game.Entities public override bool IsImmunedToSpellEffect(SpellInfo spellInfo, uint index, Unit caster) { - SpellEffectInfo effect = spellInfo.GetEffect(GetMap().GetDifficultyID(), index); + SpellEffectInfo effect = spellInfo.GetEffect(index); if (effect == null || !effect.IsEffect()) return false; @@ -4937,7 +4937,7 @@ namespace Game.Entities { //returning of reagents only for players, so best done here uint spellId = pet ? pet.m_unitData.CreatedBySpell : m_oldpetspell; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo != null) { diff --git a/Source/Game/Entities/StatSystem.cs b/Source/Game/Entities/StatSystem.cs index 142d52332..1dd91dd90 100644 --- a/Source/Game/Entities/StatSystem.cs +++ b/Source/Game/Entities/StatSystem.cs @@ -913,12 +913,12 @@ namespace Game.Entities return 0; int resistMech = 0; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null || !effect.IsEffect()) break; - int effect_mech = (int)spellInfo.GetEffectMechanic(effect.EffectIndex, GetMap().GetDifficultyID()); + int effect_mech = (int)spellInfo.GetEffectMechanic(effect.EffectIndex); if (effect_mech != 0) { int temp = GetTotalAuraModifierByMiscValue(AuraType.ModMechanicResistance, effect_mech); @@ -1451,7 +1451,7 @@ namespace Game.Entities Aura aura = GetAura(chrSpec.MasterySpellID[i]); if (aura != null) { - foreach (SpellEffectInfo effect in aura.GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in aura.GetSpellInfo().GetEffects()) { if (effect == null) continue; diff --git a/Source/Game/Entities/Totem.cs b/Source/Game/Entities/Totem.cs index cc7e6c4c5..83fa99505 100644 --- a/Source/Game/Entities/Totem.cs +++ b/Source/Game/Entities/Totem.cs @@ -75,7 +75,7 @@ namespace Game.Entities base.InitStats(duration); // Get spell cast by totem - SpellInfo totemSpell = Global.SpellMgr.GetSpellInfo(GetSpell()); + SpellInfo totemSpell = Global.SpellMgr.GetSpellInfo(GetSpell(), GetMap().GetDifficultyID()); if (totemSpell != null) if (totemSpell.CalcCastTime(GetLevel()) != 0) // If spell has cast time . its an active totem m_type = TotemType.Active; @@ -124,7 +124,7 @@ namespace Game.Entities { owner.SendAutoRepeatCancel(this); - SpellInfo spell = Global.SpellMgr.GetSpellInfo(m_unitData.CreatedBySpell); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(m_unitData.CreatedBySpell, GetMap().GetDifficultyID()); if (spell != null) GetSpellHistory().SendCooldownEvent(spell, 0, null, false); @@ -149,7 +149,7 @@ namespace Game.Entities if (GetEntry() == 5925) return false; - SpellEffectInfo effect = spellInfo.GetEffect(GetMap().GetDifficultyID(), index); + SpellEffectInfo effect = spellInfo.GetEffect(index); if (effect == null) return true; diff --git a/Source/Game/Entities/Unit/CharmInfo.cs b/Source/Game/Entities/Unit/CharmInfo.cs index 5ee4561a8..5b174c11f 100644 --- a/Source/Game/Entities/Unit/CharmInfo.cs +++ b/Source/Game/Entities/Unit/CharmInfo.cs @@ -106,7 +106,7 @@ namespace Game.Entities for (byte i = 0; i < SharedConst.MaxCreatureSpells; ++i) { uint spellId = _unit.ToCreature().m_spells[i]; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, _unit.GetMap().GetDifficultyID()); if (spellInfo != null) { if (spellInfo.IsPassive()) @@ -133,7 +133,7 @@ namespace Game.Entities for (uint x = 0; x < SharedConst.MaxSpellCharm; ++x) { uint spellId = _unit.ToCreature().m_spells[x]; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, _unit.GetMap().GetDifficultyID()); if (spellInfo == null) { @@ -260,7 +260,7 @@ namespace Game.Entities // check correctness if (PetActionBar[index].IsActionBarForSpell()) { - SpellInfo spelInfo = Global.SpellMgr.GetSpellInfo(PetActionBar[index].GetAction()); + SpellInfo spelInfo = Global.SpellMgr.GetSpellInfo(PetActionBar[index].GetAction(), _unit.GetMap().GetDifficultyID()); if (spelInfo == null) SetActionBar(index, 0, ActiveStates.Passive); else if (!spelInfo.IsAutocastable()) diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 1475dcbcb..0732ce039 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -1108,7 +1108,7 @@ namespace Game.Entities if (!victim.IsTypeId(TypeId.Player)) { // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this - if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(GetMap().GetDifficultyID(), AuraType.DamageShield))) + if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield))) victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime); victim.AddThreat(this, damage, damageSchoolMask, spellProto); @@ -2632,7 +2632,7 @@ namespace Game.Entities uint split_absorb = 0; DealDamageMods(caster, ref splitDamage, ref split_absorb); - SpellNonMeleeDamage log = new SpellNonMeleeDamage(this, caster, itr.GetSpellInfo().Id, itr.GetBase().GetSpellXSpellVisualId(), damageInfo.GetSchoolMask(), itr.GetBase().GetCastGUID()); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(this, caster, itr.GetSpellInfo(), itr.GetBase().GetSpellXSpellVisualId(), damageInfo.GetSchoolMask(), itr.GetBase().GetCastGUID()); CleanDamage cleanDamage = new CleanDamage(splitDamage, 0, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal); DealDamage(caster, splitDamage, cleanDamage, DamageEffectType.Direct, damageInfo.GetSchoolMask(), itr.GetSpellInfo(), false); log.damage = splitDamage; @@ -2806,7 +2806,7 @@ namespace Game.Entities if (APbonus != 0) // Can be negative { - bool normalized = spellProto != null && spellProto.HasEffect(GetMap().GetDifficultyID(), SpellEffectName.NormalizedWeaponDmg); + bool normalized = spellProto != null && spellProto.HasEffect(SpellEffectName.NormalizedWeaponDmg); DoneFlatBenefit += (int)(APbonus / 3.5f * GetAPMultiplier(attType, normalized)); } @@ -2986,7 +2986,7 @@ namespace Game.Entities if (!spellInfo.IsChanneled() && DotDuration > 0) DotFactor = DotDuration / 15000.0f; - uint DotTicks = spellInfo.GetMaxTicks(GetMap().GetDifficultyID()); + uint DotTicks = spellInfo.GetMaxTicks(); if (DotTicks != 0) DotFactor /= DotTicks; } @@ -3051,12 +3051,12 @@ namespace Game.Entities // can't attack invisible if (bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) { - if (obj && !obj.CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID()))) + if (obj && !obj.CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea())) return false; else if (!obj) { // ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player - bool ignoreStealthCheck = (bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID())) || + bool ignoreStealthCheck = (bySpell != null && bySpell.IsAffectingArea()) || (target.GetTypeId() == TypeId.Player && target.HasStealthAura() && target.IsInCombat() && IsInCombatWith(target)); if (!CanSeeOrDetect(target, ignoreStealthCheck)) @@ -3185,7 +3185,7 @@ namespace Game.Entities return false; // can't assist invisible - if ((bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) && !CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea(GetMap().GetDifficultyID()))) + if ((bySpell == null || !bySpell.HasAttribute(SpellAttr6.CanTargetInvisible)) && !CanSeeOrDetect(target, bySpell != null && bySpell.IsAffectingArea())) return false; // can't assist dead diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index 0bc13da3f..6ac10b27e 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -306,7 +306,7 @@ namespace Game.Entities m_attacker = spellNonMeleeDamage.attacker; m_victim = spellNonMeleeDamage.target; m_damage = spellNonMeleeDamage.damage; - m_spellInfo = Global.SpellMgr.GetSpellInfo(spellNonMeleeDamage.SpellId); + m_spellInfo = spellNonMeleeDamage.Spell; m_schoolMask = spellNonMeleeDamage.schoolMask; m_damageType = damageType; m_attackType = attackType; @@ -450,11 +450,11 @@ namespace Game.Entities public class SpellNonMeleeDamage { - public SpellNonMeleeDamage(Unit _attacker, Unit _target, uint _SpellID, uint _SpellXSpellVisualID, SpellSchoolMask _schoolMask, ObjectGuid _castId = default) + public SpellNonMeleeDamage(Unit _attacker, Unit _target, SpellInfo _spellInfo, uint _SpellXSpellVisualID, SpellSchoolMask _schoolMask, ObjectGuid _castId = default) { target = _target; attacker = _attacker; - SpellId = _SpellID; + Spell = _spellInfo; SpellXSpellVisualID = _SpellXSpellVisualID; schoolMask = _schoolMask; castId = _castId; @@ -464,7 +464,7 @@ namespace Game.Entities public Unit target; public Unit attacker; public ObjectGuid castId; - public uint SpellId; + public SpellInfo Spell; public uint SpellXSpellVisualID; public uint damage; public uint originalDamage; diff --git a/Source/Game/Entities/Unit/Unit.Pets.cs b/Source/Game/Entities/Unit/Unit.Pets.cs index 933320a54..427afb20e 100644 --- a/Source/Game/Entities/Unit/Unit.Pets.cs +++ b/Source/Game/Entities/Unit/Unit.Pets.cs @@ -194,7 +194,7 @@ namespace Game.Entities minion.SetSpeedRate(i, m_speed_rate[(int)i]); // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.m_unitData.CreatedBySpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.m_unitData.CreatedBySpell, GetMap().GetDifficultyID()); if (spellInfo != null && spellInfo.IsCooldownStartedOnEvent()) GetSpellHistory().StartCooldown(spellInfo, 0, null, true); } @@ -222,10 +222,10 @@ namespace Game.Entities else if (minion.IsTotem()) { // All summoned by totem minions must disappear when it is removed. - SpellInfo spInfo = Global.SpellMgr.GetSpellInfo(minion.ToTotem().GetSpell()); + SpellInfo spInfo = Global.SpellMgr.GetSpellInfo(minion.ToTotem().GetSpell(), GetMap().GetDifficultyID()); if (spInfo != null) { - foreach (SpellEffectInfo effect in spInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spInfo.GetEffects()) { if (effect == null || effect.Effect != SpellEffectName.Summon) continue; @@ -235,7 +235,7 @@ namespace Game.Entities } } - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.m_unitData.CreatedBySpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(minion.m_unitData.CreatedBySpell, GetMap().GetDifficultyID()); // Remove infinity cooldown if (spellInfo != null && spellInfo.IsCooldownStartedOnEvent()) GetSpellHistory().SendCooldownEvent(spellInfo); diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 32e24ea22..49830a707 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -36,12 +36,12 @@ namespace Game.Entities // function uses real base points (typically value - 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); + SpellEffectInfo effect = spellProto.GetEffect(effect_index); 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, uint castItemId = 0, int itemLevel = -1) { - SpellEffectInfo effect = spellProto.GetEffect(GetMap().GetDifficultyID(), effect_index); + SpellEffectInfo effect = spellProto.GetEffect(effect_index); variance = 0.0f; return effect != null ? effect.CalcValue(out variance, this, basePoints, target, castItemId, itemLevel) : 0; } @@ -466,7 +466,7 @@ namespace Game.Entities DoneTotal += (int)(DoneAdvertisedBenefit * coeff * stack); } - foreach (SpellEffectInfo eff in spellProto.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo eff in spellProto.GetEffects()) { if (eff == null) continue; @@ -586,7 +586,7 @@ namespace Game.Entities return false; }); - foreach (SpellEffectInfo eff in spellProto.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo eff in spellProto.GetEffects()) { if (eff == null) continue; @@ -1040,7 +1040,7 @@ namespace Game.Entities } public void CastSpell(Unit victim, uint spellId, TriggerCastFlags triggerFlags = TriggerCastFlags.None, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Spells, "CastSpell: unknown spell id {0} by caster: {1}", spellId, GetGUID().ToString()); @@ -1061,7 +1061,7 @@ namespace Game.Entities } public void CastSpell(float x, float y, float z, uint spellId, bool triggered, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Unit, "CastSpell: unknown spell id {0} by caster: {1}", spellId, GetGUID().ToString()); @@ -1074,7 +1074,7 @@ namespace Game.Entities } public void CastSpell(GameObject go, uint spellId, bool triggered, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Unit, "CastSpell: unknown spell id {0} by caster: {1}", spellId, GetGUID().ToString()); @@ -1111,7 +1111,7 @@ namespace Game.Entities } public void CastCustomSpell(uint spellId, Dictionary values, Unit victim = null, TriggerCastFlags triggerFlags = TriggerCastFlags.None, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Unit, "CastSpell: unknown spell id {0} by caster: {1}", spellId, GetGUID().ToString()); @@ -1152,7 +1152,7 @@ namespace Game.Entities bool DirectDamage = false; bool AreaEffect = false; - foreach (SpellEffectInfo effect in spellProto.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellProto.GetEffects()) { if (effect == null) continue; @@ -1213,7 +1213,7 @@ namespace Game.Entities CastingTime /= 2; // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing - foreach (SpellEffectInfo effect in spellProto.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellProto.GetEffects()) { if (effect != null && (effect.Effect == SpellEffectName.HealthLeech || (effect.Effect == SpellEffectName.ApplyAura && effect.ApplyAuraName == AuraType.PeriodicLeech))) @@ -1239,7 +1239,7 @@ namespace Game.Entities bool matches = auraEffect.GetMiscValue() != 0 ? auraEffect.GetMiscValue() == spellInfo.Id : auraEffect.IsAffectingSpell(spellInfo); if (matches) { - SpellInfo info = Global.SpellMgr.GetSpellInfo((uint)auraEffect.GetAmount()); + SpellInfo info = Global.SpellMgr.GetSpellInfo((uint)auraEffect.GetAmount(), GetMap().GetDifficultyID()); if (info != null) return info; } @@ -1266,7 +1266,7 @@ namespace Game.Entities { if (effect.GetMiscValue() == spellInfo.Id) { - SpellInfo visualSpell = Global.SpellMgr.GetSpellInfo((uint)effect.GetMiscValueB()); + SpellInfo visualSpell = Global.SpellMgr.GetSpellInfo((uint)effect.GetMiscValueB(), GetMap().GetDifficultyID()); if (visualSpell != null) { spellInfo = visualSpell; @@ -1512,7 +1512,7 @@ namespace Game.Entities int gain = victim.ModifyPower(powerType, damage); int overEnergize = damage - gain; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); victim.GetHostileRefManager().ThreatAssist(this, damage * 0.5f, spellInfo); SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType); @@ -1583,7 +1583,7 @@ namespace Game.Entities } bool immuneToAllEffects = true; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately @@ -1610,7 +1610,7 @@ namespace Game.Entities if ((pair.Key & schoolMask) == 0) continue; - SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value); + SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value, GetMap().GetDifficultyID()); if (!(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive() && caster && IsFriendlyTo(caster))) if (!spellInfo.CanPierceImmuneAura(immuneSpellInfo)) schoolImmunityMask |= pair.Key; @@ -1654,7 +1654,7 @@ namespace Game.Entities if (spellInfo == null) return false; - SpellEffectInfo effect = spellInfo.GetEffect(GetMap().GetDifficultyID(), index); + SpellEffectInfo effect = spellInfo.GetEffect(index); if (effect == null || !effect.IsEffect()) return false; @@ -1731,7 +1731,7 @@ namespace Game.Entities uint schoolImmunityMask = 0; var schoolList = m_spellImmune[(int)SpellImmunity.School]; foreach (var pair in schoolList) - if (Convert.ToBoolean(pair.Key & schoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(pair.Value))) + if (Convert.ToBoolean(pair.Key & schoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(pair.Value, GetMap().GetDifficultyID()))) schoolImmunityMask |= pair.Key; // // We need to be immune to all types @@ -2212,7 +2212,7 @@ namespace Game.Entities if (transformId == 0) return false; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(transformId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(transformId, GetMap().GetDifficultyID()); if (spellInfo == null) return false; @@ -2465,16 +2465,15 @@ namespace Game.Entities if (!victim.IsAlive() || victim.HasUnitState(UnitState.InFlight) || (victim.IsTypeId(TypeId.Unit) && victim.ToCreature().IsEvadingAttacks())) return; - SpellInfo spellProto = Global.SpellMgr.GetSpellInfo(damageInfo.SpellId); - if (spellProto == null) + if (damageInfo.Spell == null) { - Log.outDebug(LogFilter.Unit, "Unit.DealSpellDamage has wrong damageInfo.SpellID: {0}", damageInfo.SpellId); + Log.outDebug(LogFilter.Unit, "Unit.DealSpellDamage has no spell"); return; } // Call default DealDamage CleanDamage cleanDamage = new CleanDamage(damageInfo.cleanDamage, damageInfo.absorb, WeaponAttackType.BaseAttack, MeleeHitOutcome.Normal); - DealDamage(victim, damageInfo.damage, cleanDamage, DamageEffectType.SpellDirect, damageInfo.schoolMask, spellProto, durabilityLoss); + DealDamage(victim, damageInfo.damage, cleanDamage, DamageEffectType.SpellDirect, damageInfo.schoolMask, damageInfo.Spell, durabilityLoss); } public void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage log) @@ -2483,7 +2482,7 @@ namespace Game.Entities packet.Me = log.target.GetGUID(); packet.CasterGUID = log.attacker.GetGUID(); packet.CastID = log.castId; - packet.SpellID = (int)log.SpellId; + packet.SpellID = (int)(log.Spell != null ? log.Spell.Id : 0); packet.Damage = (int)log.damage; packet.OriginalDamage = (int)log.originalDamage; if (log.damage > log.preHitHealth) @@ -2622,7 +2621,7 @@ namespace Game.Entities } // turn off snare auras by setting amount to 0 - foreach (SpellEffectInfo effect in aura.GetSpellInfo().GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in aura.GetSpellInfo().GetEffects()) { if (effect == null || !effect.IsEffect()) continue; @@ -2902,7 +2901,7 @@ namespace Game.Entities if (target == null) return null; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) return null; @@ -2929,7 +2928,7 @@ namespace Game.Entities } ObjectGuid castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellInfo.Id, GetMap().GenerateLowGuid(HighGuid.Cast)); - Aura aura = Aura.TryRefreshStackOrCreate(spellInfo, castId, effMask, target, this); + Aura aura = Aura.TryRefreshStackOrCreate(spellInfo, castId, effMask, target, this, GetMap().GetDifficultyID()); if (aura != null) { aura.ApplyForTargets(); @@ -2960,14 +2959,14 @@ namespace Game.Entities Unit target = Convert.ToBoolean(clickInfo.castFlags & (byte)SpellClickCastFlags.TargetClicker) ? clicker : this; ObjectGuid origCasterGUID = Convert.ToBoolean(clickInfo.castFlags & (byte)SpellClickCastFlags.OrigCasterOwner) ? GetOwnerGUID() : clicker.GetGUID(); - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(clickInfo.spellId); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(clickInfo.spellId, caster.GetMap().GetDifficultyID()); // if (!spellEntry) should be checked at npc_spellclick load if (seatId > -1) { byte i = 0; bool valid = false; - foreach (SpellEffectInfo effect in spellEntry.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellEntry.GetEffects()) { if (effect == null) continue; @@ -2991,14 +2990,14 @@ namespace Game.Entities else // This can happen during Player._LoadAuras { int[] bp0 = new int[SpellConst.MaxEffects]; - foreach (SpellEffectInfo effect in spellEntry.GetEffectsForDifficulty(GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellEntry.GetEffects()) { if (effect != null) bp0[effect.EffectIndex] = effect.BasePoints; } bp0[i] = seatId; - Aura.TryRefreshStackOrCreate(spellEntry, ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellEntry.Id, GetMap().GenerateLowGuid(HighGuid.Cast)), SpellConst.MaxEffectMask, this, clicker, bp0, null, origCasterGUID); + Aura.TryRefreshStackOrCreate(spellEntry, ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellEntry.Id, GetMap().GenerateLowGuid(HighGuid.Cast)), SpellConst.MaxEffectMask, this, clicker, GetMap().GetDifficultyID(), bp0, null, origCasterGUID); } } else @@ -3006,7 +3005,7 @@ namespace Game.Entities if (IsInMap(caster)) caster.CastSpell(target, spellEntry, flags, null, null, origCasterGUID); else - Aura.TryRefreshStackOrCreate(spellEntry, ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellEntry.Id, GetMap().GenerateLowGuid(HighGuid.Cast)), SpellConst.MaxEffectMask, this, clicker, null, null, origCasterGUID); + Aura.TryRefreshStackOrCreate(spellEntry, ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, GetMapId(), spellEntry.Id, GetMap().GenerateLowGuid(HighGuid.Cast)), SpellConst.MaxEffectMask, this, clicker, GetMap().GetDifficultyID(), null, null, origCasterGUID); } result = true; @@ -3045,7 +3044,7 @@ namespace Game.Entities if (spellInfo.Mechanic != 0 && Convert.ToBoolean(mechanicMask & (1 << (int)spellInfo.Mechanic))) return true; - foreach (SpellEffectInfo effect in pair.Value.GetBase().GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect != null && effect.Effect != 0 && effect.Mechanic != 0) if (Convert.ToBoolean(mechanicMask & (1 << (int)effect.Mechanic))) return true; @@ -3331,10 +3330,10 @@ namespace Game.Entities if (aura.IsSingleTarget()) aura.UnregisterSingleTarget(); - Aura newAura = Aura.TryRefreshStackOrCreate(aura.GetSpellInfo(), aura.GetCastGUID(), effMask, stealer, null, baseDamage, null, aura.GetCasterGUID()); + Aura newAura = Aura.TryRefreshStackOrCreate(aura.GetSpellInfo(), aura.GetCastGUID(), effMask, stealer, null, aura.GetCastDifficulty(), baseDamage, null, aura.GetCasterGUID()); if (newAura != null) { - // created aura must not be single target aura,, so stealer won't loose it on recast + // created aura must not be single target aura, so stealer won't loose it on recast if (newAura.IsSingleTarget()) { newAura.UnregisterSingleTarget(); @@ -3742,7 +3741,7 @@ namespace Game.Entities if (pair.Value == null) continue; Aura aura = pair.Value.GetBase(); - if (!aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type)) + if (!aura.GetSpellInfo().HasAura(type)) _UnapplyAura(pair, AuraRemoveMode.Default); } @@ -3752,7 +3751,7 @@ namespace Game.Entities continue; Aura aura = pair.Value; - if (!aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type)) + if (!aura.GetSpellInfo().HasAura(type)) RemoveOwnedAura(pair, AuraRemoveMode.Default); } } @@ -3761,14 +3760,14 @@ namespace Game.Entities foreach (var pair in GetAppliedAuras()) { Aura aura = pair.Value.GetBase(); - if (!aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type1) || !aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type2)) + if (!aura.GetSpellInfo().HasAura(type1) || !aura.GetSpellInfo().HasAura(type2)) _UnapplyAura(pair, AuraRemoveMode.Default); } foreach (var pair in GetOwnedAuras()) { Aura aura = pair.Value; - if (!aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type1) || !aura.GetSpellInfo().HasAura(GetMap().GetDifficultyID(), type2)) + if (!aura.GetSpellInfo().HasAura(type1) || !aura.GetSpellInfo().HasAura(type2)) RemoveOwnedAura(pair, AuraRemoveMode.Default); } } @@ -3789,7 +3788,7 @@ namespace Game.Entities if (spell.Value.State == PlayerSpellState.Removed || spell.Value.Disabled) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.Key, Difficulty.None); if (spellInfo == null || !spellInfo.IsPassive()) continue; @@ -3804,7 +3803,7 @@ namespace Game.Entities { if (spell.Value.state == PetSpellState.Removed) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.Key, Difficulty.None); if (spellInfo == null || !spellInfo.IsPassive()) continue; if (spellInfo.CasterAuraState == flag) @@ -4189,7 +4188,7 @@ namespace Game.Entities return null; // update basepoints with new values - effect amount will be recalculated in ModStackAmount - foreach (SpellEffectInfo effect in foundAura.GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in newAura.GetEffects()) { if (effect == null) continue; @@ -4234,7 +4233,7 @@ namespace Game.Entities if (!IsHighestExclusiveAura(aura)) { - if (!aura.GetSpellInfo().IsAffectingArea(GetMap().GetDifficultyID())) + if (!aura.GetSpellInfo().IsAffectingArea()) { Unit caster = aura.GetCaster(); if (caster && caster.IsTypeId(TypeId.Player)) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index f57a4b504..ffb3131b7 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -269,7 +269,7 @@ namespace Game.Entities public bool IsDisallowedMountForm(uint spellId, ShapeShiftForm form, uint displayId) { - SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(GetTransForm()); + SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (transformSpellInfo != null) if (transformSpellInfo.HasAttribute(SpellAttr0.CastableWhileMounted)) return false; @@ -601,7 +601,7 @@ namespace Game.Entities if (gameObj.GetSpellId() != 0) { - SpellInfo createBySpell = Global.SpellMgr.GetSpellInfo(gameObj.GetSpellId()); + SpellInfo createBySpell = Global.SpellMgr.GetSpellInfo(gameObj.GetSpellId(), GetMap().GetDifficultyID()); // Need disable spell use for owner if (createBySpell != null && createBySpell.HasAttribute(SpellAttr0.DisabledWhileActive)) // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) @@ -634,7 +634,7 @@ namespace Game.Entities { RemoveAurasDueToSpell(spellid); - SpellInfo createBySpell = Global.SpellMgr.GetSpellInfo(spellid); + SpellInfo createBySpell = Global.SpellMgr.GetSpellInfo(spellid, GetMap().GetDifficultyID()); // Need activate spell use for owner if (createBySpell != null && createBySpell.IsCooldownStartedOnEvent()) // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases) @@ -1772,7 +1772,7 @@ namespace Game.Entities Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirBattle) || Global.SpellMgr.IsSpellMemberOfSpellGroup(spellProto.Id, SpellGroup.ElixirGuardian))) { - SpellEffectInfo effect = spellProto.GetEffect(Difficulty.None, 0); + SpellEffectInfo effect = spellProto.GetEffect(0); if (target.HasAura(53042) && effect != null && target.HasSpell(effect.TriggerSpell)) duration *= 2; } @@ -2674,7 +2674,7 @@ namespace Game.Entities if (effIndex != -1) { // bleeding effects are not reduced by armor - SpellEffectInfo effect = spellInfo.GetEffect(GetMap().GetDifficultyID(), (uint)effIndex); + SpellEffectInfo effect = spellInfo.GetEffect((uint)effIndex); if (effect != null) { if (effect.ApplyAuraName == AuraType.PeriodicDamage || effect.Effect == SpellEffectName.SchoolDamage) diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index e998f1cc2..c2e251cde 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -1393,7 +1393,7 @@ namespace Game case ScriptCommands.RemoveAura: { - if (Global.SpellMgr.GetSpellInfo(tmp.RemoveAura.SpellID) == null) + if (!Global.SpellMgr.HasSpellInfo(tmp.RemoveAura.SpellID, Difficulty.None)) { Log.outError(LogFilter.Sql, "Table `{0}` using non-existent spell (id: {1}) in SCRIPT_COMMAND_REMOVE_AURA for script id {2}", tableName, tmp.RemoveAura.SpellID, tmp.id); @@ -1410,7 +1410,7 @@ namespace Game case ScriptCommands.CastSpell: { - if (Global.SpellMgr.GetSpellInfo(tmp.CastSpell.SpellID) == null) + if (!Global.SpellMgr.HasSpellInfo(tmp.CastSpell.SpellID, Difficulty.None)) { Log.outError(LogFilter.Sql, "Table `{0}` using non-existent spell (id: {1}) in SCRIPT_COMMAND_CAST_SPELL for script id {2}", tableName, tmp.CastSpell.SpellID, tmp.id); @@ -1493,7 +1493,7 @@ namespace Game foreach (var script in sSpellScripts) { uint spellId = script.Key & 0x00FFFFFF; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Table `spell_scripts` has not existing spell (Id: {0}) as script id", spellId); @@ -1521,16 +1521,17 @@ namespace Game } // Load all possible script entries from spells - foreach (var spell in Global.SpellMgr.GetSpellInfoStorage().Values) + foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values) { - foreach (SpellEffectInfo effect in spell.GetEffectsForDifficulty(Difficulty.None)) + SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellNameEntry.Id, Difficulty.None); + if (spell != null) { - if (effect == null) - continue; - - if (effect.Effect == SpellEffectName.SendEvent) - if (effect.MiscValue != 0) - evt_scripts.Add((uint)effect.MiscValue); + foreach (SpellEffectInfo effect in spell.GetEffects()) + { + if (effect != null && effect.Effect == SpellEffectName.SendEvent) + if (effect.MiscValue != 0) + evt_scripts.Add((uint)effect.MiscValue); + } } } @@ -1612,7 +1613,7 @@ namespace Game spellId = -spellId; } - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)spellId, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Scriptname: `{0}` spell (Id: {1}) does not exist.", scriptName, spellId); @@ -1663,7 +1664,7 @@ namespace Game foreach (var script in spellScriptsStorage.KeyValueList) { - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(script.Key); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(script.Key, Difficulty.None); Dictionary SpellScriptLoaders = Global.ScriptMgr.CreateSpellScriptLoaders(script.Key); foreach (var pair in SpellScriptLoaders) @@ -1973,14 +1974,14 @@ namespace Game if (!uint.TryParse(id, out uint spellId)) continue; - SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (AdditionalSpellInfo == null) { Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has wrong spell {1} defined in `auras` field in `creature_template_addon`.", entry, spellId); continue; } - if (AdditionalSpellInfo.HasAura(Difficulty.None, AuraType.ControlVehicle)) + if (AdditionalSpellInfo.HasAura(AuraType.ControlVehicle)) Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has SPELL_AURA_CONTROL_VEHICLE aura {1} defined in `auras` field in `creature_template_addon`.", entry, spellId); if (creatureAddon.auras.Contains(spellId)) @@ -2087,14 +2088,14 @@ namespace Game if (!uint.TryParse(id, out uint spellId)) continue; - SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo AdditionalSpellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (AdditionalSpellInfo == null) { Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has wrong spell {1} defined in `auras` field in `creatureaddon`.", guid, spellId); continue; } - if (AdditionalSpellInfo.HasAura(Difficulty.None, AuraType.ControlVehicle)) + if (AdditionalSpellInfo.HasAura(AuraType.ControlVehicle)) Log.outError(LogFilter.Sql, "Creature (GUID: {0}) has SPELL_AURA_CONTROL_VEHICLE aura {1} defined in `auras` field in `creature_addon`.", guid, spellId); if (creatureAddon.auras.Contains(spellId)) @@ -2677,7 +2678,7 @@ namespace Game for (byte j = 0; j < SharedConst.MaxCreatureSpells; ++j) { - if (cInfo.Spells[j] != 0 && !Global.SpellMgr.HasSpellInfo(cInfo.Spells[j])) + if (cInfo.Spells[j] != 0 && !Global.SpellMgr.HasSpellInfo(cInfo.Spells[j], Difficulty.None)) { Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has non-existing Spell{1} ({2}), set to 0.", cInfo.Entry, j + 1, cInfo.Spells[j]); cInfo.Spells[j] = 0; @@ -2991,7 +2992,7 @@ namespace Game spell.ReqAbility[2] = trainerSpellsResult.Read(7); spell.ReqLevel = trainerSpellsResult.Read(8); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.SpellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell.SpellId, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, $"Table `trainer_spell` references non-existing spell (SpellId: {spell.SpellId}) for TrainerId {trainerId}, ignoring"); @@ -3008,7 +3009,7 @@ namespace Game for (var i = 0; i < spell.ReqAbility.Count; ++i) { uint requiredSpell = spell.ReqAbility[i]; - if (requiredSpell != 0 && !Global.SpellMgr.HasSpellInfo(requiredSpell)) + if (requiredSpell != 0 && !Global.SpellMgr.HasSpellInfo(requiredSpell, Difficulty.None)) { Log.outError(LogFilter.Sql, $"Table `trainer_spell` references non-existing spell (ReqAbility {i + 1}: {requiredSpell}) for TrainerId {spell.SpellId} and SpellId {trainerId}, ignoring"); allReqValid = false; @@ -4439,7 +4440,7 @@ namespace Game } void CheckGOSpellId(GameObjectTemplate goInfo, uint dataN, uint N) { - if (Global.SpellMgr.HasSpellInfo(dataN)) + if (Global.SpellMgr.HasSpellInfo(dataN, Difficulty.None)) return; Log.outError(LogFilter.Sql, "Gameobject (Entry: {0} GoType: {1}) have data{2}={3} but Spell (Entry {4}) not exist.", goInfo.entry, goInfo.type, N, dataN, dataN); @@ -5225,7 +5226,7 @@ namespace Game break; } case EncounterCreditType.CastSpell: - if (!Global.SpellMgr.HasSpellInfo(creditEntry)) + if (!Global.SpellMgr.HasSpellInfo(creditEntry, Difficulty.None)) { Log.outError(LogFilter.Sql, "Table `instance_encounters` has an invalid spell (entry {0}) linked to the encounter {1} ({2}), skipped!", creditEntry, entry, dungeonEncounter.Name[Global.WorldMgr.GetDefaultDbcLocale()]); @@ -6239,9 +6240,9 @@ namespace Game uint alliance = result.Read(0); uint horde = result.Read(1); - if (!Global.SpellMgr.HasSpellInfo(alliance)) + if (!Global.SpellMgr.HasSpellInfo(alliance, Difficulty.None)) Log.outError(LogFilter.Sql, "Spell {0} (alliance_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance); - else if (!Global.SpellMgr.HasSpellInfo(horde)) + else if (!Global.SpellMgr.HasSpellInfo(horde, Difficulty.None)) Log.outError(LogFilter.Sql, "Spell {0} (horde_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", horde); else FactionChangeSpells[alliance] = horde; @@ -6730,7 +6731,7 @@ namespace Game if (qinfo.SourceSpellID != 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.SourceSpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.SourceSpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Quest {0} has `SourceSpellid` = {1} but spell {1} doesn't exist, quest can't be done.", @@ -6810,7 +6811,7 @@ namespace Game Log.outError(LogFilter.Sql, "Quest {0} objective {1} has invalid currency amount {2}", qinfo.Id, obj.Id, obj.Amount); break; case QuestObjectiveType.LearnSpell: - if (!Global.SpellMgr.HasSpellInfo((uint)obj.ObjectID)) + if (!Global.SpellMgr.HasSpellInfo((uint)obj.ObjectID, Difficulty.None)) Log.outError(LogFilter.Sql, "Quest {0} objective {1} has non existing spell id {2}", qinfo.Id, obj.Id, obj.ObjectID); break; case QuestObjectiveType.WinPetBattleAgainstNpc: @@ -6943,7 +6944,7 @@ namespace Game { if (qinfo.RewardDisplaySpell[i] != 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.RewardSpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.RewardSpell, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Quest {0} has `RewardSpell` = {1} but spell {2} does not exist, spell removed as display reward.", @@ -6961,7 +6962,7 @@ namespace Game if (qinfo.RewardSpell > 0) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.RewardSpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(qinfo.RewardSpell, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Quest {0} has `RewardSpellCast` = {1} but spell {2} does not exist, quest will not have a spell reward.", @@ -7130,9 +7131,13 @@ namespace Game } // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE - foreach (var spellInfo in Global.SpellMgr.GetSpellInfoStorage().Values) + foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values) { - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellNameEntry.Id, Difficulty.None); + if (spellInfo == null) + continue; + + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null || effect.Effect != SpellEffectName.QuestComplete) continue; @@ -7736,7 +7741,7 @@ namespace Game } uint spellid = result.Read(1); - SpellInfo spellinfo = Global.SpellMgr.GetSpellInfo(spellid); + SpellInfo spellinfo = Global.SpellMgr.GetSpellInfo(spellid, Difficulty.None); if (spellinfo == null) { Log.outError(LogFilter.Sql, "Table npc_spellclick_spells creature: {0} references unknown spellid {1}. Skipping entry.", npc_entry, spellid); diff --git a/Source/Game/Handlers/PetHandler.cs b/Source/Game/Handlers/PetHandler.cs index 1e759e02b..4cbd8da44 100644 --- a/Source/Game/Handlers/PetHandler.cs +++ b/Source/Game/Handlers/PetHandler.cs @@ -75,7 +75,7 @@ namespace Game if (!pet.IsAlive()) { - SpellInfo spell = (flag == ActiveStates.Enabled || flag == ActiveStates.Passive) ? Global.SpellMgr.GetSpellInfo(spellid) : null; + SpellInfo spell = (flag == ActiveStates.Enabled || flag == ActiveStates.Passive) ? Global.SpellMgr.GetSpellInfo(spellid, pet.GetMap().GetDifficultyID()) : null; if (spell == null) return; if (!spell.HasAttribute(SpellAttr0.CastableWhileDead)) @@ -285,14 +285,14 @@ namespace Game unit_target = Global.ObjAccessor.GetUnit(GetPlayer(), guid2); // do not cast unknown spells - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellid, pet.GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", spellid); return; } - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy)) return; @@ -484,7 +484,7 @@ namespace Game //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if (!((act_state == ActiveStates.Enabled || act_state == ActiveStates.Disabled || act_state == ActiveStates.Passive) && spell_id != 0 && !pet.HasSpell(spell_id))) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, pet.GetMap().GetDifficultyID()); if (spellInfo != null) { //sign for autocast @@ -607,7 +607,7 @@ namespace Game return; } - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID, pet.GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Network, "WorldSession.HandlePetSpellAutocast: Unknown spell id {0} used by {1}.", packet.SpellID, packet.PetGUID.ToString()); @@ -636,13 +636,6 @@ namespace Game [WorldPacketHandler(ClientOpcodes.PetCastSpell)] void HandlePetCastSpell(PetCastSpell petCastSpell) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID); - if (spellInfo == null) - { - Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: unknown spell id {0} tried to cast by {1}", petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString()); - return; - } - Unit caster = Global.ObjAccessor.GetUnit(GetPlayer(), petCastSpell.PetGUID); if (!caster) { @@ -650,6 +643,13 @@ namespace Game return; } + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petCastSpell.Cast.SpellID, caster.GetMap().GetDifficultyID()); + if (spellInfo == null) + { + Log.outError(LogFilter.Network, "WorldSession.HandlePetCastSpell: unknown spell id {0} tried to cast by {1}", petCastSpell.Cast.SpellID, petCastSpell.PetGUID.ToString()); + return; + } + // This opcode is also sent from charmed and possessed units (players and creatures) if (caster != GetPlayer().GetGuardianPet() && caster != GetPlayer().GetCharm()) { diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 75a72f76b..6bdc33f26 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -92,7 +92,7 @@ namespace Game { foreach (ItemEffectRecord effect in item.GetEffects()) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effect.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)effect.SpellID, user.GetMap().GetDifficultyID()); if (spellInfo != null) { if (!spellInfo.CanBeUsedInCombat()) @@ -168,7 +168,7 @@ namespace Game uint lockId = proto.GetLockID(); if (lockId != 0) { - LockRecord lockInfo = CliDB.LockStorage.LookupByKey(lockId); + LockRecord lockInfo = CliDB.LockStorage.LookupByKey(lockId); if (lockInfo == null) { player.SendEquipError(InventoryResult.ItemLocked, item); @@ -274,7 +274,7 @@ namespace Game if (mover != GetPlayer() && mover.IsTypeId(TypeId.Player)) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cast.Cast.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cast.Cast.SpellID, mover.GetMap().GetDifficultyID()); if (spellInfo == null) { Log.outError(LogFilter.Network, "WORLD: unknown spell id {0}", cast.Cast.SpellID); @@ -351,7 +351,7 @@ namespace Game [WorldPacketHandler(ClientOpcodes.CancelAura)] void HandleCancelAura(CancelAura cancelAura) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cancelAura.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cancelAura.SpellID, _player.GetMap().GetDifficultyID()); if (spellInfo == null) return; @@ -401,14 +401,13 @@ namespace Game [WorldPacketHandler(ClientOpcodes.PetCancelAura)] void HandlePetCancelAura(PetCancelAura packet) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.SpellID); - if (spellInfo == null) + if (!Global.SpellMgr.HasSpellInfo(packet.SpellID, Difficulty.None)) { Log.outError(LogFilter.Network, "WORLD: unknown PET spell id {0}", packet.SpellID); return; } - Creature pet= ObjectAccessor.GetCreatureOrPetOrVehicle(_player, packet.PetGUID); + Creature pet = ObjectAccessor.GetCreatureOrPetOrVehicle(_player, packet.PetGUID); if (pet == null) { Log.outError(LogFilter.Network, "HandlePetCancelAura: Attempt to cancel an aura for non-existant {0} by player '{1}'", packet.PetGUID.ToString(), GetPlayer().GetName()); @@ -480,7 +479,7 @@ namespace Game if (!selfResSpells.Contains(selfRes.SpellId)) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(selfRes.SpellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(selfRes.SpellId, _player.GetMap().GetDifficultyID()); if (spellInfo != null) _player.CastSpell(_player, spellInfo, false, null); diff --git a/Source/Game/Handlers/ToyHandler.cs b/Source/Game/Handlers/ToyHandler.cs index b8802a814..11b7ddb1c 100644 --- a/Source/Game/Handlers/ToyHandler.cs +++ b/Source/Game/Handlers/ToyHandler.cs @@ -67,7 +67,7 @@ namespace Game if (effect == null) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.Cast.SpellID); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(packet.Cast.SpellID, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Network, "HandleUseToy: unknown spell id: {0} used by Toy Item entry {1}", packet.Cast.SpellID, itemId); diff --git a/Source/Game/Handlers/TradeHandler.cs b/Source/Game/Handlers/TradeHandler.cs index 6e62bc407..0a96a1d6f 100644 --- a/Source/Game/Handlers/TradeHandler.cs +++ b/Source/Game/Handlers/TradeHandler.cs @@ -341,7 +341,7 @@ namespace Game uint my_spell_id = my_trade.GetSpell(); if (my_spell_id != 0) { - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(my_spell_id); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(my_spell_id, _player.GetMap().GetDifficultyID()); Item castItem = my_trade.GetSpellCastItem(); if (spellEntry == null || !his_trade.GetItem(TradeSlots.NonTraded) || @@ -377,7 +377,7 @@ namespace Game uint his_spell_id = his_trade.GetSpell(); if (his_spell_id != 0) { - SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(his_spell_id); + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(his_spell_id, trader.GetMap().GetDifficultyID()); Item castItem = his_trade.GetSpellCastItem(); if (spellEntry == null || !my_trade.GetItem(TradeSlots.NonTraded) || (his_trade.HasSpellCastItem() && !castItem)) diff --git a/Source/Game/Loot/LootManager.cs b/Source/Game/Loot/LootManager.cs index 8ccb75da6..8e1af4fa2 100644 --- a/Source/Game/Loot/LootManager.cs +++ b/Source/Game/Loot/LootManager.cs @@ -20,6 +20,7 @@ using Framework.Database; using Game.Conditions; using Game.DataStorage; using Game.Entities; +using Game.Spells; using System; using System.Collections.Generic; @@ -378,8 +379,12 @@ namespace Game.Loots uint count = Spell.LoadAndCollectLootIds(out lootIdSet); // remove real entries and check existence loot - foreach (var spellInfo in Global.SpellMgr.GetSpellInfoStorage().Values) + foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values) { + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellNameEntry.Id, Difficulty.None); + if (spellInfo == null) + continue; + // possible cases if (!spellInfo.IsLootCrafting()) continue; diff --git a/Source/Game/Network/Packets/HotfixPackets.cs b/Source/Game/Network/Packets/HotfixPackets.cs index 34b4b7312..ccda15022 100644 --- a/Source/Game/Network/Packets/HotfixPackets.cs +++ b/Source/Game/Network/Packets/HotfixPackets.cs @@ -139,7 +139,7 @@ namespace Game.Network.Packets } public List Hotfixes = new List(); - public ByteBuffer HotfixContent; + public ByteBuffer HotfixContent = new ByteBuffer(); public class HotfixData { diff --git a/Source/Game/Scripting/ScriptManager.cs b/Source/Game/Scripting/ScriptManager.cs index 5579a1dab..3e5b392d1 100644 --- a/Source/Game/Scripting/ScriptManager.cs +++ b/Source/Game/Scripting/ScriptManager.cs @@ -335,73 +335,6 @@ namespace Game.Scripting public void FillSpellSummary() { UnitAI.FillAISpellInfo(); - - SpellInfo pTempSpell; - var spellStorage = Global.SpellMgr.GetSpellInfoStorage(); - foreach (var i in spellStorage.Keys) - { - spellSummaryStorage[i] = new SpellSummary(); - - pTempSpell = spellStorage.LookupByKey(i); - // This spell doesn't exist. - if (pTempSpell == null) - continue; - - foreach (SpellEffectInfo effect in pTempSpell.GetEffectsForDifficulty(Difficulty.None)) - { - if (effect == null) - continue; - - // Spell targets self. - if (effect.TargetA.GetTarget() == Targets.UnitCaster) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.Self - 1); - - // Spell targets a single enemy. - if (effect.TargetA.GetTarget() == Targets.UnitEnemy || effect.TargetA.GetTarget() == Targets.DestEnemy) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.SingleEnemy - 1); - - // Spell targets AoE at enemy. - if (effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || - effect.TargetA.GetTarget() == Targets.SrcCaster || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.AoeEnemy - 1); - - // Spell targets an enemy. - if (effect.TargetA.GetTarget() == Targets.UnitEnemy || effect.TargetA.GetTarget() == Targets.DestEnemy || - effect.TargetA.GetTarget() == Targets.UnitSrcAreaEnemy || effect.TargetA.GetTarget() == Targets.UnitDestAreaEnemy || - effect.TargetA.GetTarget() == Targets.SrcCaster || effect.TargetA.GetTarget() == Targets.DestDynobjEnemy) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.AnyEnemy - 1); - - // Spell targets a single friend (or self). - if (effect.TargetA.GetTarget() == Targets.UnitCaster || effect.TargetA.GetTarget() == Targets.UnitAlly || - effect.TargetA.GetTarget() == Targets.UnitParty) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.SingleFriend - 1); - - // Spell targets AoE friends. - if (effect.TargetA.GetTarget() == Targets.UnitCasterAreaParty || effect.TargetA.GetTarget() == Targets.UnitLastAreaParty || - effect.TargetA.GetTarget() == Targets.SrcCaster) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.AoeFriend - 1); - - // Spell targets any friend (or self). - if (effect.TargetA.GetTarget() == Targets.UnitCaster || effect.TargetA.GetTarget() == Targets.UnitAlly || - effect.TargetA.GetTarget() == Targets.UnitParty || effect.TargetA.GetTarget() == Targets.UnitCasterAreaParty || - effect.TargetA.GetTarget() == Targets.UnitLastAreaParty || effect.TargetA.GetTarget() == Targets.SrcCaster) - spellSummaryStorage[i].Targets |= 1 << ((int)SelectTargetType.AnyFriend - 1); - - // Make sure that this spell includes a damage effect. - if (effect.Effect == SpellEffectName.SchoolDamage || effect.Effect == SpellEffectName.Instakill || - effect.Effect == SpellEffectName.EnvironmentalDamage || effect.Effect == SpellEffectName.HealthLeech) - spellSummaryStorage[i].Effects |= 1 << ((int)SelectEffect.Damage - 1); - - // Make sure that this spell includes a healing effect (or an apply aura with a periodic heal). - if (effect.Effect == SpellEffectName.Heal || effect.Effect == SpellEffectName.HealMaxHealth || - effect.Effect == SpellEffectName.HealMechanical || (effect.Effect == SpellEffectName.ApplyAura && effect.ApplyAuraName == AuraType.PeriodicHeal)) - spellSummaryStorage[i].Effects |= 1 << ((int)SelectEffect.Healing - 1); - - // Make sure that this spell applies an aura. - if (effect.Effect == SpellEffectName.ApplyAura) - spellSummaryStorage[i].Effects |= 1 << ((int)SelectEffect.Aura - 1); - } - } } public List GetSplineChain(Creature who, ushort chainId) diff --git a/Source/Game/Scripting/SpellScript.cs b/Source/Game/Scripting/SpellScript.cs index 94f54b7a2..cabab6a20 100644 --- a/Source/Game/Scripting/SpellScript.cs +++ b/Source/Game/Scripting/SpellScript.cs @@ -48,7 +48,7 @@ namespace Game.Scripting bool allValid = true; foreach (uint spellId in spellIds) { - if (!Global.SpellMgr.HasSpellInfo(spellId)) + if (!Global.SpellMgr.HasSpellInfo(spellId, Difficulty.None)) { Log.outError(LogFilter.Scripts, "BaseSpellScript.ValidateSpellInfo: Spell {0} does not exist.", spellId); allValid = false; @@ -494,11 +494,12 @@ namespace Game.Scripting public Unit GetCaster() { return m_spell.GetCaster(); } public Unit GetOriginalCaster() { return m_spell.GetOriginalCaster(); } public SpellInfo GetSpellInfo() { return m_spell.GetSpellInfo(); } + public Difficulty GetCastDifficulty() { return m_spell.GetCastDifficulty(); } public SpellValue GetSpellValue() { return m_spell.m_spellValue; } public SpellEffectInfo GetEffectInfo(uint effIndex) { - return m_spell.GetEffect(effIndex); + return GetSpellInfo().GetEffect(effIndex); } // methods useable after spell is prepared @@ -773,7 +774,7 @@ namespace Game.Scripting public delegate void AuraEffectAbsorbDelegate(AuraEffect aura, DamageInfo damageInfo, ref uint absorbAmount); public delegate void AuraEffectSplitDelegate(AuraEffect aura, DamageInfo damageInfo, uint splitAmount); public delegate bool AuraCheckProcDelegate(ProcEventInfo info); - public delegate bool AuraCheckEffectProcDelegate(AuraEffect aura , ProcEventInfo info); + public delegate bool AuraCheckEffectProcDelegate(AuraEffect aura, ProcEventInfo info); public delegate void AuraProcDelegate(ProcEventInfo info); public delegate void AuraEffectProcDelegate(AuraEffect aura, ProcEventInfo info); @@ -1422,5 +1423,10 @@ namespace Game.Scripting } // returns AuraApplication object of currently processed target public AuraApplication GetTargetApplication() { return m_auraApplication; } + + public Difficulty GetCastDifficulty() + { + return GetAura().GetCastDifficulty(); + } } } diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index e9a5b67e9..cfa25ff5d 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -123,7 +123,7 @@ namespace Game.Spells if (IsSelfcasted() || caster == null || !caster.IsFriendlyTo(GetTarget())) { bool negativeFound = false; - foreach (SpellEffectInfo effect in GetBase().GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetBase().GetSpellInfo().GetEffects()) { if (effect != null && (Convert.ToBoolean((1 << (int)effect.EffectIndex) & effMask) && !GetBase().GetSpellInfo().IsPositiveEffect(effect.EffectIndex))) { @@ -138,7 +138,7 @@ namespace Game.Spells else { bool positiveFound = false; - foreach (SpellEffectInfo effect in GetBase().GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetBase().GetSpellInfo().GetEffects()) { if (effect != null && (Convert.ToBoolean((1 << (int)effect.EffectIndex) & effMask) && GetBase().GetSpellInfo().IsPositiveEffect(effect.EffectIndex))) { @@ -284,9 +284,10 @@ 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, uint castItemId, int castItemLevel) + public Aura(SpellInfo spellproto, ObjectGuid castId, WorldObject owner, Unit caster, Difficulty castDifficulty, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) { m_spellInfo = spellproto; + m_castDifficulty = castDifficulty; m_castGuid = castId; m_casterGuid = !casterGUID.IsEmpty() ? casterGUID : caster.GetGUID(); m_castItemGuid = castItem != null ? castItem.GetGUID() : castItemGuid; @@ -306,9 +307,8 @@ namespace Game.Spells m_lastProcAttemptTime = (DateTime.Now - TimeSpan.FromSeconds(10)); m_lastProcSuccessTime = (DateTime.Now - TimeSpan.FromSeconds(120)); - var powers = Global.DB2Mgr.GetSpellPowers(GetId(), caster ? caster.GetMap().GetDifficultyID() : Difficulty.None); - foreach (var power in powers) - if (power.ManaPerSecond != 0 || power.PowerPctPerSecond > 0.0f) + foreach (SpellPowerRecord power in m_spellInfo.PowerCosts) + if (power != null && (power.ManaPerSecond != 0 || power.PowerPctPerSecond > 0.0f)) m_periodicCosts.Add(power); if (!m_periodicCosts.Empty()) @@ -337,11 +337,9 @@ namespace Game.Spells public void _InitEffects(uint effMask, Unit caster, int[] baseAmount) { // shouldn't be in constructor - functions in AuraEffect.AuraEffect use polymorphism - _spellEffectInfos = m_spellInfo.GetEffectsForDifficulty(GetOwner().GetMap().GetDifficultyID()); + _effects = new AuraEffect[GetSpellInfo().GetEffects().Count]; - _effects = new AuraEffect[GetSpellEffectInfos().Length]; - - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { if (effect != null && Convert.ToBoolean(effMask & (1 << (int)effect.EffectIndex))) _effects[effect.EffectIndex] = new AuraEffect(this, effect.EffectIndex, baseAmount != null ? baseAmount[effect.EffectIndex] : (int?)null, caster); @@ -897,7 +895,7 @@ namespace Game.Spells public bool HasMoreThanOneEffectForType(AuraType auraType) { uint count = 0; - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { if (effect != null && HasEffect(effect.EffectIndex) && effect.ApplyAuraName == auraType) ++count; @@ -908,7 +906,7 @@ namespace Game.Spells public bool IsArea() { - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { if (effect != null && HasEffect(effect.EffectIndex) && effect.IsAreaAuraEffect()) return true; @@ -1287,7 +1285,7 @@ namespace Game.Spells // check cooldown if (caster.IsTypeId(TypeId.Player)) { - if (caster.GetSpellHistory().HasCooldown(aura.GetId())) + if (caster.GetSpellHistory().HasCooldown(aura.GetSpellInfo())) { // This additional check is needed to add a minimal delay before cooldown in in effect // to allow all bubbles broken by a single damage source proc mana return @@ -1502,14 +1500,14 @@ namespace Game.Spells if (IsPassive() && sameCaster && (m_spellInfo.IsDifferentRankOf(existingSpellInfo) || (m_spellInfo.Id == existingSpellInfo.Id && m_castItemGuid.IsEmpty()))) return false; - foreach (SpellEffectInfo effect in existingAura.GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in existingSpellInfo.GetEffects()) { // prevent remove triggering aura by triggered aura if (effect != null && effect.TriggerSpell == GetId()) return true; } - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { // prevent remove triggered aura by triggering aura refresh if (effect != null && effect.TriggerSpell == existingAura.GetId()) @@ -1552,7 +1550,7 @@ namespace Game.Spells // check same periodic auras for (byte i = 0; i < SpellConst.MaxEffects; i++) { - SpellEffectInfo effect = GetSpellEffectInfo(i); + SpellEffectInfo effect = m_spellInfo.GetEffect(i); if (effect == null) continue; @@ -1570,7 +1568,7 @@ namespace Game.Spells case AuraType.ObsModPower: case AuraType.ObsModHealth: case AuraType.PeriodicTriggerSpellWithValue: - SpellEffectInfo existingEffect = GetSpellEffectInfo(i); + SpellEffectInfo existingEffect = m_spellInfo.GetEffect(i); // periodic auras which target areas are not allowed to stack this way (replenishment for example) if (effect.IsTargetingArea() || (existingEffect != null && existingEffect.IsTargetingArea())) break; @@ -1639,7 +1637,7 @@ namespace Game.Spells SetNeedClientUpdateForTargets(); } - SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetId()); + SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); Cypher.Assert(procEntry != null); @@ -1651,7 +1649,7 @@ namespace Game.Spells public uint GetProcEffectMask(AuraApplication aurApp, ProcEventInfo eventInfo, DateTime now) { - SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetId()); + SpellProcEntry procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); // only auras with spell proc entry can trigger proc if (procEntry == null) return 0; @@ -1671,7 +1669,7 @@ namespace Game.Spells } // check don't break stealth attr present - if (m_spellInfo.HasAura(Difficulty.None, AuraType.ModStealth)) + if (m_spellInfo.HasAura(AuraType.ModStealth)) { SpellInfo eventSpellInfo = eventInfo.GetSpellInfo(); if (eventSpellInfo != null) @@ -2240,6 +2238,7 @@ namespace Game.Spells public SpellInfo GetSpellInfo() { return m_spellInfo; } public uint GetId() { return m_spellInfo.Id; } + public Difficulty GetCastDifficulty() { return m_castDifficulty; } public ObjectGuid GetCastGUID() { return m_castGuid; } public ObjectGuid GetCasterGUID() { return m_casterGuid; } public ObjectGuid GetCastItemGUID() { return m_castItemGuid; } @@ -2297,7 +2296,7 @@ namespace Game.Spells byte CalcMaxCharges(Unit caster) { uint maxProcCharges = m_spellInfo.ProcCharges; - var procEntry = Global.SpellMgr.GetSpellProcEntry(GetId()); + var procEntry = Global.SpellMgr.GetSpellProcEntry(GetSpellInfo()); if (procEntry != null) maxProcCharges = procEntry.Charges; @@ -2357,15 +2356,6 @@ namespace Game.Spells public AuraEffect[] GetAuraEffects() { return _effects; } - public SpellEffectInfo[] GetSpellEffectInfos() { return _spellEffectInfos; } - public SpellEffectInfo GetSpellEffectInfo(uint index) - { - if (index >= _spellEffectInfos.Length) - return null; - - return _spellEffectInfos[index]; - } - public void SetLastProcAttemptTime(DateTime lastProcAttemptTime) { m_lastProcAttemptTime = lastProcAttemptTime; } public void SetLastProcSuccessTime(DateTime lastProcSuccessTime) { m_lastProcSuccessTime = lastProcSuccessTime; } @@ -2379,14 +2369,14 @@ namespace Game.Spells { case TypeId.Unit: case TypeId.Player: - foreach (SpellEffectInfo effect in spellProto.GetEffectsForDifficulty(owner.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellProto.GetEffects()) { if (effect != null && effect.IsUnitOwnedAuraEffect()) effMask |= (uint)(1 << (int)effect.EffectIndex); } break; case TypeId.DynamicObject: - foreach (SpellEffectInfo effect in spellProto.GetEffectsForDifficulty(owner.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellProto.GetEffects()) { if (effect != null && effect.Effect == SpellEffectName.PersistentAreaAura) effMask |= (uint)(1 << (int)effect.EffectIndex); @@ -2397,12 +2387,11 @@ 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, uint castItemId = 0, int castItemLevel = -1) + public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, Difficulty castDifficulty, 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, castItemId, castItemLevel); + return TryRefreshStackOrCreate(spellproto, castId, tryEffMask, owner, caster, castDifficulty, out _, 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, uint castItemId = 0, int castItemLevel = -1) + public static Aura TryRefreshStackOrCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, Difficulty castDifficulty, 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); @@ -2425,9 +2414,9 @@ namespace Game.Spells return foundAura; } else - return Create(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, castDifficulty, 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, uint castItemId = 0, int castItemLevel = -1) + public static Aura TryCreate(SpellInfo spellproto, ObjectGuid castId, uint tryEffMask, WorldObject owner, Unit caster, Difficulty castDifficulty, 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); @@ -2436,9 +2425,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, castItemId, castItemLevel); + return Create(spellproto, castId, effMask, owner, caster, castDifficulty, 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, uint castItemId, int castItemLevel) + public static Aura Create(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, Difficulty castDifficulty, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) { Cypher.Assert(effMask != 0); Cypher.Assert(spellproto != null); @@ -2468,10 +2457,10 @@ namespace Game.Spells { case TypeId.Unit: case TypeId.Player: - aura = new UnitAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + aura = new UnitAura(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; case TypeId.DynamicObject: - aura = new DynObjAura(spellproto, castId, effMask, owner, caster, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); + aura = new DynObjAura(spellproto, castId, effMask, owner, caster, castDifficulty, baseAmount, castItem, casterGUID, castItemGuid, castItemId, castItemLevel); break; default: Cypher.Assert(false); @@ -2486,6 +2475,7 @@ namespace Game.Spells #region Fields List m_loadedScripts = new List(); SpellInfo m_spellInfo; + Difficulty m_castDifficulty; ObjectGuid m_castGuid; ObjectGuid m_casterGuid; ObjectGuid m_castItemGuid; @@ -2506,7 +2496,6 @@ namespace Game.Spells byte m_stackAmount; // Aura stack amount //might need to be arrays still - SpellEffectInfo[] _spellEffectInfos; AuraEffect[] _effects; Dictionary m_applications = new Dictionary(); @@ -2526,8 +2515,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, uint castItemId, int castItemLevel) - : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) + public UnitAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, Difficulty castDifficulty, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) + : base(spellproto, castId, owner, caster, castDifficulty, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { m_AuraDRGroup = DiminishingGroup.None; LoadScripts(); @@ -2560,7 +2549,7 @@ namespace Game.Spells public override void FillTargetMap(ref Dictionary targets, Unit caster) { - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { if (effect == null || !HasEffect(effect.EffectIndex)) continue; @@ -2637,8 +2626,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, uint castItemId, int castItemLevel) - : base(spellproto, castId, owner, caster, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) + public DynObjAura(SpellInfo spellproto, ObjectGuid castId, uint effMask, WorldObject owner, Unit caster, Difficulty castDifficulty, int[] baseAmount, Item castItem, ObjectGuid casterGUID, ObjectGuid castItemGuid, uint castItemId, int castItemLevel) + : base(spellproto, castId, owner, caster, castDifficulty, castItem, casterGUID, castItemGuid, castItemId, castItemLevel) { LoadScripts(); Cypher.Assert(GetDynobjOwner() != null); @@ -2661,7 +2650,7 @@ namespace Game.Spells Unit dynObjOwnerCaster = GetDynobjOwner().GetCaster(); float radius = GetDynobjOwner().GetRadius(); - foreach (SpellEffectInfo effect in GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) { if (effect == null || !HasEffect(effect.EffectIndex)) continue; diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 431aa51a6..8f25025bf 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -32,14 +32,14 @@ namespace Game.Spells { public class AuraEffect { - public AuraEffect(Aura baseAura, uint effindex, int? baseAmount, Unit caster) + public AuraEffect(Aura baseAura, uint effIndex, int? baseAmount, Unit caster) { auraBase = baseAura; m_spellInfo = baseAura.GetSpellInfo(); - _effectInfo = baseAura.GetSpellEffectInfo(effindex); + _effectInfo = m_spellInfo.GetEffect(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_effIndex = (byte)effIndex; m_canBeRecalculated = true; m_isPeriodic = false; @@ -683,7 +683,7 @@ namespace Game.Spells { // Don't proc extra attacks while already processing extra attack spell uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo != null) if (aurApp.GetTarget().ExtraAttacks != 0 && triggeredSpellInfo.HasEffect(SpellEffectName.AddExtraAttacks)) return false; @@ -818,7 +818,7 @@ namespace Game.Spells if (pair.Key == spellId || pair.Key == spellId2 || pair.Key == spellId3 || pair.Key == spellId4) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); if (spellInfo == null || !(spellInfo.IsPassive() || spellInfo.HasAttribute(SpellAttr0.HiddenClientside))) continue; @@ -1340,7 +1340,7 @@ namespace Game.Spells if (modelid > 0) { - SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransForm()); + SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransForm(), GetBase().GetCastDifficulty()); if (transformSpellInfo == null || !GetSpellInfo().IsPositive()) target.SetDisplayId(modelid); } @@ -1438,7 +1438,7 @@ namespace Game.Spells if (apply) { // update active transform spell only when transform not set or not overwriting negative by positive case - SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransForm()); + SpellInfo transformSpellInfo = Global.SpellMgr.GetSpellInfo(target.GetTransForm(), GetBase().GetCastDifficulty()); if (transformSpellInfo == null || !GetSpellInfo().IsPositive() || transformSpellInfo.IsPositive()) { target.SetTransForm(GetId()); @@ -2168,7 +2168,7 @@ namespace Game.Spells } //some spell has one aura of mount and one of vehicle - foreach (SpellEffectInfo effect in GetBase().GetSpellEffectInfos()) + foreach (SpellEffectInfo effect in GetSpellInfo().GetEffects()) if (effect != null && GetSpellEffectInfo().Effect == SpellEffectName.Summon && effect.MiscValue == GetMiscValue()) displayId = 0; } @@ -4464,10 +4464,10 @@ namespace Game.Spells uint spellId = 24659; if (apply && caster != null) { - SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId, GetBase().GetCastDifficulty()); for (uint i = 0; i < spell.StackAmount; ++i) - caster.CastSpell(target, spell.Id, true, null, null, GetCasterGUID()); + caster.CastSpell(target, spell, true, null, null, GetCasterGUID()); break; } target.RemoveAurasDueToSpell(spellId); @@ -4479,9 +4479,9 @@ namespace Game.Spells uint spellId = 24662; if (apply && caster != null) { - SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(spellId, GetBase().GetCastDifficulty()); for (uint i = 0; i < spell.StackAmount; ++i) - caster.CastSpell(target, spell.Id, true, null, null, GetCasterGUID()); + caster.CastSpell(target, spell, true, null, null, GetCasterGUID()); break; } target.RemoveAurasDueToSpell(spellId); @@ -4720,11 +4720,11 @@ namespace Game.Spells Unit target = aurApp.GetTarget(); uint triggeredSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggeredSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggeredSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo == null) return; - Unit caster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, target.GetMap().GetDifficultyID()) ? GetCaster() : target; + Unit caster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCaster() : target; if (!caster) return; @@ -4740,13 +4740,13 @@ namespace Game.Spells } else { - ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, caster.GetMap().GetDifficultyID()) ? GetCasterGUID() : target.GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target.GetGUID(); target.RemoveAura(triggeredSpellId, casterGUID, 0, aurApp.GetRemoveMode()); } } else if (mode.HasAnyFlag(AuraEffectHandleModes.Reapply) && apply) { - ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, caster.GetMap().GetDifficultyID()) ? GetCasterGUID() : target.GetGUID(); + ObjectGuid casterGUID = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target.GetGUID(); // change the stack amount to be equal to stack amount of our aura Aura triggeredAura = target.GetAura(triggeredSpellId, casterGUID); if (triggeredAura != null) @@ -5054,7 +5054,7 @@ namespace Game.Spells // generic casting code with custom spells and target/caster customs uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); SpellInfo auraSpellInfo = GetSpellInfo(); uint auraId = auraSpellInfo.Id; @@ -5320,11 +5320,11 @@ namespace Game.Spells } // Reget trigger spell proto - triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo != null) { - Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, target.GetMap().GetDifficultyID()) ? caster : target; + Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target; if (triggerCaster != null) { triggerCaster.CastSpell(target, triggeredSpellInfo, true, null, this); @@ -5338,10 +5338,10 @@ namespace Game.Spells void HandlePeriodicTriggerSpellWithValueAuraTick(Unit target, Unit caster) { uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo != null) { - Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, target.GetMap().GetDifficultyID()) ? caster : target; + Unit triggerCaster = triggeredSpellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target; if (triggerCaster != null) { int basepoints = GetAmount(); @@ -5571,7 +5571,7 @@ namespace Game.Spells uint resist = damageInfo.GetResist(); // SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage - SpellNonMeleeDamage log = new SpellNonMeleeDamage(caster, target, GetId(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().GetSchoolMask(), GetBase().GetCastGUID()); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(caster, target, GetSpellInfo(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().GetSchoolMask(), GetBase().GetCastGUID()); log.damage = damage; log.originalDamage = dmg; log.absorb = absorb; @@ -5876,7 +5876,7 @@ namespace Game.Spells SpellInfo spellProto = GetSpellInfo(); // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, target, spellProto.Id, GetBase().GetSpellXSpellVisualId(), spellProto.SchoolMask, GetBase().GetCastGUID()); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, target, spellProto, GetBase().GetSpellXSpellVisualId(), spellProto.SchoolMask, GetBase().GetCastGUID()); // no SpellDamageBonus for burn mana caster.CalculateSpellDamageTaken(damageInfo, (int)(gain * dmgMultiplier), spellProto); @@ -5917,7 +5917,7 @@ namespace Game.Spells Unit triggerTarget = eventInfo.GetProcTarget(); uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo != null) { Log.outDebug(LogFilter.Spells, "AuraEffect.HandleProcTriggerSpellAuraProc: Triggering spell {0} from aura {1} proc", triggeredSpellInfo.Id, GetId()); @@ -5933,7 +5933,7 @@ namespace Game.Spells Unit triggerTarget = eventInfo.GetProcTarget(); uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); if (triggeredSpellInfo != null) { int basepoints0 = GetAmount(); @@ -5954,7 +5954,7 @@ namespace Game.Spells return; } - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(target, triggerTarget, GetId(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().SchoolMask, GetBase().GetCastGUID()); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(target, triggerTarget, GetSpellInfo(), GetBase().GetSpellXSpellVisualId(), GetSpellInfo().SchoolMask, GetBase().GetCastGUID()); int damage = (int)target.SpellDamageBonusDone(triggerTarget, GetSpellInfo(), (uint)GetAmount(), DamageEffectType.SpellDirect, GetSpellEffectInfo()); damage = (int)triggerTarget.SpellDamageBonusTaken(target, GetSpellInfo(), (uint)damage, DamageEffectType.SpellDirect, GetSpellEffectInfo()); target.CalculateSpellDamageTaken(damageInfo, damage, GetSpellInfo()); @@ -6128,7 +6128,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - SpellInfo triggerSpellInfo = Global.SpellMgr.GetSpellInfo(GetSpellEffectInfo().TriggerSpell); + SpellInfo triggerSpellInfo = Global.SpellMgr.GetSpellInfo(GetSpellEffectInfo().TriggerSpell, GetBase().GetCastDifficulty()); if (triggerSpellInfo == null) return; @@ -6139,7 +6139,7 @@ namespace Game.Spells else { List summonedEntries = new List(); - foreach (var spellEffect in triggerSpellInfo.GetEffectsForDifficulty(target.GetMap().GetDifficultyID())) + foreach (var spellEffect in triggerSpellInfo.GetEffects()) { if (spellEffect != null && spellEffect.Effect == SpellEffectName.Summon) { diff --git a/Source/Game/Spells/Skills/SkillDiscovery.cs b/Source/Game/Spells/Skills/SkillDiscovery.cs index 0161d1460..44f914783 100644 --- a/Source/Game/Spells/Skills/SkillDiscovery.cs +++ b/Source/Game/Spells/Skills/SkillDiscovery.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Framework.Database; +using Game.DataStorage; using Game.Entities; using System.Collections.Generic; using System.Linq; @@ -62,7 +63,7 @@ namespace Game.Spells if (reqSkillOrSpell > 0) // spell case { uint absReqSkillOrSpell = (uint)reqSkillOrSpell; - SpellInfo reqSpellInfo = Global.SpellMgr.GetSpellInfo(absReqSkillOrSpell); + SpellInfo reqSpellInfo = Global.SpellMgr.GetSpellInfo(absReqSkillOrSpell, Difficulty.None); if (reqSpellInfo == null) { if (!reportedReqSpells.Contains(absReqSkillOrSpell)) @@ -117,8 +118,12 @@ namespace Game.Spells Log.outError(LogFilter.Sql, "Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n{0}", ssNonDiscoverableEntries.ToString()); // report about empty data for explicit discovery spells - foreach (var spellEntry in Global.SpellMgr.GetSpellInfoStorage().Values) + foreach (SpellNameRecord spellNameEntry in CliDB.SpellNameStorage.Values) { + SpellInfo spellEntry = Global.SpellMgr.GetSpellInfo(spellNameEntry.Id, Difficulty.None); + if (spellEntry == null) + continue; + // skip not explicit discovery spells if (!spellEntry.IsExplicitDiscovery()) continue; diff --git a/Source/Game/Spells/Skills/SkillExtraItems.cs b/Source/Game/Spells/Skills/SkillExtraItems.cs index 3a0bbd19b..dad16b8e1 100644 --- a/Source/Game/Spells/Skills/SkillExtraItems.cs +++ b/Source/Game/Spells/Skills/SkillExtraItems.cs @@ -44,14 +44,14 @@ namespace Game.Spells { uint spellId = result.Read(0); - if (!Global.SpellMgr.HasSpellInfo(spellId)) + if (!Global.SpellMgr.HasSpellInfo(spellId, Framework.Constants.Difficulty.None)) { Log.outError(LogFilter.Sql, "Skill specialization {0} has non-existent spell id in `skill_extra_item_template`!", spellId); continue; } uint requiredSpecialization = result.Read(1); - if (!Global.SpellMgr.HasSpellInfo(requiredSpecialization)) + if (!Global.SpellMgr.HasSpellInfo(requiredSpecialization, Framework.Constants.Difficulty.None)) { Log.outError(LogFilter.Sql, "Skill specialization {0} have not existed required specialization spell id {1} in `skill_extra_item_template`!", spellId, requiredSpecialization); continue; @@ -144,14 +144,14 @@ namespace Game.Spells do { uint spellId = result.Read(0); - if (!Global.SpellMgr.HasSpellInfo(spellId)) + if (!Global.SpellMgr.HasSpellInfo(spellId, Framework.Constants.Difficulty.None)) { Log.outError(LogFilter.Sql, "Skill perfection data for spell {0} has non-existent spell id in `skill_perfect_item_template`!", spellId); continue; } uint requiredSpecialization = result.Read(1); - if (!Global.SpellMgr.HasSpellInfo(requiredSpecialization)) + if (!Global.SpellMgr.HasSpellInfo(requiredSpecialization, Framework.Constants.Difficulty.None)) { Log.outError(LogFilter.Sql, "Skill perfection data for spell {0} has non-existent required specialization spell id {1} in `skill_perfect_item_template`!", spellId, requiredSpecialization); continue; diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index d892e9929..16cea526b 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -40,10 +40,9 @@ namespace Game.Spells { m_spellInfo = info; m_caster = (info.HasAttribute(SpellAttr6.CastByCharmer) && caster.GetCharmerOrOwner() != null ? caster.GetCharmerOrOwner() : caster); - m_spellValue = new SpellValue(caster.GetMap().GetDifficultyID(), m_spellInfo, caster); + m_spellValue = new SpellValue(m_spellInfo, caster); m_preGeneratedPath = new PathGenerator(m_caster); m_castItemLevel = -1; - _effects = info.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID()); m_castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, m_caster.GetMapId(), m_spellInfo.Id, m_caster.GetMap().GenerateLowGuid(HighGuid.Cast)); m_SpellVisual = caster.GetCastSpellXSpellVisualId(m_spellInfo); @@ -235,7 +234,7 @@ namespace Game.Spells SelectExplicitTargets(); uint processedAreaEffectsMask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -330,11 +329,11 @@ namespace Game.Spells // targets for effect already selected if (Convert.ToBoolean(effectMask & processedEffectMask)) return; - SpellEffectInfo _effect = GetEffect(effIndex); + SpellEffectInfo _effect = m_spellInfo.GetEffect(effIndex); if (_effect != null) { // choose which targets we can select at once - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null || effect.EffectIndex <= effIndex) continue; @@ -509,7 +508,7 @@ namespace Game.Spells return; } - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return; @@ -644,7 +643,7 @@ namespace Game.Spells List targets = new List(); SpellTargetObjectTypes objectType = targetType.GetObjectType(); SpellTargetCheckTypes selectionType = targetType.GetCheckType(); - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return; @@ -732,7 +731,7 @@ namespace Game.Spells return; } List targets = new List(); - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return; @@ -830,7 +829,7 @@ namespace Game.Spells break; } default: - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect != null) { float dist = effect.CalcRadius(m_caster); @@ -882,11 +881,11 @@ namespace Game.Spells switch (targetType.GetTarget()) { - case Targets.DestEnemy: + case Targets.DestTargetEnemy: case Targets.DestAny: break; default: - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect != null) { float angle = targetType.CalcDirectionAngle(); @@ -927,7 +926,7 @@ namespace Game.Spells case Targets.DestDest: return; default: - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect != null) { float angle = targetType.CalcDirectionAngle(); @@ -1018,7 +1017,7 @@ namespace Game.Spells void SelectImplicitChainTargets(uint effIndex, SpellImplicitTargetInfo targetType, WorldObject target, uint effMask) { - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return; @@ -1030,7 +1029,7 @@ namespace Game.Spells if (maxTargets > 1) { // mark damage multipliers as used - foreach (SpellEffectInfo eff in GetEffects()) + foreach (SpellEffectInfo eff in m_spellInfo.GetEffects()) if (eff != null && Convert.ToBoolean(effMask & (1 << (int)eff.EffectIndex))) m_damageMultipliers[eff.EffectIndex] = 1.0f; m_applyMultiplierMask |= (byte)effMask; @@ -1090,7 +1089,7 @@ namespace Game.Spells // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range) // limit max range to 300 yards, sometimes triggered spells can have 50000yds float bestDist = m_spellInfo.GetMaxRange(false); - SpellInfo triggerSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo triggerSpellInfo = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, GetCastDifficulty()); if (triggerSpellInfo != null) bestDist = Math.Min(Math.Max(bestDist, triggerSpellInfo.GetMaxRange(false)), Math.Min(dist2d, 300.0f)); @@ -1153,7 +1152,7 @@ namespace Game.Spells { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER // @todo this is a workaround - target shouldn't be stored in target map for those spells - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return; switch (effect.Effect) @@ -1505,7 +1504,7 @@ namespace Game.Spells void AddUnitTarget(Unit target, uint effectMask, bool checkIfValid = true, bool Implicit = true, Position losPosition = null) { uint validEffectMask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && (effectMask & (1 << (int)effect.EffectIndex)) != 0 && CheckEffectTarget(target, effect, losPosition)) validEffectMask |= 1u << (int)effect.EffectIndex; @@ -1520,7 +1519,7 @@ namespace Game.Spells return; // Check for effect immune skip if immuned - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && target.IsImmunedToSpellEffect(m_spellInfo, effect.EffectIndex, m_caster)) effectMask &= ~(uint)(1 << (int)effect.EffectIndex); @@ -1603,7 +1602,7 @@ namespace Game.Spells void AddGOTarget(GameObject go, uint effectMask) { uint validEffectMask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && (effectMask & (1 << (int)effect.EffectIndex)) != 0 && CheckEffectTarget(go, effect)) validEffectMask |= (uint)(1 << (int)effect.EffectIndex); @@ -1660,7 +1659,7 @@ namespace Game.Spells void AddItemTarget(Item item, uint effectMask) { uint validEffectMask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && (effectMask & (1 << (int)effect.EffectIndex)) != 0 && CheckEffectTarget(item, effect)) validEffectMask |= 1u << (int)effect.EffectIndex; @@ -1709,7 +1708,7 @@ namespace Game.Spells { uint farMask = 0; // create far target mask - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null && effect.IsFarUnitTargetEffect()) if (Convert.ToBoolean((1 << (int)effect.EffectIndex) & mask)) @@ -1726,7 +1725,7 @@ namespace Game.Spells // do far effects on the unit // can't use default call because of threading, do stuff as fast as possible - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(farMask & (1 << (int)effect.EffectIndex))) HandleEffects(unit, null, null, effect.EffectIndex, SpellEffectHandleMode.HitTarget); return; @@ -1885,7 +1884,7 @@ namespace Game.Spells else if (m_damage > 0) { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellSchoolMask, m_castId); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellSchoolMask, m_castId); // Check damage immunity if (unitTarget.IsImmunedToDamage(m_spellInfo)) @@ -1926,7 +1925,7 @@ namespace Game.Spells else { // Fill base damage struct (unitTarget - is real spell target) - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellSchoolMask); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellSchoolMask); hitMask |= Unit.CreateProcHitMask(damageInfo, missInfo); // Do triggers for unit if (canEffectTrigger) @@ -1996,7 +1995,7 @@ namespace Game.Spells // disable effects to which unit is immune SpellMissInfo returnVal = SpellMissInfo.Immune; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex))) if (unit.IsImmunedToSpellEffect(m_spellInfo, effect.EffectIndex, m_caster)) effectMask &= (uint)~(1 << (int)effect.EffectIndex); @@ -2051,7 +2050,7 @@ namespace Game.Spells } uint aura_effmask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && (Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)) && effect.IsUnitOwnedAuraEffect())) aura_effmask |= (1u << (int)effect.EffectIndex); @@ -2075,7 +2074,7 @@ namespace Game.Spells if (m_originalCaster != null) { int[] basePoints = new int[SpellConst.MaxEffects]; - foreach (SpellEffectInfo auraSpellEffect in GetEffects()) + foreach (SpellEffectInfo auraSpellEffect in m_spellInfo.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_castItemEntry, m_castItemLevel); @@ -2083,7 +2082,7 @@ namespace Game.Spells 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_castItemEntry, m_castItemLevel); + m_originalCaster, GetCastDifficulty(), 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 @@ -2117,7 +2116,7 @@ namespace Game.Spells { m_spellAura.Remove(); bool found = false; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && (Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)) && effect.Effect != SpellEffectName.ApplyAura)) found = true; if (!found) @@ -2137,7 +2136,7 @@ namespace Game.Spells { int origDuration = duration; duration = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null) { @@ -2168,7 +2167,7 @@ namespace Game.Spells } } - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex))) HandleEffects(unit, null, null, effect.EffectIndex, SpellEffectHandleMode.HitTarget); @@ -2244,7 +2243,7 @@ namespace Game.Spells PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(SpellMissInfo.None); - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex))) HandleEffects(null, null, go, effect.EffectIndex, SpellEffectHandleMode.HitTarget); @@ -2264,7 +2263,7 @@ namespace Game.Spells PrepareScriptHitHandlers(); CallScriptBeforeHitHandlers(SpellMissInfo.None); - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex))) HandleEffects(null, target.item, null, effect.EffectIndex, SpellEffectHandleMode.HitTarget); @@ -2281,7 +2280,7 @@ namespace Game.Spells uint channelTargetEffectMask = m_channelTargetEffectMask; uint channelAuraMask = 0; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && effect.Effect == SpellEffectName.ApplyAura) channelAuraMask |= (1u << (int)effect.EffectIndex); @@ -2481,7 +2480,7 @@ namespace Game.Spells if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && m_spellInfo.IsBreakingStealth()) { m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Cast); - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null && effect.GetUsedTargetObjectType() == SpellTargetObjectTypes.Unit) { @@ -2999,7 +2998,7 @@ namespace Game.Spells PrepareScriptHitHandlers(); // handle effects with SPELL_EFFECT_HANDLE_HIT mode - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { // don't do anything for empty effect if (effect == null || !effect.IsEffect()) @@ -3078,7 +3077,7 @@ namespace Game.Spells // check if the player caster has moved before the spell finished // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect - SpellEffectInfo effect = GetEffect(0); + SpellEffectInfo effect = m_spellInfo.GetEffect(0); if ((m_caster.IsTypeId(TypeId.Player) && m_timer != 0) && m_caster.IsMoving() && m_spellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.Movement) && ((effect != null && effect.Effect != SpellEffectName.Stuck) || !m_caster.HasUnitMovementFlag(MovementFlag.FallingFar)) && @@ -3187,7 +3186,7 @@ namespace Game.Spells { // Unsummon statue uint spell = m_caster.m_unitData.CreatedBySpell; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell, GetCastDifficulty()); if (spellInfo != null && spellInfo.IconFileDataId == 134230) { Log.outDebug(LogFilter.Spells, "Statue {0} is unsummoned in spell {1} finish", m_caster.GetGUID().ToString(), m_spellInfo.Id); @@ -3325,7 +3324,7 @@ namespace Game.Spells else { uint item = 0; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect.ItemType != 0) item = effect.ItemType; ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item); @@ -3799,7 +3798,7 @@ namespace Game.Spells spellExecuteLog.Caster = m_caster.GetGUID(); spellExecuteLog.SpellID = m_spellInfo.Id; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -4321,7 +4320,7 @@ namespace Game.Spells gameObjTarget = pGOTarget; destTarget = m_destTargets[i].Position; - effectInfo = GetEffect(i); + effectInfo = m_spellInfo.GetEffect(i); if (effectInfo == null) { Log.outError(LogFilter.Spells, "Spell: {0} HandleEffects at EffectIndex: {1} missing effect", m_spellInfo.Id, i); @@ -4477,7 +4476,7 @@ namespace Game.Spells if (m_caster.IsTypeId(TypeId.Player) && m_caster.ToPlayer().IsMoving() && (!m_caster.IsCharmed() || !m_caster.GetCharmerGUID().IsCreature()) && !m_caster.HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, m_spellInfo)) { // skip stuck spell to allow use it in falling case and apply spell limitations at movement - SpellEffectInfo effect = GetEffect(0); + SpellEffectInfo effect = m_spellInfo.GetEffect(0); if ((!m_caster.HasUnitMovementFlag(MovementFlag.FallingFar) || (effect != null && effect.Effect != SpellEffectName.Stuck)) && (IsAutoRepeat() || m_spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated))) return SpellCastResult.Moving; @@ -4584,7 +4583,7 @@ namespace Game.Spells } // check pet presence - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null && effect.TargetA.GetTarget() == Targets.UnitPet) { @@ -4678,7 +4677,7 @@ namespace Game.Spells if (castResult != SpellCastResult.SpellCastOk) return castResult; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -4712,11 +4711,10 @@ namespace Game.Spells break; Pet pet = m_caster.ToPlayer().GetPet(); - if (pet == null) return SpellCastResult.NoPet; - SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty.None); if (learn_spellproto == null) return SpellCastResult.NotKnown; @@ -4749,7 +4747,7 @@ namespace Game.Spells if (pet == null || pet.GetOwner() != m_caster) return SpellCastResult.BadTargets; - SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty.None); if (learn_spellproto == null) return SpellCastResult.NotKnown; @@ -5194,7 +5192,7 @@ namespace Game.Spells } } - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -5255,7 +5253,7 @@ namespace Game.Spells } case AuraType.Mounted: { - if (m_caster.IsInWater() && m_spellInfo.HasAura(m_caster.GetMap().GetDifficultyID(), AuraType.ModIncreaseMountedFlightSpeed)) + if (m_caster.IsInWater() && m_spellInfo.HasAura(AuraType.ModIncreaseMountedFlightSpeed)) return SpellCastResult.OnlyAbovewater; // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells @@ -5613,7 +5611,7 @@ namespace Game.Spells ObjectGuid targetguid = target.GetGUID(); // check if target already has the same or a more powerful aura - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -5837,7 +5835,7 @@ namespace Game.Spells { // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example SpellCastResult failReason = SpellCastResult.SpellCastOk; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster if (effect == null || effect.TargetA.GetTarget() == Targets.UnitPet) @@ -5993,7 +5991,7 @@ namespace Game.Spells } // special checks for spell effects - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -6028,7 +6026,7 @@ namespace Game.Spells player.SendEquipError(msg, null, null, effect.ItemType); return SpellCastResult.DontReport; } - else if ((efi = GetEffect(1)) != null) + else if ((efi = m_spellInfo.GetEffect(1)) != null) player.CastSpell(m_caster, (uint)efi.CalcValue(), false); // move this to anywhere return SpellCastResult.DontReport; } @@ -6437,7 +6435,7 @@ namespace Game.Spells WorldObject transport = null; // update effect destinations (in case of moved transport dest target) - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -6471,6 +6469,11 @@ namespace Game.Spells return CurrentSpellTypes.Generic; } + public Difficulty GetCastDifficulty() + { + return m_caster.GetMap().GetDifficultyID(); + } + bool CheckEffectTarget(Unit target, SpellEffectInfo effect, Position losPosition) { if (!effect.IsEffect()) @@ -6632,7 +6635,7 @@ namespace Game.Spells void HandleLaunchPhase() { // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { // don't do anything for empty effect if (effect == null || !effect.IsEffect()) @@ -6642,7 +6645,7 @@ namespace Game.Spells } float[] multiplier = new float[SpellConst.MaxEffects]; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) if (effect != null && Convert.ToBoolean(m_applyMultiplierMask & (1 << (int)effect.EffectIndex))) multiplier[effect.EffectIndex] = effect.CalcDamageMultiplier(m_originalCaster, this); @@ -6674,7 +6677,7 @@ namespace Game.Spells if (unit == null) return; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null && Convert.ToBoolean(targetInfo.effectMask & (1 << (int)effect.EffectIndex))) { @@ -6723,7 +6726,7 @@ namespace Game.Spells if (lockInfo == null) return SpellCastResult.BadTargets; - SpellEffectInfo effect = GetEffect(effIndex); + SpellEffectInfo effect = m_spellInfo.GetEffect(effIndex); if (effect == null) return SpellCastResult.BadTargets; // no idea about correct error @@ -7054,7 +7057,7 @@ namespace Game.Spells { bool only_on_caster = (triggeredByAura != null && triggeredByAura.HasAttribute(SpellAttr4.ProcOnlyOnCaster)); // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a casted spell with TARGET_UNIT_CASTER - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect != null && (Convert.ToBoolean(effMask & (1 << (int)effect.EffectIndex)) && (!only_on_caster || (effect.TargetA.GetTarget() == Targets.UnitCaster)))) return true; @@ -7073,7 +7076,7 @@ namespace Game.Spells if (!aurEff.IsAffectingSpell(m_spellInfo)) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(aurEff.GetSpellEffectInfo().TriggerSpell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(aurEff.GetSpellEffectInfo().TriggerSpell, GetCastDifficulty()); if (spellInfo != null) { // calculate the chance using spell base amount, because aura amount is not updated on combo-points change @@ -7279,25 +7282,6 @@ namespace Game.Spells public SpellInfo GetTriggeredByAuraSpell() { return m_triggeredByAuraSpell; } - SpellEffectInfo[] GetEffects() { return _effects; } - public SpellEffectInfo GetEffect(uint index) - { - if (index >= _effects.Length) - return null; - - return _effects[index]; - } - - bool HasEffect(SpellEffectName effect) - { - foreach (SpellEffectInfo eff in GetEffects()) - { - if (eff != null && eff.IsEffect(effect)) - return true; - } - return false; - } - public static implicit operator bool(Spell spell) { return spell != null; @@ -7412,8 +7396,6 @@ namespace Game.Spells // and in same time need aura data and after aura deleting. public SpellInfo m_triggeredByAuraSpell; - SpellEffectInfo[] _effects = new SpellEffectInfo[SpellConst.MaxEffects]; - bool m_skipCheck; #endregion } @@ -7605,11 +7587,9 @@ namespace Game.Spells public class SpellValue { - public SpellValue(Difficulty difficulty, SpellInfo proto, Unit caster) + public SpellValue(SpellInfo proto, Unit caster) { - var effects = proto.GetEffectsForDifficulty(difficulty); - Cypher.Assert(effects.Length <= SpellConst.MaxEffects); - foreach (SpellEffectInfo effect in effects) + foreach (SpellEffectInfo effect in proto.GetEffects()) if (effect != null) EffectBasePoints[effect.EffectIndex] = effect.CalcBaseValue(caster, null, 0, -1); diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 2d1983061..5667c6f44 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -133,7 +133,7 @@ namespace Game.Spells DamageInfo damageInfo = new DamageInfo(m_caster, unitTarget, (uint)damage, m_spellInfo, m_spellInfo.GetSchoolMask(), DamageEffectType.SpellDirect, WeaponAttackType.BaseAttack); m_caster.CalcAbsorbResist(damageInfo); - SpellNonMeleeDamage log = new SpellNonMeleeDamage(m_caster, unitTarget, m_spellInfo.Id, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(m_caster, unitTarget, m_spellInfo, m_SpellVisual, m_spellInfo.GetSchoolMask(), m_castId); log.damage = damageInfo.GetDamage(); log.originalDamage = (uint)damage; log.absorb = damageInfo.GetAbsorb(); @@ -359,7 +359,7 @@ namespace Game.Spells case 29284: { // Brittle Armor - SpellInfo spell = Global.SpellMgr.GetSpellInfo(24575); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(24575, GetCastDifficulty()); if (spell == null) return; @@ -371,7 +371,7 @@ namespace Game.Spells case 29286: { // Mercurial Shield - SpellInfo spell = Global.SpellMgr.GetSpellInfo(26464); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(26464, GetCastDifficulty()); if (spell == null) return; @@ -401,7 +401,7 @@ namespace Game.Spells } // normal case - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (spellInfo == null) { Log.outDebug(LogFilter.Spells, "Spell.EffectTriggerSpell spell {0} tried to trigger unknown spell {1}", m_spellInfo.Id, triggered_spell_id); @@ -411,13 +411,13 @@ namespace Game.Spells SpellCastTargets targets = new SpellCastTargets(); if (effectHandleMode == SpellEffectHandleMode.LaunchTarget) { - if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID())) + if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo)) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SpellEffectHandleMode.Launch) { - if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID()) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) + if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) return; if (spellInfo.GetExplicitTargetMask().HasAnyFlag(SpellCastTargetFlags.DestLocation)) @@ -450,7 +450,7 @@ namespace Game.Spells uint triggered_spell_id = effectInfo.TriggerSpell; // normal case - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (spellInfo == null) { Log.outDebug(LogFilter.Spells, "Spell.EffectTriggerMissileSpell spell {0} tried to trigger unknown spell {1}", m_spellInfo.Id, triggered_spell_id); @@ -460,13 +460,13 @@ namespace Game.Spells SpellCastTargets targets = new SpellCastTargets(); if (effectHandleMode == SpellEffectHandleMode.HitTarget) { - if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID())) + if (!spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo)) return; targets.SetUnitTarget(unitTarget); } else //if (effectHandleMode == SpellEffectHandleMode.Hit) { - if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo, m_caster.GetMap().GetDifficultyID()) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) + if (spellInfo.NeedsToBeTriggeredByCaster(m_spellInfo) && effectInfo.GetProvidedTargetMask().HasAnyFlag(SpellCastTargetFlags.UnitMask)) return; if (spellInfo.GetExplicitTargetMask().HasAnyFlag(SpellCastTargetFlags.DestLocation)) @@ -503,7 +503,7 @@ namespace Game.Spells uint triggered_spell_id = effectInfo.TriggerSpell; // normal case - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (spellInfo == null) { Log.outError(LogFilter.Spells, "Spell.EffectForceCast of spell {0}: triggering unknown spell id {1}", m_spellInfo.Id, triggered_spell_id); @@ -548,7 +548,7 @@ namespace Game.Spells return; uint triggered_spell_id = effectInfo.TriggerSpell; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(triggered_spell_id, GetCastDifficulty()); if (spellInfo == null) { Log.outError(LogFilter.Spells, "EffectTriggerRitualOfSummoning of spell {0}: triggering unknown spell id {1}", m_spellInfo.Id, triggered_spell_id); @@ -1217,7 +1217,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_castItemEntry, m_castItemLevel); + Aura aura = Aura.TryCreate(m_spellInfo, m_castId, SpellConst.MaxEffectMask, dynObj, caster, GetCastDifficulty(), m_spellValue.EffectBasePoints, null, ObjectGuid.Empty, ObjectGuid.Empty, m_castItemEntry, m_castItemLevel); if (aura != null) { m_spellAura = aura; @@ -1775,8 +1775,8 @@ namespace Game.Spells int basePoints = effectInfo.CalcValue(); if (basePoints > SharedConst.MaxVehicleSeats) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)basePoints); - if (spellInfo != null && spellInfo.HasAura(m_originalCaster.GetMap().GetDifficultyID(), AuraType.ControlVehicle)) + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo((uint)basePoints, GetCastDifficulty()); + if (spellInfo != null && spellInfo.HasAura(AuraType.ControlVehicle)) spellId = spellInfo.Id; } @@ -2435,7 +2435,7 @@ namespace Game.Spells if (pet == null) return; - SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell); + SpellInfo learn_spellproto = Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell, Difficulty.None); if (learn_spellproto == null) return; @@ -2497,7 +2497,7 @@ namespace Game.Spells // and handle all effects at once for (var i = effIndex + 1; i < SpellConst.MaxEffects; ++i) { - var effect = GetEffect(i); + var effect = m_spellInfo.GetEffect(i); if (effect == null) continue; @@ -2588,7 +2588,7 @@ namespace Game.Spells // Blood Strike if (m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x400000u)) { - SpellEffectInfo effect = GetEffect(2); + SpellEffectInfo effect = m_spellInfo.GetEffect(2); if (effect != null) { float bonusPct = effect.CalcValue(m_caster) * unitTarget.GetDiseasesByCaster(m_caster.GetGUID()) / 2.0f; @@ -2606,7 +2606,7 @@ namespace Game.Spells bool normalized = false; float weaponDamagePercentMod = 1.0f; - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -2659,7 +2659,7 @@ namespace Game.Spells uint weaponDamage = m_caster.CalculateDamage(m_attackType, normalized, addPctMods); // Sequence is important - foreach (SpellEffectInfo effect in GetEffects()) + foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) { if (effect == null) continue; @@ -3118,8 +3118,8 @@ namespace Game.Spells if (unitTarget == null || !unitTarget.IsTypeId(TypeId.Player) || effIndex != 0) return; - uint spellID = (uint)GetEffect(0).CalcValue(); - uint questID = (uint)GetEffect(1).CalcValue(); + uint spellID = (uint)m_spellInfo.GetEffect(0).CalcValue(); + uint questID = (uint)m_spellInfo.GetEffect(1).CalcValue(); if (unitTarget.ToPlayer().GetQuestStatus(questID) == QuestStatus.Complete) unitTarget.CastSpell(unitTarget, spellID, true); @@ -3192,7 +3192,7 @@ namespace Game.Spells { // @todo a hack, range = 11, should after some time cast, otherwise too far m_caster.CastSpell(parent, 62496, true); - unitTarget.CastSpell(parent, (uint)GetEffect(0).CalcValue()); + unitTarget.CastSpell(parent, (uint)m_spellInfo.GetEffect(0).CalcValue()); } } } @@ -3289,64 +3289,6 @@ namespace Game.Spells } break; } - case SpellFamilyNames.Paladin: - { - // Judgement (seal trigger) - if (m_spellInfo.GetCategory() == (int)SpellCategories.Judgement) - { - if (unitTarget == null || !unitTarget.IsAlive()) - return; - uint spellId1; - uint spellId2 = 0; - - // Judgement self add switch - switch (m_spellInfo.Id) - { - case 53407: spellId1 = 20184; break; // Judgement of Justice - case 20271: // Judgement of Light - case 57774: spellId1 = 20185; break; // Judgement of Light - case 53408: spellId1 = 20186; break; // Judgement of Wisdom - default: - Log.outError(LogFilter.Spells, "Unsupported Judgement (seal trigger) spell (Id: {0}) in Spell.EffectScriptEffect", m_spellInfo.Id); - return; - } - // all seals have aura dummy in 2 effect - foreach (var app in m_caster.GetAppliedAuras()) - { - Aura aura = app.Value.GetBase(); - if (aura.GetSpellInfo().GetSpellSpecific() == SpellSpecificType.Seal) - { - AuraEffect aureff = aura.GetEffect(2); - if (aureff != null) - if (aureff.GetAuraType() == AuraType.Dummy) - { - if (Global.SpellMgr.GetSpellInfo((uint)aureff.GetAmount()) != null) - spellId2 = (uint)aureff.GetAmount(); - break; - } - if (spellId2 == 0) - { - switch (app.Key) - { - // Seal of light, Seal of wisdom, Seal of justice - case 20165: - case 20166: - case 20164: - spellId2 = 54158; - break; - } - } - break; - } - } - if (spellId1 != 0) - m_caster.CastSpell(unitTarget, spellId1, true); - if (spellId2 != 0) - m_caster.CastSpell(unitTarget, spellId2, true); - return; - } - break; - } } // normal DB scripted effect @@ -3535,7 +3477,7 @@ namespace Game.Spells player.TeleportTo(player.GetHomebind(), TeleportToOptions.Spell); // Stuck spell trigger Hearthstone cooldown - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(8690); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(8690, GetCastDifficulty()); if (spellInfo == null) return; @@ -4399,7 +4341,7 @@ namespace Game.Spells if (totem != null && totem.IsTotem()) { uint spell_id = totem.m_unitData.CreatedBySpell; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, GetCastDifficulty()); if (spellInfo != null) { var costs = spellInfo.CalcPowerCost(m_caster, spellInfo.GetSchoolMask()); @@ -5244,7 +5186,7 @@ namespace Game.Spells if (spell_id == 0) continue; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, GetCastDifficulty()); if (spellInfo == null) continue; @@ -5255,7 +5197,7 @@ namespace Game.Spells continue; TriggerCastFlags triggerFlags = (TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.CastDirectly | TriggerCastFlags.DontReportCastError); - m_caster.CastSpell(m_caster, spell_id, triggerFlags); + m_caster.CastSpell(m_caster, spellInfo, triggerFlags); } } @@ -5365,7 +5307,7 @@ namespace Game.Spells uint health = (uint)target.CountPctFromMaxHealth(damage); uint mana = (uint)MathFunctions.CalculatePct(target.GetMaxPower(PowerType.Mana), damage); uint resurrectAura = 0; - if (Global.SpellMgr.GetSpellInfo(effectInfo.TriggerSpell) != null) + if (Global.SpellMgr.HasSpellInfo(effectInfo.TriggerSpell, Difficulty.None)) resurrectAura = effectInfo.TriggerSpell; if (resurrectAura != 0 && target.HasAura(resurrectAura)) diff --git a/Source/Game/Spells/SpellHistory.cs b/Source/Game/Spells/SpellHistory.cs index e3ba46d59..2911a4bcf 100644 --- a/Source/Game/Spells/SpellHistory.cs +++ b/Source/Game/Spells/SpellHistory.cs @@ -40,7 +40,7 @@ namespace Game.Spells do { uint spellId = cooldownsResult.Read(0); - if (!Global.SpellMgr.HasSpellInfo(spellId)) + if (!Global.SpellMgr.HasSpellInfo(spellId, Difficulty.None)) continue; int index = (typeof(T) == typeof(Pet) ? 1 : 2); @@ -222,7 +222,7 @@ namespace Game.Spells if (IsSchoolLocked(spellInfo.GetSchoolMask())) return false; - if (HasCooldown(spellInfo.Id, itemId, ignoreCategoryCooldown)) + if (HasCooldown(spellInfo, itemId, ignoreCategoryCooldown)) return false; if (!HasCharge(spellInfo.ChargeCategoryId)) @@ -459,7 +459,7 @@ namespace Game.Spells player.SendPacket(new CooldownEvent(player != _owner, categoryEntry.SpellId)); if (startCooldown) - StartCooldown(Global.SpellMgr.GetSpellInfo(categoryEntry.SpellId), itemId, spell); + StartCooldown(Global.SpellMgr.GetSpellInfo(categoryEntry.SpellId, _owner.GetMap().GetDifficultyID()), itemId, spell); } player.SendPacket(new CooldownEvent(player != _owner, spellInfo.Id)); @@ -581,7 +581,7 @@ namespace Game.Spells public bool HasCooldown(uint spellId, uint itemId = 0, bool ignoreCategoryCooldown = false) { - return HasCooldown(Global.SpellMgr.GetSpellInfo(spellId), itemId, ignoreCategoryCooldown); + return HasCooldown(Global.SpellMgr.GetSpellInfo(spellId, _owner.GetMap().GetDifficultyID()), itemId, ignoreCategoryCooldown); } public bool HasCooldown(SpellInfo spellInfo, uint itemId = 0, bool ignoreCategoryCooldown = false) @@ -663,7 +663,7 @@ namespace Game.Spells spellCooldown.Flags = SpellCooldownFlags.None; foreach (uint spellId in knownSpells) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, _owner.GetMap().GetDifficultyID()); if (spellInfo.IsCooldownStartedOnEvent()) continue; @@ -904,7 +904,7 @@ namespace Game.Spells // add all profession CDs created while in duel (if any) foreach (var c in _spellCooldowns) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(c.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(c.Key, Difficulty.None); if (spellInfo.RecoveryTime > 10 * Time.Minute * Time.InMilliseconds || spellInfo.CategoryRecoveryTime > 10 * Time.Minute * Time.InMilliseconds) _spellCooldownsBeforeDuel[c.Key] = _spellCooldowns[c.Key]; diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 2236bf565..5857d3533 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -30,31 +30,20 @@ namespace Game.Spells { public class SpellInfo { - public SpellInfo(SpellInfoLoadHelper data, Dictionary effectsMap, MultiMap visuals) + public SpellInfo(SpellNameRecord spellName, Difficulty difficulty, SpellInfoLoadHelper data, List visuals) { - Id = data.Entry.Id; + Id = spellName.Id; + Difficulty = difficulty; - _effects = new Dictionary(); - - if (effectsMap != null) + foreach (SpellEffectRecord spellEffect in data.Effects) { - foreach (var pair in effectsMap) - { - if (!_effects.ContainsKey(pair.Key)) - _effects[pair.Key] = new SpellEffectInfo[pair.Value.Length]; + if (spellEffect == null) + continue; - for (int i = 0; i < pair.Value.Length; ++i) - { - SpellEffectRecord effect = pair.Value[i]; - if (effect == null) - continue; + _effects[spellEffect.EffectIndex] = new SpellEffectInfo(this, spellEffect); + } - _effects[pair.Key][effect.EffectIndex] = new SpellEffectInfo(this, effect.EffectIndex, effect); - } - } - } - - SpellName = data.Entry.Name; + SpellName = spellName.Name; SpellMiscRecord _misc = data.Misc; if (_misc != null) @@ -90,10 +79,6 @@ namespace Game.Spells if (visuals != null) _visuals = visuals; - // sort all visuals so that the ones without a condition requirement are last on the list - foreach (var key in _visuals.Keys.ToList()) - _visuals[key] = _visuals[key].OrderByDescending(x => x.CasterPlayerConditionID).ToList(); - // SpellScalingEntry SpellScalingRecord _scaling = data.Scaling; if (_scaling != null) @@ -204,7 +189,7 @@ namespace Game.Spells } // SpellPowerEntry - PowerCosts = Global.DB2Mgr.GetSpellPowers(Id, Difficulty.None, out _hasPowerDifficultyData); + PowerCosts = data.Powers; // SpellReagentsEntry SpellReagentsRecord _reagents = data.Reagents; @@ -248,91 +233,53 @@ namespace Game.Spells _auraState = AuraStateType.None; } - public bool HasEffect(Difficulty difficulty, SpellEffectName effect) - { - var effects = GetEffectsForDifficulty(difficulty); - foreach (var eff in effects) - { - if (eff != null && eff.IsEffect(effect)) - return true; - } - - return false; - } - public bool HasEffect(SpellEffectName effect) { - foreach (var pair in _effects) - { - foreach (SpellEffectInfo eff in pair.Value) - { - if (eff != null && eff.IsEffect(effect)) - return true; - } + foreach (SpellEffectInfo eff in _effects.Values) + if (eff != null && eff.IsEffect(effect)) + return true; - } return false; } - public bool HasAura(Difficulty difficulty, AuraType aura) + public bool HasAura(AuraType aura) { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { + foreach (SpellEffectInfo effect in _effects.Values) if (effect != null && effect.IsAura(aura)) return true; - } - return false; - } - - public bool HasAreaAuraEffect(Difficulty difficulty) - { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { - if (effect != null && effect.IsAreaAuraEffect()) - return true; - } return false; } public bool HasAreaAuraEffect() { - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect != null && effect.IsAreaAuraEffect()) - return true; - } - } + foreach (SpellEffectInfo effect in _effects.Values) + if (effect != null && effect.IsAreaAuraEffect()) + return true; + return false; } public bool HasOnlyDamageEffects() { - foreach (var pair in _effects) + foreach (SpellEffectInfo effect in _effects.Values) { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect == null) - continue; + if (effect == null) + continue; - switch (effect.Effect) - { - case SpellEffectName.WeaponDamage: - case SpellEffectName.WeaponDamageNoschool: - case SpellEffectName.NormalizedWeaponDmg: - case SpellEffectName.WeaponPercentDamage: - case SpellEffectName.SchoolDamage: - case SpellEffectName.EnvironmentalDamage: - case SpellEffectName.HealthLeech: - case SpellEffectName.DamageFromMaxHealthPCT: - continue; - default: - return false; - } + switch (effect.Effect) + { + case SpellEffectName.WeaponDamage: + case SpellEffectName.WeaponDamageNoschool: + case SpellEffectName.NormalizedWeaponDmg: + case SpellEffectName.WeaponPercentDamage: + case SpellEffectName.SchoolDamage: + case SpellEffectName.EnvironmentalDamage: + case SpellEffectName.HealthLeech: + case SpellEffectName.DamageFromMaxHealthPCT: + continue; + default: + return false; } } @@ -341,8 +288,8 @@ namespace Game.Spells public bool IsExplicitDiscovery() { - SpellEffectInfo effect0 = GetEffect(Difficulty.None, 0); - SpellEffectInfo effect1 = GetEffect(Difficulty.None, 1); + SpellEffectInfo effect0 = GetEffect(0); + SpellEffectInfo effect1 = GetEffect(1); return ((effect0 != null && (effect0.Effect == SpellEffectName.CreateRandomItem || effect0.Effect == SpellEffectName.CreateLoot)) && effect1 != null && effect1.Effect == SpellEffectName.ScriptEffect) @@ -356,16 +303,15 @@ namespace Game.Spells public bool IsQuestTame() { - SpellEffectInfo effect0 = GetEffect(Difficulty.None, 0); - SpellEffectInfo effect1 = GetEffect(Difficulty.None, 1); + SpellEffectInfo effect0 = GetEffect(0); + SpellEffectInfo effect1 = GetEffect(1); return effect0 != null && effect1 != null && effect0.Effect == SpellEffectName.Threat && effect1.Effect == SpellEffectName.ApplyAura && effect1.ApplyAuraName == AuraType.Dummy; } - public bool IsProfession(Difficulty difficulty = Difficulty.None) + public bool IsProfession() { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect != null && effect.Effect == SpellEffectName.Skill) { @@ -378,25 +324,19 @@ namespace Game.Spells return false; } - public bool IsPrimaryProfession(Difficulty difficulty) + public bool IsPrimaryProfession() { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { + foreach (SpellEffectInfo effect in _effects.Values) if (effect != null && effect.Effect == SpellEffectName.Skill) - { - uint skill = (uint)effect.MiscValue; - - if (Global.SpellMgr.IsPrimaryProfessionSkill(skill)) + if (Global.SpellMgr.IsPrimaryProfessionSkill((uint)effect.MiscValue)) return true; - } - } + return false; } - public bool IsPrimaryProfessionFirstRank(Difficulty difficulty = Difficulty.None) + public bool IsPrimaryProfessionFirstRank() { - return IsPrimaryProfession(difficulty) && GetRank() == 1; + return IsPrimaryProfession() && GetRank() == 1; } public bool IsAbilityOfSkillType(SkillType skillType) @@ -410,26 +350,22 @@ namespace Game.Spells return false; } - public bool IsAffectingArea(Difficulty difficulty) + public bool IsAffectingArea() { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { + foreach (SpellEffectInfo effect in _effects.Values) if (effect != null && effect.IsEffect() && (effect.IsTargetingArea() || effect.IsEffect(SpellEffectName.PersistentAreaAura) || effect.IsAreaAuraEffect())) return true; - } + return false; } // checks if spell targets are selected from area, doesn't include spell effects in check (like area wide auras for example) - public bool IsTargetingArea(Difficulty difficulty) + public bool IsTargetingArea() { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { + foreach (SpellEffectInfo effect in _effects.Values) if (effect != null && effect.IsEffect() && effect.IsTargetingArea()) return true; - } + return false; } @@ -438,7 +374,7 @@ namespace Game.Spells return Convert.ToBoolean(GetExplicitTargetMask() & SpellCastTargetFlags.UnitMask); } - public bool NeedsToBeTriggeredByCaster(SpellInfo triggeringSpell, Difficulty difficulty) + public bool NeedsToBeTriggeredByCaster(SpellInfo triggeringSpell) { if (NeedsExplicitUnitTarget()) return true; @@ -446,8 +382,7 @@ namespace Game.Spells if (triggeringSpell.IsChanneled()) { SpellCastTargetFlags mask = 0; - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect != null && (effect.TargetA.GetTarget() != Targets.UnitCaster && effect.TargetA.GetTarget() != Targets.DestCaster && effect.TargetB.GetTarget() != Targets.UnitCaster && effect.TargetB.GetTarget() != Targets.DestCaster)) @@ -483,8 +418,7 @@ namespace Game.Spells return false; // All stance spells. if any better way, change it. - var effects = GetEffectsForDifficulty(Difficulty.None); - foreach (SpellEffectInfo effect in effects) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect == null) continue; @@ -550,8 +484,7 @@ namespace Game.Spells public bool IsGroupBuff() { - var effects = GetEffectsForDifficulty(Difficulty.None); - foreach (SpellEffectInfo effect in effects) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect == null) continue; @@ -704,7 +637,7 @@ namespace Game.Spells if (!IsAffectedBySpellMods()) return false; - SpellInfo affectSpell = Global.SpellMgr.GetSpellInfo(mod.spellId); + SpellInfo affectSpell = Global.SpellMgr.GetSpellInfo(mod.spellId, Difficulty); if (affectSpell == null) return false; @@ -1010,7 +943,7 @@ namespace Game.Spells // aura limitations if (player) { - foreach (SpellEffectInfo effect in GetEffectsForDifficulty(player.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect == null || !effect.IsAura()) continue; @@ -1184,7 +1117,7 @@ namespace Game.Spells return SpellCastResult.TargetAurastate; if (unitTarget.HasAuraType(AuraType.PreventResurrection)) - if (HasEffect(caster.GetMap().GetDifficultyID(), SpellEffectName.SelfResurrect) || HasEffect(caster.GetMap().GetDifficultyID(), SpellEffectName.Resurrect)) + if (HasEffect(SpellEffectName.SelfResurrect) || HasEffect(SpellEffectName.Resurrect)) return SpellCastResult.TargetCannotBeResurrected; if (HasAttribute(SpellAttr8.BattleResurrection)) @@ -1251,7 +1184,7 @@ namespace Game.Spells if (vehicle) { VehicleSeatFlags checkMask = 0; - foreach (SpellEffectInfo effect in GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect != null && effect.ApplyAuraName == AuraType.ModShapeshift) { @@ -1262,7 +1195,7 @@ namespace Game.Spells } } - if (HasAura(caster.GetMap().GetDifficultyID(), AuraType.Mounted)) + if (HasAura(AuraType.Mounted)) checkMask |= VehicleSeatFlags.CanCastMountSpell; if (checkMask == 0) @@ -1276,7 +1209,7 @@ namespace Game.Spells // Can only summon uncontrolled minions/guardians when on controlled vehicle if (vehicleSeat.HasSeatFlag(VehicleSeatFlags.CanControl | VehicleSeatFlags.Unk2)) { - foreach (SpellEffectInfo effect in GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect == null || effect.Effect != SpellEffectName.Summon) continue; @@ -1323,14 +1256,10 @@ namespace Game.Spells if (Mechanic != 0) mask |= (uint)(1 << (int)Mechanic); - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect != null && effect.IsEffect() && effect.Mechanic != 0) - mask |= (uint)(1 << (int)effect.Mechanic); - } - } + foreach (SpellEffectInfo effect in _effects.Values) + if (effect != null && effect.IsEffect() && effect.Mechanic != 0) + mask |= 1u << (int)effect.Mechanic; + return mask; } @@ -1340,14 +1269,10 @@ namespace Game.Spells if (Mechanic != 0) mask |= (uint)(1 << (int)Mechanic); - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect != null && effect.EffectIndex == effIndex && effect.IsEffect() && effect.Mechanic != 0) - mask |= (uint)(1 << (int)effect.Mechanic); - } - } + var effect = _effects.LookupByKey(effIndex); + if (effect != null && effect.IsEffect() && effect.Mechanic != 0) + mask |= 1u << (int)effect.Mechanic; + return mask; } @@ -1357,24 +1282,22 @@ namespace Game.Spells if (Mechanic != 0) mask |= (uint)(1 << (int)Mechanic); - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)) && effect.Mechanic != 0) - mask |= (uint)(1 << (int)effect.Mechanic); - } - } + foreach (SpellEffectInfo effect in _effects.Values) + if (effect != null && Convert.ToBoolean(effectMask & (1 << (int)effect.EffectIndex)) && effect.Mechanic != 0) + mask |= 1u << (int)effect.Mechanic; + return mask; } - public Mechanics GetEffectMechanic(uint effIndex, Difficulty difficulty) + public Mechanics GetEffectMechanic(uint effIndex) { - SpellEffectInfo effect = GetEffect(difficulty, effIndex); + SpellEffectInfo effect = GetEffect(effIndex); if (effect != null && effect.IsEffect() && effect.Mechanic != 0) return effect.Mechanic; + if (Mechanic != 0) return Mechanic; + return Mechanics.None; } @@ -1448,10 +1371,9 @@ namespace Game.Spells if (Convert.ToBoolean(GetSchoolMask() & SpellSchoolMask.Frost)) { - foreach (var pair in _effects) - foreach (SpellEffectInfo effect in pair.Value) - if (effect != null && (effect.IsAura(AuraType.ModStun) || effect.IsAura(AuraType.ModRoot))) - _auraState = AuraStateType.Frozen; + foreach (SpellEffectInfo effect in _effects.Values) + if (effect != null && (effect.IsAura(AuraType.ModStun) || effect.IsAura(AuraType.ModRoot))) + _auraState = AuraStateType.Frozen; } switch (Id) @@ -1483,27 +1405,25 @@ namespace Game.Spells { bool food = false; bool drink = false; - foreach (var pair in _effects) + foreach (SpellEffectInfo effect in _effects.Values) { - foreach (SpellEffectInfo effect in pair.Value) + if (effect == null || !effect.IsAura()) + continue; + + switch (effect.ApplyAuraName) { - if (effect == null || !effect.IsAura()) - continue; - switch (effect.ApplyAuraName) - { - // Food - case AuraType.ModRegen: - case AuraType.ObsModHealth: - food = true; - break; - // Drink - case AuraType.ModPowerRegen: - case AuraType.ObsModPower: - drink = true; - break; - default: - break; - } + // Food + case AuraType.ModRegen: + case AuraType.ObsModHealth: + food = true; + break; + // Drink + case AuraType.ModPowerRegen: + case AuraType.ObsModPower: + drink = true; + break; + default: + break; } } @@ -1541,7 +1461,8 @@ namespace Game.Spells // Arcane brillance and Arcane intelect (normal check fails because of flags difference) if (SpellFamilyFlags[0].HasAnyFlag(0x400u)) _spellSpecific = SpellSpecificType.MageArcaneBrillance; - SpellEffectInfo effect = GetEffect(Difficulty.None, 0); + + SpellEffectInfo effect = GetEffect(0); if (effect != null && SpellFamilyFlags[0].HasAnyFlag(0x1000000u) && effect.IsAura(AuraType.ModConfuse)) _spellSpecific = SpellSpecificType.MagePolymorph; @@ -1626,30 +1547,27 @@ namespace Game.Spells break; } - foreach (var pair in _effects) + foreach (SpellEffectInfo effect in _effects.Values) { - foreach (SpellEffectInfo effect in pair.Value) + if (effect != null && effect.Effect == SpellEffectName.ApplyAura) { - if (effect != null && effect.Effect == SpellEffectName.ApplyAura) + switch (effect.ApplyAuraName) { - switch (effect.ApplyAuraName) - { - case AuraType.ModCharm: - case AuraType.ModPossessPet: - case AuraType.ModPossess: - case AuraType.AoeCharm: - _spellSpecific = SpellSpecificType.Charm; - break; - case AuraType.TrackCreatures: - // @workaround For non-stacking tracking spells (We need generic solution) - if (Id == 30645) // Gas Cloud Tracking - _spellSpecific = SpellSpecificType.Normal; - break; - case AuraType.TrackResources: - case AuraType.TrackStealthed: - _spellSpecific = SpellSpecificType.Tracker; - break; - } + case AuraType.ModCharm: + case AuraType.ModPossessPet: + case AuraType.ModPossess: + case AuraType.AoeCharm: + _spellSpecific = SpellSpecificType.Charm; + break; + case AuraType.TrackCreatures: + // @workaround For non-stacking tracking spells (We need generic solution) + if (Id == 30645) // Gas Cloud Tracking + _spellSpecific = SpellSpecificType.Normal; + break; + case AuraType.TrackResources: + case AuraType.TrackStealthed: + _spellSpecific = SpellSpecificType.Tracker; + break; } } } @@ -1691,7 +1609,7 @@ namespace Game.Spells if (IsPositive()) return DiminishingGroup.None; - if (HasAura(Difficulty.None, AuraType.ModTaunt)) + if (HasAura(AuraType.ModTaunt)) return DiminishingGroup.Taunt; switch (Id) @@ -2374,16 +2292,13 @@ namespace Game.Spells _allowedMechanicMask |= immuneInfo.MechanicImmuneMask; }); - foreach (var effects in _effects) + foreach (SpellEffectInfo effect in _effects.Values) { - foreach (SpellEffectInfo effect in effects.Value) - { - if (effect == null) - continue; + if (effect == null) + continue; - loadImmunityInfoFn(effect); - } - } + loadImmunityInfoFn(effect); + } if (HasAttribute(SpellAttr5.UsableWhileStunned)) { @@ -2489,7 +2404,7 @@ namespace Game.Spells if (auraSpellInfo == null) return false; - foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effectInfo in _effects.Values) { if (effectInfo == null) continue; @@ -2515,7 +2430,7 @@ namespace Game.Spells return true; bool immuneToAllEffects = true; - foreach (SpellEffectInfo auraSpellEffectInfo in auraSpellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo auraSpellEffectInfo in auraSpellInfo.GetEffects()) { if (auraSpellEffectInfo == null) continue; @@ -2581,7 +2496,7 @@ namespace Game.Spells if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) return false; - foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effectInfo in _effects.Values) { if (effectInfo == null) continue; @@ -2716,13 +2631,13 @@ namespace Game.Spells return (castTime > 0) ? castTime : 0; } - public uint GetMaxTicks(Difficulty difficulty) + public uint GetMaxTicks() { int DotDuration = GetDuration(); if (DotDuration == 0) return 1; - foreach (SpellEffectInfo effect in GetEffectsForDifficulty(difficulty)) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect != null && effect.Effect == SpellEffectName.ApplyAura) { @@ -2761,129 +2676,89 @@ namespace Game.Spells { List costs = new List(); - var collector = new Action>(powers => + int healthCost = 0; + + foreach (SpellPowerRecord power in PowerCosts) { - int healthCost = 0; + if (power == null) + continue; - foreach (SpellPowerRecord power in powers) + if (power.RequiredAuraSpellID != 0 && !caster.HasAura(power.RequiredAuraSpellID)) + continue; + + // Spell drain all exist power on cast (Only paladin lay of Hands) + if (HasAttribute(SpellAttr1.DrainAllPower)) { - if (power.RequiredAuraSpellID != 0 && !caster.HasAura(power.RequiredAuraSpellID)) - continue; - - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (HasAttribute(SpellAttr1.DrainAllPower)) + // If power type - health drain all + if (power.PowerType == PowerType.Health) { - // If power type - health drain all - if (power.PowerType == PowerType.Health) - { - healthCost = (int)caster.GetHealth(); - continue; - } - // Else drain all power - if (power.PowerType < PowerType.Max) - { - SpellPowerCost cost = new SpellPowerCost(); - cost.Power = power.PowerType; - cost.Amount = caster.GetPower(cost.Power); - costs.Add(cost); - continue; - } - - Log.outError(LogFilter.Spells, "SpellInfo.GetCostDataList: Unknown power type '{0}' in spell {1}", power.PowerType, Id); + healthCost = (int)caster.GetHealth(); + continue; + } + // Else drain all power + if (power.PowerType < PowerType.Max) + { + SpellPowerCost cost = new SpellPowerCost(); + cost.Power = power.PowerType; + cost.Amount = caster.GetPower(cost.Power); + costs.Add(cost); continue; } - // Base powerCost - int powerCost = power.ManaCost; - // PCT cost from total amount - if (power.PowerCostPct != 0) + Log.outError(LogFilter.Spells, "SpellInfo.GetCostDataList: Unknown power type '{0}' in spell {1}", power.PowerType, Id); + continue; + } + + // Base powerCost + int powerCost = power.ManaCost; + // PCT cost from total amount + if (power.PowerCostPct != 0) + { + switch (power.PowerType) { - switch (power.PowerType) - { - // health as power used - case PowerType.Health: - powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostPct); - break; - case PowerType.Mana: - powerCost += (int)MathFunctions.CalculatePct(caster.GetCreateMana(), power.PowerCostPct); - break; - case PowerType.Rage: - case PowerType.Focus: - case PowerType.Energy: - powerCost += MathFunctions.CalculatePct(caster.GetMaxPower(power.PowerType), power.PowerCostPct); - break; - case PowerType.Runes: - case PowerType.RunicPower: - Log.outDebug(LogFilter.Spells, "GetCostDataList: Not implemented yet!"); - break; - default: - Log.outError(LogFilter.Spells, "GetCostDataList: Unknown power type '{0}' in spell {1}", power.PowerType, Id); - continue; - } + // health as power used + case PowerType.Health: + powerCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostPct); + break; + case PowerType.Mana: + powerCost += (int)MathFunctions.CalculatePct(caster.GetCreateMana(), power.PowerCostPct); + break; + case PowerType.Rage: + case PowerType.Focus: + case PowerType.Energy: + powerCost += MathFunctions.CalculatePct(caster.GetMaxPower(power.PowerType), power.PowerCostPct); + break; + case PowerType.Runes: + case PowerType.RunicPower: + Log.outDebug(LogFilter.Spells, "GetCostDataList: Not implemented yet!"); + break; + default: + Log.outError(LogFilter.Spells, "GetCostDataList: Unknown power type '{0}' in spell {1}", power.PowerType, Id); + continue; } + } - if (power.PowerCostMaxPct != 0) - healthCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostMaxPct); + if (power.PowerCostMaxPct != 0) + healthCost += (int)MathFunctions.CalculatePct(caster.GetMaxHealth(), power.PowerCostMaxPct); - if (power.PowerType != PowerType.Health) - { - // Flat mod from caster auras by spell school and power type - var auras = caster.GetAuraEffectsByType(AuraType.ModPowerCostSchool); - foreach (var eff in auras) - { - if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) - continue; + int optionalCost = (int)power.OptionalCost; + optionalCost += caster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff => + { + return aurEff.GetMiscValue() == (int)power.PowerType + && aurEff.IsAffectingSpell(this); + }); - if (!Convert.ToBoolean(eff.GetMiscValueB() & (1 << (int)power.PowerType))) - continue; + if (optionalCost != 0) + { + int remainingPower = caster.GetPower(power.PowerType) - powerCost; + powerCost += MathFunctions.RoundToInterval(ref remainingPower, 0, optionalCost); + } - powerCost += eff.GetAmount(); - } - } - - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if (HasAttribute(SpellAttr4.SpellVsExtendCost)) - { - uint speed = 0; - SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(caster.GetShapeshiftForm()); - if (ss != null) - speed = ss.CombatRoundTime; - else - { - WeaponAttackType slot = WeaponAttackType.BaseAttack; - if (HasAttribute(SpellAttr3.ReqOffhand)) - slot = WeaponAttackType.OffAttack; - - speed = caster.GetBaseAttackTime(slot); - } - - powerCost += (int)(speed / 100); - } - - // Apply cost mod by spell - Player modOwner = caster.GetSpellModOwner(); - if (modOwner) - { - if (power.OrderIndex == 0) - modOwner.ApplySpellMod(Id, SpellModOp.Cost, ref powerCost, spell); - else if (power.OrderIndex == 1) - modOwner.ApplySpellMod(Id, SpellModOp.SpellCost2, ref powerCost, spell); - } - - if (!caster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0) - { - if (HasAttribute(SpellAttr0.LevelDamageCalculation)) - { - GtNpcManaCostScalerRecord spellScaler = CliDB.NpcManaCostScalerGameTable.GetRow(SpellLevel); - GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(caster.GetLevel()); - if (spellScaler != null && casterScaler != null) - powerCost *= (int)(casterScaler.Scaler / spellScaler.Scaler); - } - } - - // PCT mod from user auras by spell school and power type - var aurasPct = caster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct); - foreach (var eff in aurasPct) + if (power.PowerType != PowerType.Health) + { + // Flat mod from caster auras by spell school and power type + var auras = caster.GetAuraEffectsByType(AuraType.ModPowerCostSchool); + foreach (var eff in auras) { if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) continue; @@ -2891,48 +2766,96 @@ namespace Game.Spells if (!Convert.ToBoolean(eff.GetMiscValueB() & (1 << (int)power.PowerType))) continue; - powerCost += MathFunctions.CalculatePct(powerCost, eff.GetAmount()); - } - - if (power.PowerType == PowerType.Health) - { - healthCost += powerCost; - continue; - } - - bool found = false; - for (var i = 0; i < costs.Count; ++i) - { - var cost = costs[i]; - if (cost.Power == power.PowerType) - { - cost.Amount += powerCost; - found = true; - } - } - - if (!found) - { - SpellPowerCost cost = new SpellPowerCost(); - cost.Power = power.PowerType; - cost.Amount = powerCost; - costs.Add(cost); + powerCost += eff.GetAmount(); } } - if (healthCost > 0) + // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) + if (HasAttribute(SpellAttr4.SpellVsExtendCost)) + { + uint speed = 0; + SpellShapeshiftFormRecord ss = CliDB.SpellShapeshiftFormStorage.LookupByKey(caster.GetShapeshiftForm()); + if (ss != null) + speed = ss.CombatRoundTime; + else + { + WeaponAttackType slot = WeaponAttackType.BaseAttack; + if (HasAttribute(SpellAttr3.ReqOffhand)) + slot = WeaponAttackType.OffAttack; + + speed = caster.GetBaseAttackTime(slot); + } + + powerCost += (int)(speed / 100); + } + + // Apply cost mod by spell + Player modOwner = caster.GetSpellModOwner(); + if (modOwner) + { + if (power.OrderIndex == 0) + modOwner.ApplySpellMod(Id, SpellModOp.Cost, ref powerCost, spell); + else if (power.OrderIndex == 1) + modOwner.ApplySpellMod(Id, SpellModOp.SpellCost2, ref powerCost, spell); + } + + if (!caster.IsControlledByPlayer() && MathFunctions.fuzzyEq(power.PowerCostPct, 0.0f) && SpellLevel != 0) + { + if (HasAttribute(SpellAttr0.LevelDamageCalculation)) + { + GtNpcManaCostScalerRecord spellScaler = CliDB.NpcManaCostScalerGameTable.GetRow(SpellLevel); + GtNpcManaCostScalerRecord casterScaler = CliDB.NpcManaCostScalerGameTable.GetRow(caster.GetLevel()); + if (spellScaler != null && casterScaler != null) + powerCost *= (int)(casterScaler.Scaler / spellScaler.Scaler); + } + } + + // PCT mod from user auras by spell school and power type + var aurasPct = caster.GetAuraEffectsByType(AuraType.ModPowerCostSchoolPct); + foreach (var eff in aurasPct) + { + if (!Convert.ToBoolean(eff.GetMiscValue() & (int)schoolMask)) + continue; + + if (!Convert.ToBoolean(eff.GetMiscValueB() & (1 << (int)power.PowerType))) + continue; + + powerCost += MathFunctions.CalculatePct(powerCost, eff.GetAmount()); + } + + if (power.PowerType == PowerType.Health) + { + healthCost += powerCost; + continue; + } + + bool found = false; + for (var i = 0; i < costs.Count; ++i) + { + var cost = costs[i]; + if (cost.Power == power.PowerType) + { + cost.Amount += powerCost; + found = true; + } + } + + if (!found) { SpellPowerCost cost = new SpellPowerCost(); - cost.Power = PowerType.Health; - cost.Amount = healthCost; + cost.Power = power.PowerType; + cost.Amount = powerCost; costs.Add(cost); } - }); + } - if (!_hasPowerDifficultyData) // optimization - use static data for 99.5% cases (4753 of 4772 in build 6.1.0.19702) - collector(PowerCosts); - else - collector(Global.DB2Mgr.GetSpellPowers(Id, caster.GetMap().GetDifficultyID())); + if (healthCost > 0) + { + SpellPowerCost cost = new SpellPowerCost(); + cost.Power = PowerType.Health; + cost.Amount = healthCost; + costs.Add(cost); + } return costs; } @@ -3110,7 +3033,7 @@ namespace Game.Spells return this; bool needRankSelection = false; - foreach (SpellEffectInfo effect in GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in _effects.Values) { if (effect != null && IsPositiveEffect(effect.EffectIndex) && (effect.Effect == SpellEffectName.ApplyAura || @@ -3165,36 +3088,12 @@ namespace Game.Spells public uint GetSpellXSpellVisualId(Unit caster = null) { - if (caster) + foreach (SpellXSpellVisualRecord visual in _visuals) { - Difficulty difficulty = caster.GetMap().GetDifficultyID(); - DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficulty); - while (difficultyEntry != null) - { - var visualList = _visuals.LookupByKey(difficulty); - if (visualList != null) - { - foreach (SpellXSpellVisualRecord visual in visualList) - { - PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(visual.CasterPlayerConditionID); - if (playerCondition == null || (caster.IsTypeId(TypeId.Player) && ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), playerCondition))) - return visual.Id; - } - } - difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); - } - } - - var defaultList = _visuals.LookupByKey(Difficulty.None); - if (defaultList != null) - { - foreach (var visual in defaultList) - { - PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(visual.CasterPlayerConditionID); - if (playerCondition == null || (caster && caster.IsTypeId(TypeId.Player) && ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), playerCondition))) - return visual.Id; - } + PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(visual.CasterPlayerConditionID); + if (playerCondition == null || (caster && caster.GetTypeId() == TypeId.Player && ConditionManager.IsPlayerMeetingCondition(caster.ToPlayer(), playerCondition))) + return visual.Id; } return 0; @@ -3220,28 +3119,26 @@ namespace Game.Spells bool dstSet = false; SpellCastTargetFlags targetMask = targets; // prepare target mask using effect target entries - foreach (var pair in _effects) + foreach (SpellEffectInfo effect in _effects.Values) { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect == null || !effect.IsEffect()) - continue; + if (effect == null || !effect.IsEffect()) + continue; - targetMask |= effect.TargetA.GetExplicitTargetMask(srcSet, dstSet); - targetMask |= effect.TargetB.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect.TargetA.GetExplicitTargetMask(srcSet, dstSet); + targetMask |= effect.TargetB.GetExplicitTargetMask(srcSet, dstSet); - // add explicit target flags based on spell effects which have SpellEffectImplicitTargetTypes.Explicit and no valid target provided - if (effect.GetImplicitTargetType() != SpellEffectImplicitTargetTypes.Explicit) - continue; + // add explicit target flags based on spell effects which have SpellEffectImplicitTargetTypes.Explicit and no valid target provided + if (effect.GetImplicitTargetType() != SpellEffectImplicitTargetTypes.Explicit) + continue; - // extend explicit target mask only if valid targets for effect could not be provided by target types - SpellCastTargetFlags effectTargetMask = effect.GetMissingTargetMask(srcSet, dstSet, targetMask); + // extend explicit target mask only if valid targets for effect could not be provided by target types + SpellCastTargetFlags effectTargetMask = effect.GetMissingTargetMask(srcSet, dstSet, targetMask); - // don't add explicit object/dest flags when spell has no max range - if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) - effectTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.CorpseMask | SpellCastTargetFlags.DestLocation); - targetMask |= effectTargetMask; - } + // don't add explicit object/dest flags when spell has no max range + if (GetMaxRange(true) == 0.0f && GetMaxRange(false) == 0.0f) + effectTargetMask &= ~(SpellCastTargetFlags.UnitMask | SpellCastTargetFlags.Gameobject | SpellCastTargetFlags.CorpseMask | SpellCastTargetFlags.DestLocation); + + targetMask |= effectTargetMask; } ExplicitTargetMask = (uint)targetMask; @@ -3300,203 +3197,185 @@ namespace Game.Spells return true; // Special case: effects which determine positivity of whole spell - foreach (var pair in _effects) + foreach (SpellEffectInfo effectInfo in _effects.Values) + if (effectInfo != null && effectInfo.IsAura() && effectInfo.ApplyAuraName == AuraType.ModStealth) + return true; + + SpellEffectInfo effect = GetEffect(effIndex); + if (effect != null) { - foreach (SpellEffectInfo effect in pair.Value) + switch (effect.Effect) { - if (effect != null && effect.IsAura() && effect.ApplyAuraName == AuraType.ModStealth) + case SpellEffectName.Dummy: + // some explicitly required dummy effect sets + switch (Id) + { + case 28441: + return false; // AB Effect 000 + } + break; + // always positive effects (check before target checks that provided non-positive result in some case for positive effects) + case SpellEffectName.Heal: + case SpellEffectName.LearnSpell: + case SpellEffectName.SkillStep: + case SpellEffectName.HealPct: + case SpellEffectName.EnergizePct: return true; - } - } + case SpellEffectName.ApplyAreaAuraEnemy: + return false; - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect == null || effect.EffectIndex != effIndex) - continue; - - switch (effect.Effect) - { - case SpellEffectName.Dummy: - // some explicitly required dummy effect sets - switch (Id) + // non-positive aura use + case SpellEffectName.ApplyAura: + case SpellEffectName.ApplyAreaAuraFriend: + { + switch (effect.ApplyAuraName) { - case 28441: - return false; // AB Effect 000 - } - break; - // always positive effects (check before target checks that provided non-positive result in some case for positive effects) - case SpellEffectName.Heal: - case SpellEffectName.LearnSpell: - case SpellEffectName.SkillStep: - case SpellEffectName.HealPct: - case SpellEffectName.EnergizePct: - return true; - case SpellEffectName.ApplyAreaAuraEnemy: - return false; - - // non-positive aura use - case SpellEffectName.ApplyAura: - case SpellEffectName.ApplyAreaAuraFriend: - { - switch (effect.ApplyAuraName) - { - case AuraType.ModDamageDone: // dependent from bas point sign (negative . negative) - case AuraType.ModStat: - case AuraType.ModSkill: - case AuraType.ModSkill2: - case AuraType.ModDodgePercent: - case AuraType.ModHealingPct: - case AuraType.ModHealingDone: - case AuraType.ModHealingDonePercent: - if (effect.CalcValue() < 0) - return false; - break; - case AuraType.ModDamageTaken: // dependent from bas point sign (positive . negative) - if (effect.CalcValue() > 0) - return false; - break; - case AuraType.ModCritPct: - case AuraType.ModSpellCritChance: - if (effect.CalcValue() > 0) - return true; // some expected positive spells have SPELL_ATTR1_NEGATIVE - break; - case AuraType.AddTargetTrigger: - return true; - case AuraType.PeriodicTriggerSpellWithValue: - case AuraType.PeriodicTriggerSpell: - if (!deep) + case AuraType.ModDamageDone: // dependent from bas point sign (negative . negative) + case AuraType.ModStat: + case AuraType.ModSkill: + case AuraType.ModSkill2: + case AuraType.ModDodgePercent: + case AuraType.ModHealingPct: + case AuraType.ModHealingDone: + case AuraType.ModHealingDonePercent: + if (effect.CalcValue() < 0) + return false; + break; + case AuraType.ModDamageTaken: // dependent from bas point sign (positive . negative) + if (effect.CalcValue() > 0) + return false; + break; + case AuraType.ModCritPct: + case AuraType.ModSpellCritChance: + if (effect.CalcValue() > 0) + return true; // some expected positive spells have SPELL_ATTR1_NEGATIVE + break; + case AuraType.AddTargetTrigger: + return true; + case AuraType.PeriodicTriggerSpellWithValue: + case AuraType.PeriodicTriggerSpell: + if (!deep) + { + var spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty); + if (spellTriggeredProto != null) { - var spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); - if (spellTriggeredProto != null) + // negative targets of main spell return early + foreach (SpellEffectInfo eff in spellTriggeredProto._effects.Values) { - // negative targets of main spell return early - foreach (var pair2 in spellTriggeredProto._effects) + if (eff == null || eff.Effect == 0) + continue; + // if non-positive trigger cast targeted to positive target this main cast is non-positive + // this will place this spell auras as debuffs + if (_IsPositiveTarget(eff.TargetA.GetTarget(), eff.TargetB.GetTarget()) && !spellTriggeredProto._IsPositiveEffect(eff.EffectIndex, true)) + return false; + } + } + } + break; + case AuraType.ProcTriggerSpell: + // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example) + break; + case AuraType.ModStun: //have positive and negative spells, we can't sort its correctly at this moment. + bool more = false; + foreach (SpellEffectInfo eff in _effects.Values) + { + if (eff != null && eff.EffectIndex != 0) + { + more = true; + break; + } + } + + if (effIndex == 0 && !more) + return false; // but all single stun aura spells is negative + break; + case AuraType.ModPacifySilence: + if (Id == 24740) // Wisp Costume + return true; + return false; + case AuraType.ModRoot: + case AuraType.ModRoot2: + case AuraType.ModSilence: + case AuraType.Ghost: + case AuraType.PeriodicLeech: + case AuraType.ModStalked: + case AuraType.PeriodicDamagePercent: + case AuraType.PreventResurrection: + case AuraType.Empathy: + return false; + case AuraType.PeriodicDamage: // used in positive spells also. + // part of negative spell if casted at self (prevent cancel) + if (effect.TargetA.GetTarget() == Targets.UnitCaster) + return false; + break; + case AuraType.ModDecreaseSpeed: // used in positive spells also + // part of positive spell if casted at self + if (effect.TargetA.GetTarget() != Targets.UnitCaster) + return false; + // but not this if this first effect (didn't find better check) + if (HasAttribute(SpellAttr0.Negative1) && effIndex == 0) + return false; + break; + case AuraType.MechanicImmunity: + { + // non-positive immunities + switch ((Mechanics)effect.MiscValue) + { + case Mechanics.Bandage: + case Mechanics.Shield: + case Mechanics.Mount: + case Mechanics.Invulnerability: + return false; + } + break; + } + case AuraType.AddFlatModifier: // mods + case AuraType.AddPctModifier: + { + // non-positive mods + switch ((SpellModOp)effect.MiscValue) + { + case SpellModOp.Cost: // dependent from bas point sign (negative . positive) + if (effect.CalcValue() > 0) { - foreach (SpellEffectInfo eff in pair2.Value) + if (!deep) { - if (eff == null || eff.Effect == 0) - continue; - // if non-positive trigger cast targeted to positive target this main cast is non-positive - // this will place this spell auras as debuffs - if (_IsPositiveTarget(eff.TargetA.GetTarget(), eff.TargetB.GetTarget()) && !spellTriggeredProto._IsPositiveEffect(eff.EffectIndex, true)) + bool negative = true; + for (uint i = 0; i < SpellConst.MaxEffects; ++i) + { + if (i != effIndex) + { + if (_IsPositiveEffect(i, true)) + { + negative = false; + break; + } + } + } + if (negative) return false; } } - } + break; } break; - case AuraType.ProcTriggerSpell: - // many positive auras have negative triggered spells at damage for example and this not make it negative (it can be canceled for example) - break; - case AuraType.ModStun: //have positive and negative spells, we can't sort its correctly at this moment. - bool more = false; - foreach (var pair2 in _effects) - { - foreach (SpellEffectInfo eff in pair2.Value) - { - if (eff != null && eff.EffectIndex != 0) - { - more = true; - break; - } - } - } - - if (effIndex == 0 && !more) - return false; // but all single stun aura spells is negative - break; - case AuraType.ModPacifySilence: - if (Id == 24740) // Wisp Costume - return true; - return false; - case AuraType.ModRoot: - case AuraType.ModRoot2: - case AuraType.ModSilence: - case AuraType.Ghost: - case AuraType.PeriodicLeech: - case AuraType.ModStalked: - case AuraType.PeriodicDamagePercent: - case AuraType.PreventResurrection: - case AuraType.Empathy: - return false; - case AuraType.PeriodicDamage: // used in positive spells also. - // part of negative spell if casted at self (prevent cancel) - if (effect.TargetA.GetTarget() == Targets.UnitCaster) - return false; - break; - case AuraType.ModDecreaseSpeed: // used in positive spells also - // part of positive spell if casted at self - if (effect.TargetA.GetTarget() != Targets.UnitCaster) - return false; - // but not this if this first effect (didn't find better check) - if (HasAttribute(SpellAttr0.Negative1) && effIndex == 0) - return false; - break; - case AuraType.MechanicImmunity: - { - // non-positive immunities - switch ((Mechanics)effect.MiscValue) - { - case Mechanics.Bandage: - case Mechanics.Shield: - case Mechanics.Mount: - case Mechanics.Invulnerability: - return false; - } - break; - } - case AuraType.AddFlatModifier: // mods - case AuraType.AddPctModifier: - { - // non-positive mods - switch ((SpellModOp)effect.MiscValue) - { - case SpellModOp.Cost: // dependent from bas point sign (negative . positive) - if (effect.CalcValue() > 0) - { - if (!deep) - { - bool negative = true; - for (uint i = 0; i < SpellConst.MaxEffects; ++i) - { - if (i != effIndex) - { - if (_IsPositiveEffect(i, true)) - { - negative = false; - break; - } - } - } - if (negative) - return false; - } - } - break; - } - break; - } - } - break; + } } - } + break; + } + } + // non-positive targets + if (!_IsPositiveTarget(effect.TargetA.GetTarget(), effect.TargetB.GetTarget())) + return false; - - // non-positive targets - if (!_IsPositiveTarget(effect.TargetA.GetTarget(), effect.TargetB.GetTarget())) - return false; - - // negative spell if triggered spell is negative - if (!deep && effect.ApplyAuraName == 0 && effect.TriggerSpell != 0) - { - SpellInfo spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); - if (spellTriggeredProto != null) - if (!spellTriggeredProto._IsPositiveSpell()) - return false; - } + // negative spell if triggered spell is negative + if (!deep && effect.ApplyAuraName == 0 && effect.TriggerSpell != 0) + { + SpellInfo spellTriggeredProto = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty); + if (spellTriggeredProto != null) + if (!spellTriggeredProto._IsPositiveSpell()) + return false; } } // ok, positive @@ -3519,13 +3398,13 @@ namespace Game.Spells switch (targetA) { case Targets.UnitNearbyEnemy: - case Targets.UnitEnemy: + case Targets.UnitTargetEnemy: case Targets.UnitSrcAreaEnemy: case Targets.UnitDestAreaEnemy: case Targets.UnitConeEnemy24: case Targets.UnitConeEnemy104: case Targets.DestDynobjEnemy: - case Targets.DestEnemy: + case Targets.DestTargetEnemy: return false; default: break; @@ -3538,21 +3417,19 @@ namespace Game.Spells public void _UnloadImplicitTargetConditionLists() { // find the same instances of ConditionList and delete them. - foreach (var pair in _effects) + var effectList = _effects.Values.ToList(); + for (int i = 0; i < effectList.Count; ++i) { - for (uint i = 0; i < pair.Value.Length; ++i) - { - SpellEffectInfo effect = pair.Value[i]; - if (effect == null) - continue; - + SpellEffectInfo effect = effectList[i]; + if (effect != null) + { var cur = effect.ImplicitTargetConditions; if (cur == null) continue; - for (var j = i; j < pair.Value.Length; ++j) + for (var j = i; j < effectList.Count; ++j) { - SpellEffectInfo eff = pair.Value[j]; + SpellEffectInfo eff = effectList[j]; if (eff != null && eff.ImplicitTargetConditions == cur) eff.ImplicitTargetConditions = null; } @@ -3594,90 +3471,16 @@ namespace Game.Spells return CategoryId; } - public SpellEffectInfo[] GetEffectsForDifficulty(Difficulty difficulty) - { - SpellEffectInfo[] effList = new SpellEffectInfo[SpellConst.MaxEffects]; + public ICollection GetEffects() { return _effects.Values; } - // downscale difficulty if original was not found - DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficulty); - while (difficultyEntry != null) - { - var effectArray = _effects.LookupByKey(difficulty); - if (effectArray != null) - { - foreach (SpellEffectInfo effect in effectArray) - { - if (effect == null) - continue; - - if (effList[effect.EffectIndex] == null) - effList[effect.EffectIndex] = effect; - } - } - - difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); - } - - // DIFFICULTY_NONE effects are the default effects, always active if current difficulty's effects don't overwrite - var effects = _effects.LookupByKey(Difficulty.None); - if (effects != null) - { - foreach (SpellEffectInfo effect in effects) - { - if (effect == null) - continue; - - if (effList[effect.EffectIndex] == null) - effList[effect.EffectIndex] = effect; - } - } - - return effList; - } - - public SpellEffectInfo GetEffect(uint index) { return GetEffect(Difficulty.None, index); } - public SpellEffectInfo GetEffect(Difficulty difficulty, uint index) - { - DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficulty); - while (difficultyEntry != null) - { - var effectArray = _effects.LookupByKey(difficulty); - if (effectArray != null) - if (effectArray.Length > index && effectArray[index] != null) - return effectArray[index]; - - difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); - } - - var spellEffectInfos = _effects.LookupByKey(Difficulty.None); - if (spellEffectInfos != null) - if (spellEffectInfos.Length > index) - return spellEffectInfos[index]; - - return null; - } + public SpellEffectInfo GetEffect(uint index) { return _effects.LookupByKey(index); } public bool HasTargetType(Targets target) { - foreach (var pair in _effects) - { - foreach (SpellEffectInfo effect in pair.Value) - { - if (effect != null && (effect.TargetA.GetTarget() == target || effect.TargetB.GetTarget() == target)) - return true; - } - } - return false; - } - - public bool HasTargetType(Difficulty difficulty, Targets target) - { - var effects = GetEffectsForDifficulty(difficulty); - foreach (SpellEffectInfo effect in effects) - { + foreach (SpellEffectInfo effect in _effects.Values) if (effect != null && (effect.TargetA.GetTarget() == target || effect.TargetB.GetTarget() == target)) return true; - } + return false; } @@ -3705,8 +3508,9 @@ namespace Game.Spells #region Fields - public uint Id; - uint CategoryId; + public uint Id { get; set; } + public Difficulty Difficulty { get; set; } + public uint CategoryId { get; set; } public DispelType Dispel { get; set; } public Mechanics Mechanic { get; set; } public SpellAttr0 Attributes { get; set; } @@ -3756,7 +3560,7 @@ namespace Game.Spells public uint BaseLevel { get; set; } public uint SpellLevel { get; set; } public SpellDurationRecord DurationEntry { get; set; } - public List PowerCosts = new List(); + public SpellPowerRecord[] PowerCosts = new SpellPowerRecord[SpellConst.MaxPowersPerSpell]; public uint RangeIndex { get; set; } public SpellRangeRecord RangeEntry { get; set; } public float Speed { get; set; } @@ -3789,8 +3593,8 @@ namespace Game.Spells public uint ExplicitTargetMask { get; set; } public SpellChainNode ChainEntry { get; set; } - internal Dictionary _effects; - MultiMap _visuals = new MultiMap(); + Dictionary _effects = new Dictionary(); + List _visuals = new List(); bool _hasPowerDifficultyData; SpellSpecificType _spellSpecific; AuraStateType _auraState; @@ -3810,44 +3614,35 @@ namespace Game.Spells public class SpellEffectInfo { - public SpellEffectInfo(SpellInfo spellInfo, uint effIndex, SpellEffectRecord _effect) + public SpellEffectInfo(SpellInfo spellInfo, SpellEffectRecord effect) { _spellInfo = spellInfo; - EffectIndex = effIndex; - - TargetA = new SpellImplicitTargetInfo(); - TargetB = new SpellImplicitTargetInfo(); - SpellClassMask = new FlagArray128(); - - if (_effect != null) - { - EffectIndex = _effect.EffectIndex; - Effect = (SpellEffectName)_effect.Effect; - ApplyAuraName = (AuraType)_effect.EffectAura; - ApplyAuraPeriod = _effect.EffectAuraPeriod; - RealPointsPerLevel = _effect.EffectRealPointsPerLevel; - BasePoints = (int)_effect.EffectBasePoints; - PointsPerResource = _effect.EffectPointsPerResource; - Amplitude = _effect.EffectAmplitude; - ChainAmplitude = _effect.EffectChainAmplitude; - BonusCoefficient = _effect.EffectBonusCoefficient; - MiscValue = _effect.EffectMiscValue[0]; - MiscValueB = _effect.EffectMiscValue[1]; - Mechanic = (Mechanics)_effect.EffectMechanic; - PositionFacing = _effect.EffectPosFacing; - TargetA = new SpellImplicitTargetInfo((Targets)_effect.ImplicitTarget[0]); - TargetB = new SpellImplicitTargetInfo((Targets)_effect.ImplicitTarget[1]); - RadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(_effect.EffectRadiusIndex[0]); - MaxRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(_effect.EffectRadiusIndex[1]); - ChainTargets = _effect.EffectChainTargets; - ItemType = _effect.EffectItemType; - TriggerSpell = _effect.EffectTriggerSpell; - SpellClassMask = _effect.EffectSpellClassMask; - BonusCoefficientFromAP = _effect.BonusCoefficientFromAP; - Scaling.Coefficient = _effect.Coefficient; - Scaling.Variance = _effect.Variance; - Scaling.ResourceCoefficient = _effect.ResourceCoefficient; - } + EffectIndex = effect.EffectIndex; + Effect = (SpellEffectName)effect.Effect; + ApplyAuraName = (AuraType)effect.EffectAura; + ApplyAuraPeriod = effect.EffectAuraPeriod; + RealPointsPerLevel = effect.EffectRealPointsPerLevel; + BasePoints = (int)effect.EffectBasePoints; + PointsPerResource = effect.EffectPointsPerResource; + Amplitude = effect.EffectAmplitude; + ChainAmplitude = effect.EffectChainAmplitude; + BonusCoefficient = effect.EffectBonusCoefficient; + MiscValue = effect.EffectMiscValue[0]; + MiscValueB = effect.EffectMiscValue[1]; + Mechanic = (Mechanics)effect.EffectMechanic; + PositionFacing = effect.EffectPosFacing; + TargetA = new SpellImplicitTargetInfo((Targets)effect.ImplicitTarget[0]); + TargetB = new SpellImplicitTargetInfo((Targets)effect.ImplicitTarget[1]); + RadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(effect.EffectRadiusIndex[0]); + MaxRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(effect.EffectRadiusIndex[1]); + ChainTargets = effect.EffectChainTargets; + ItemType = effect.EffectItemType; + TriggerSpell = effect.EffectTriggerSpell; + SpellClassMask = effect.EffectSpellClassMask; + BonusCoefficientFromAP = effect.BonusCoefficientFromAP; + Scaling.Coefficient = effect.Coefficient; + Scaling.Variance = effect.Variance; + Scaling.ResourceCoefficient = effect.ResourceCoefficient; ImplicitTargetConditions = null; @@ -4612,7 +4407,7 @@ namespace Game.Spells case Targets.UnitCasterAreaParty: case Targets.UnitSrcAreaAlly: case Targets.UnitSrcAreaParty: - case Targets.UnitLastAreaParty: + case Targets.UnitLastTargetAreaParty: case Targets.GameobjectSrcArea: case Targets.UnitCasterAreaRaid: case Targets.CorpseSrcAreaEnemy: diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index 57ba064d5..a076cfa06 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -104,10 +104,10 @@ namespace Game.Entities if (spellInfo == null) return false; - bool need_check_reagents = false; + bool needCheckReagents = false; // check effects - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -150,12 +150,12 @@ namespace Game.Entities return false; } - need_check_reagents = true; + needCheckReagents = true; break; } case SpellEffectName.LearnSpell: { - SpellInfo spellInfo2 = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo spellInfo2 = GetSpellInfo(effect.TriggerSpell, Difficulty.None); if (!IsSpellValid(spellInfo2, player, msg)) { if (msg) @@ -172,7 +172,7 @@ namespace Game.Entities } } - if (need_check_reagents) + if (needCheckReagents) { for (int j = 0; j < SpellConst.MaxReagents; ++j) { @@ -444,9 +444,26 @@ namespace Game.Entities return SpellGroupStackRule.Default; } - public SpellProcEntry GetSpellProcEntry(uint spellId) + public SpellProcEntry GetSpellProcEntry(SpellInfo spellInfo) { - return mSpellProcMap.LookupByKey(spellId); + SpellProcEntry procEntry = mSpellProcMap.LookupByKey((spellInfo.Id, spellInfo.Difficulty)); + if (procEntry != null) + return procEntry; + + DifficultyRecord difficulty = CliDB.DifficultyStorage.LookupByKey(spellInfo.Difficulty); + if (difficulty != null) + { + do + { + procEntry = mSpellProcMap.LookupByKey((spellInfo.Id, difficulty.FallbackDifficultyID)); + if (procEntry != null) + return procEntry; + + difficulty = CliDB.DifficultyStorage.LookupByKey(difficulty.FallbackDifficultyID); + } while (difficulty != null); + } + + return null; } public static bool CanSpellTriggerProcOnEvent(SpellProcEntry procEntry, ProcEventInfo eventInfo) @@ -622,10 +639,52 @@ namespace Game.Entities return mSpellAreaForQuestAreaMap.LookupByKey(Tuple.Create(area_id, quest_id)); } + public SpellInfo GetSpellInfo(uint spellId, Difficulty difficulty) + { + var list = mSpellInfoMap.LookupByKey(spellId); + + var index = list.FindIndex(spellInfo => spellInfo.Difficulty == difficulty); + if (index != -1) + return list[index]; + + DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficulty); + if (difficultyEntry != null) + { + do + { + index = list.FindIndex(spellInfo => spellInfo.Difficulty == (Difficulty)difficultyEntry.FallbackDifficultyID); + if (index != -1) + return list[index]; + + difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); + } while (difficultyEntry != null); + } + + return null; + } + + List _GetSpellInfo(uint spellId) + { + return mSpellInfoMap.LookupByKey(spellId); + } + + public void ForEachSpellInfo(Action callback) + { + foreach (SpellInfo spellInfo in mSpellInfoMap.Values) + callback(spellInfo); + } + + public void ForEachSpellInfoDifficulty(uint spellId, Action callback) + { + foreach (SpellInfo spellInfo in _GetSpellInfo(spellId)) + callback(spellInfo); + } + void UnloadSpellInfoChains() { - foreach (var chain in mSpellChains) - mSpellInfoMap[chain.Key].ChainEntry = null; + foreach (var pair in mSpellChains) + foreach (SpellInfo spellInfo in _GetSpellInfo(pair.Key)) + spellInfo.ChainEntry = null; mSpellChains.Clear(); } @@ -642,7 +701,7 @@ namespace Game.Entities if (skillAbility.SupercedesSpell == 0) continue; - if (!HasSpellInfo(skillAbility.SupercedesSpell) || !HasSpellInfo(skillAbility.Spell)) + if (!HasSpellInfo(skillAbility.SupercedesSpell, Difficulty.None) || !HasSpellInfo(skillAbility.Spell, Difficulty.None)) continue; chains[skillAbility.SupercedesSpell] = skillAbility.Spell; @@ -655,8 +714,8 @@ namespace Game.Entities if (hasPrev.Contains(pair.Key)) continue; - SpellInfo first = GetSpellInfo(pair.Key); - SpellInfo next = GetSpellInfo(pair.Value); + SpellInfo first = GetSpellInfo(pair.Key, Difficulty.None); + SpellInfo next = GetSpellInfo(pair.Value, Difficulty.None); if (!mSpellChains.ContainsKey(pair.Key)) mSpellChains[pair.Key] = new SpellChainNode(); @@ -666,7 +725,8 @@ namespace Game.Entities mSpellChains[pair.Key].next = next; mSpellChains[pair.Key].last = next; mSpellChains[pair.Key].rank = 1; - mSpellInfoMap[pair.Key].ChainEntry = mSpellChains[pair.Key]; + foreach (SpellInfo difficultyInfo in _GetSpellInfo(pair.Key)) + difficultyInfo.ChainEntry = mSpellChains[pair.Key]; if (!mSpellChains.ContainsKey(pair.Value)) mSpellChains[pair.Value] = new SpellChainNode(); @@ -676,14 +736,15 @@ namespace Game.Entities mSpellChains[pair.Value].next = null; mSpellChains[pair.Value].last = next; mSpellChains[pair.Value].rank = 2; - mSpellInfoMap[pair.Value].ChainEntry = mSpellChains[pair.Value]; + foreach (SpellInfo difficultyInfo in _GetSpellInfo(pair.Value)) + difficultyInfo.ChainEntry = mSpellChains[pair.Value]; byte rank = 3; var nextPair = chains.Find(pair.Value); while (nextPair.Key != 0) { - SpellInfo prev = GetSpellInfo(nextPair.Key); // already checked in previous iteration (or above, in case this is the first one) - SpellInfo last = GetSpellInfo(nextPair.Value); + SpellInfo prev = GetSpellInfo(nextPair.Key, Difficulty.None); // already checked in previous iteration (or above, in case this is the first one) + SpellInfo last = GetSpellInfo(nextPair.Value, Difficulty.None); if (last == null) break; @@ -700,7 +761,8 @@ namespace Game.Entities mSpellChains[nextPair.Value].next = null; mSpellChains[nextPair.Value].last = last; mSpellChains[nextPair.Value].rank = rank++; - mSpellInfoMap[nextPair.Value].ChainEntry = mSpellChains[nextPair.Value]; + foreach (SpellInfo difficultyInfo in _GetSpellInfo(nextPair.Value)) + difficultyInfo.ChainEntry = mSpellChains[nextPair.Value]; // fill 'last' do @@ -725,7 +787,6 @@ namespace Game.Entities // 0 1 SQLResult result = DB.World.Query("SELECT spell_id, req_spell from spell_required"); - if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 spell required records. DB table `spell_required` is empty."); @@ -740,14 +801,14 @@ namespace Game.Entities uint spell_req = result.Read(1); // check if chain is made with valid first spell - SpellInfo spell = GetSpellInfo(spell_id); + SpellInfo spell = GetSpellInfo(spell_id, Difficulty.None); if (spell == null) { Log.outError(LogFilter.Sql, "spell_id {0} in `spell_required` table is not found in dbcs, skipped", spell_id); continue; } - SpellInfo req_spell = GetSpellInfo(spell_req); + SpellInfo req_spell = GetSpellInfo(spell_req, Difficulty.None); if (req_spell == null) { Log.outError(LogFilter.Sql, "req_spell {0} in `spell_required` table is not found in dbcs, skipped", spell_req); @@ -781,11 +842,14 @@ namespace Game.Entities // search auto-learned skills and add its to map also for use in unlearn spells/talents uint dbc_count = 0; - foreach (var spell in mSpellInfoMap.Values) + foreach (var entry in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in spell.GetEffectsForDifficulty(Difficulty.None)) + if (entry.Difficulty != Difficulty.None) + continue; + + foreach (SpellEffectInfo effect in entry.GetEffects()) { - if (effect == null) + if (effect != null) continue; SpellLearnSkillNode dbc_node = new SpellLearnSkillNode(); @@ -810,7 +874,7 @@ namespace Game.Entities continue; } - mSpellLearnSkills.Add(spell.Id, dbc_node); + mSpellLearnSkills.Add(entry.Id, dbc_node); ++dbc_count; break; } @@ -842,14 +906,14 @@ namespace Game.Entities node.Active = result.Read(2); node.AutoLearned = false; - SpellInfo spellInfo = GetSpellInfo(spell_id); + SpellInfo spellInfo = GetSpellInfo(spell_id, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_learn_spell` does not exist", spell_id); continue; } - if (GetSpellInfo(node.Spell) == null) + if (!HasSpellInfo(node.Spell, Difficulty.None)) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_learn_spell` learning not existed spell {1}", spell_id, node.Spell); continue; @@ -869,7 +933,10 @@ namespace Game.Entities uint dbc_count = 0; foreach (var entry in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in entry.GetEffectsForDifficulty(Difficulty.None)) + if (entry.Difficulty != Difficulty.None) + continue; + + foreach (SpellEffectInfo effect in entry.GetEffects()) { if (effect != null && effect.Effect == SpellEffectName.LearnSpell) { @@ -879,7 +946,7 @@ namespace Game.Entities dbc_node.OverridesSpell = 0; // ignore learning not existed spells (broken/outdated/or generic learnig spell 483 - if (GetSpellInfo(dbc_node.Spell) == null) + if (GetSpellInfo(dbc_node.Spell, Difficulty.None) == null) continue; // talent or passive spells or skill-step spells auto-cast and not need dependent learning, @@ -912,7 +979,7 @@ namespace Game.Entities foreach (var spellLearnSpell in CliDB.SpellLearnSpellStorage.Values) { - if (GetSpellInfo(spellLearnSpell.SpellID) == null) + if (!HasSpellInfo(spellLearnSpell.SpellID, Difficulty.None)) continue; var db_node_bounds = mSpellLearnSpells.LookupByKey(spellLearnSpell.LearnSpellID); @@ -997,7 +1064,7 @@ namespace Game.Entities continue; } - SpellInfo spellInfo = GetSpellInfo(spellId); + SpellInfo spellInfo = GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell (ID: {0}) listed in `spell_target_position` does not exist.", spellId); @@ -1079,8 +1146,7 @@ namespace Game.Entities } else { - SpellInfo spellInfo = GetSpellInfo((uint)group.Value); - + SpellInfo spellInfo = GetSpellInfo((uint)group.Value, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_group` does not exist", group.Value); @@ -1179,8 +1245,8 @@ namespace Game.Entities foreach (uint spellId in spellIds) { - SpellInfo spellInfo = GetSpellInfo(spellId); - foreach (SpellEffectInfo effectInfo in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + SpellInfo spellInfo = GetSpellInfo(spellId, Difficulty.None); + foreach (SpellEffectInfo effectInfo in spellInfo.GetEffects()) { if (!effectInfo.IsAura()) continue; @@ -1221,14 +1287,14 @@ namespace Game.Entities // re-check spells against guessed group foreach (uint spellId in spellIds) { - SpellInfo spellInfo = GetSpellInfo(spellId); + SpellInfo spellInfo = GetSpellInfo(spellId, Difficulty.None); bool found = false; while (spellInfo != null) { foreach (AuraType auraType in auraTypes) { - if (spellInfo.HasAura(Difficulty.None, auraType)) + if (spellInfo.HasAura(auraType)) { found = true; break; @@ -1278,7 +1344,7 @@ namespace Game.Entities spellId = -spellId; } - SpellInfo spellInfo = GetSpellInfo((uint)spellId); + SpellInfo spellInfo = GetSpellInfo((uint)spellId, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_proc` does not exist", spellId); @@ -1312,7 +1378,7 @@ namespace Game.Entities while (spellInfo != null) { - if (mSpellProcMap.ContainsKey(spellInfo.Id)) + if (mSpellProcMap.ContainsKey((spellInfo.Id, spellInfo.Difficulty))) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_proc` has duplicate entry in the table", spellInfo.Id); break; @@ -1363,7 +1429,7 @@ namespace Game.Entities if (procEntry.HitMask != 0 && !(Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.TakenHitMask) || (Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.DoneHitMask) && (procEntry.SpellPhaseMask == 0 || Convert.ToBoolean(procEntry.SpellPhaseMask & (ProcFlagsSpellPhase.Hit | ProcFlagsSpellPhase.Finish)))))) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellInfo.Id); - mSpellProcMap.Add(spellInfo.Id, procEntry); + mSpellProcMap.Add((spellInfo.Id, spellInfo.Difficulty), procEntry); ++count; if (allRanks) @@ -1385,11 +1451,8 @@ namespace Game.Entities foreach (SpellInfo spellInfo in mSpellInfoMap.Values) { - if (spellInfo == null) - continue; - // Data already present in DB, overwrites default proc - if (mSpellProcMap.ContainsKey(spellInfo.Id)) + if (mSpellProcMap.ContainsKey((spellInfo.Id, spellInfo.Difficulty))) continue; // Nothing to do if no flags set @@ -1398,7 +1461,7 @@ namespace Game.Entities bool addTriggerFlag = false; ProcFlagsSpellType procSpellTypeMask = ProcFlagsSpellType.None; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null || !effect.IsEffect()) continue; @@ -1433,7 +1496,7 @@ namespace Game.Entities if (procSpellTypeMask == 0) { - foreach (SpellEffectInfo effectInfo in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effectInfo in spellInfo.GetEffects()) { if (effectInfo != null && effectInfo.IsAura()) { @@ -1449,7 +1512,7 @@ namespace Game.Entities procEntry.SchoolMask = 0; procEntry.ProcFlags = spellInfo.ProcFlags; procEntry.SpellFamilyName = 0; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) if (effect != null && effect.IsEffect() && IsTriggerAura(effect.ApplyAuraName)) procEntry.SpellFamilyMask |= effect.SpellClassMask; @@ -1460,7 +1523,7 @@ namespace Game.Entities procEntry.SpellPhaseMask = ProcFlagsSpellPhase.Hit; procEntry.HitMask = ProcFlagsHit.None; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null || !effect.IsAura()) continue; @@ -1498,7 +1561,7 @@ namespace Game.Entities procEntry.Cooldown = spellInfo.ProcCooldown; procEntry.Charges = spellInfo.ProcCharges; - mSpellProcMap[spellInfo.Id] = procEntry; + mSpellProcMap[(spellInfo.Id, spellInfo.Difficulty)] = procEntry; ++count; } @@ -1523,7 +1586,7 @@ namespace Game.Entities { uint entry = result.Read(0); - if (GetSpellInfo(entry) == null) + if (!HasSpellInfo(entry, Difficulty.None)) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_threat` does not exist", entry); continue; @@ -1580,7 +1643,7 @@ namespace Game.Entities petAura.AddAura(pet, aura); else { - SpellInfo spellInfo = GetSpellInfo(spell); + SpellInfo spellInfo = GetSpellInfo(spell, Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_pet_auras` does not exist", spell); @@ -1599,7 +1662,7 @@ namespace Game.Entities continue; } - SpellInfo spellInfo2 = GetSpellInfo(aura); + SpellInfo spellInfo2 = GetSpellInfo(aura, Difficulty.None); if (spellInfo2 == null) { Log.outError(LogFilter.Sql, "Aura {0} listed in `spell_pet_auras` does not exist", aura); @@ -1627,7 +1690,7 @@ namespace Game.Entities if (!spellInfo.HasAttribute(SpellAttr2.PreserveEnchantInArena) || !spellInfo.HasAttribute(SpellAttr0.NotShapeshift)) continue; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect != null && effect.Effect == SpellEffectName.EnchantItemTemporary) { @@ -1706,14 +1769,23 @@ namespace Game.Entities int effect = result.Read(1); int type = result.Read(2); - SpellInfo spellInfo = GetSpellInfo((uint)Math.Abs(trigger)); + SpellInfo spellInfo = GetSpellInfo((uint)Math.Abs(trigger), Difficulty.None); if (spellInfo == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_linked_spell` does not exist", Math.Abs(trigger)); continue; } - spellInfo = GetSpellInfo((uint)Math.Abs(effect)); - if (spellInfo == null) + + if (effect >= 0) + { + foreach (SpellEffectInfo eff in spellInfo.GetEffects()) + { + if (eff != null && eff.CalcValue() == Math.Abs(effect)) + Log.outError(LogFilter.Sql, $"The spell {Math.Abs(trigger)} Effect: {Math.Abs(effect)} listed in `spell_linked_spell` has same bp{eff.EffectIndex} like effect (possible hack)"); + } + } + + if (!HasSpellInfo((uint)Math.Abs(effect), Difficulty.None)) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_linked_spell` does not exist", Math.Abs(effect)); continue; @@ -1758,7 +1830,7 @@ namespace Game.Entities if (skillLine.AcquireMethod != AbilityLearnType.OnSkillLearn) continue; - SpellInfo spell = GetSpellInfo(skillLine.Spell); + SpellInfo spell = GetSpellInfo(skillLine.Spell, Difficulty.None); if (spell == null) // not exist or triggered or talent continue; @@ -1795,28 +1867,31 @@ namespace Game.Entities // different summon spells foreach (var spellEntry in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in spellEntry.GetEffectsForDifficulty(Difficulty.None)) + if (spellEntry.Difficulty != Difficulty.None) { - if (effect != null && (effect.Effect == SpellEffectName.Summon || effect.Effect == SpellEffectName.SummonPet)) + foreach (SpellEffectInfo effect in spellEntry.GetEffects()) { - int creature_id = effect.MiscValue; - CreatureTemplate cInfo = Global.ObjectMgr.GetCreatureTemplate((uint)creature_id); - if (cInfo == null) - continue; - - // get default pet spells from creature_template - uint petSpellsId = cInfo.Entry; - if (mPetDefaultSpellsMap.LookupByKey(cInfo.Entry) != null) - continue; - - PetDefaultSpellsEntry petDefSpells = new PetDefaultSpellsEntry(); - for (byte j = 0; j < SharedConst.MaxCreatureSpellDataSlots; ++j) - petDefSpells.spellid[j] = cInfo.Spells[j]; - - if (LoadPetDefaultSpells_helper(cInfo, petDefSpells)) + if (effect != null && (effect.Effect == SpellEffectName.Summon || effect.Effect == SpellEffectName.SummonPet)) { - mPetDefaultSpellsMap[petSpellsId] = petDefSpells; - ++countCreature; + int creature_id = effect.MiscValue; + CreatureTemplate cInfo = Global.ObjectMgr.GetCreatureTemplate((uint)creature_id); + if (cInfo == null) + continue; + + // get default pet spells from creature_template + uint petSpellsId = cInfo.Entry; + if (mPetDefaultSpellsMap.LookupByKey(cInfo.Entry) != null) + continue; + + PetDefaultSpellsEntry petDefSpells = new PetDefaultSpellsEntry(); + for (byte j = 0; j < SharedConst.MaxCreatureSpellDataSlots; ++j) + petDefSpells.spellid[j] = cInfo.Spells[j]; + + if (LoadPetDefaultSpells_helper(cInfo, petDefSpells)) + { + mPetDefaultSpellsMap[petSpellsId] = petDefSpells; + ++countCreature; + } } } } @@ -1909,7 +1984,7 @@ namespace Game.Entities spellArea.gender = (Gender)result.Read(8); spellArea.flags = (SpellAreaFlag)result.Read(9); - SpellInfo spellInfo = GetSpellInfo(spell); + SpellInfo spellInfo = GetSpellInfo(spell, Difficulty.None); if (spellInfo != null) { if (spellArea.flags.HasAnyFlag(SpellAreaFlag.AutoCast)) @@ -1974,7 +2049,7 @@ namespace Game.Entities if (spellArea.auraSpell != 0) { - SpellInfo info = GetSpellInfo((uint)Math.Abs(spellArea.auraSpell)); + SpellInfo info = GetSpellInfo((uint)Math.Abs(spellArea.auraSpell), Difficulty.None); if (info == null) { Log.outError(LogFilter.Sql, "Spell {0} listed in `spell_area` have wrong aura spell ({1}) requirement", spell, Math.Abs(spellArea.auraSpell)); @@ -2072,15 +2147,22 @@ namespace Game.Entities uint oldMSTime = Time.GetMSTime(); mSpellInfoMap.Clear(); - Dictionary loadData = new Dictionary(); + var loadData = new Dictionary<(uint Id, Difficulty difficulty), SpellInfoLoadHelper>(); Dictionary battlePetSpeciesByCreature = new Dictionary(); foreach (var battlePetSpecies in CliDB.BattlePetSpeciesStorage.Values) if (battlePetSpecies.CreatureID != 0) battlePetSpeciesByCreature[battlePetSpecies.CreatureID] = battlePetSpecies; - Dictionary> effectsBySpell = new Dictionary>(); - Dictionary> visualsBySpell = new Dictionary>(); + SpellInfoLoadHelper GetLoadHelper(uint spellId, uint difficulty) + { + var key = (spellId, (Difficulty)difficulty); + if (!loadData.ContainsKey(key)) + loadData[key] = new SpellInfoLoadHelper(); + + return loadData[key]; + } + foreach (var effect in CliDB.SpellEffectStorage.Values) { Cypher.Assert(effect.EffectIndex < SpellConst.MaxEffects, $"MAX_SPELL_EFFECTS must be at least {effect.EffectIndex}"); @@ -2089,13 +2171,7 @@ namespace Game.Entities Cypher.Assert(effect.ImplicitTarget[0] < (int)Targets.TotalSpellTargets, $"TOTAL_SPELL_TARGETS must be at least {effect.ImplicitTarget[0]}"); Cypher.Assert(effect.ImplicitTarget[1] < (int)Targets.TotalSpellTargets, $"TOTAL_SPELL_TARGETS must be at least {effect.ImplicitTarget[1]}"); - if (!effectsBySpell.ContainsKey(effect.SpellID)) - effectsBySpell[effect.SpellID] = new Dictionary(); - - if (!effectsBySpell[effect.SpellID].ContainsKey(effect.DifficultyID)) - effectsBySpell[effect.SpellID][effect.DifficultyID] = new SpellEffectRecord[SpellConst.MaxEffects]; - - effectsBySpell[effect.SpellID][effect.DifficultyID][effect.EffectIndex] = effect; + GetLoadHelper(effect.SpellID, effect.DifficultyID).Effects[effect.EffectIndex] = effect; if (effect.Effect == (int)SpellEffectName.Summon) { @@ -2112,112 +2188,164 @@ namespace Game.Entities } } - SpellInfoLoadHelper GetSpellInfoLoadHelper(uint spellId) - { - if (!loadData.ContainsKey(spellId)) - loadData[spellId] = new SpellInfoLoadHelper(); - - return loadData[spellId]; - } - foreach (SpellAuraOptionsRecord auraOptions in CliDB.SpellAuraOptionsStorage.Values) - if (auraOptions.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(auraOptions.SpellID).AuraOptions = auraOptions; + GetLoadHelper(auraOptions.SpellID, auraOptions.DifficultyID).AuraOptions = auraOptions; CliDB.SpellAuraOptionsStorage.Clear(); foreach (SpellAuraRestrictionsRecord auraRestrictions in CliDB.SpellAuraRestrictionsStorage.Values) - { - if (auraRestrictions.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(auraRestrictions.SpellID).AuraRestrictions = auraRestrictions; - } + GetLoadHelper(auraRestrictions.SpellID, auraRestrictions.DifficultyID).AuraRestrictions = auraRestrictions; + CliDB.SpellAuraRestrictionsStorage.Clear(); foreach (SpellCastingRequirementsRecord castingRequirements in CliDB.SpellCastingRequirementsStorage.Values) - GetSpellInfoLoadHelper(castingRequirements.SpellID).CastingRequirements = castingRequirements; + GetLoadHelper(castingRequirements.SpellID, 0).CastingRequirements = castingRequirements; CliDB.SpellCastingRequirementsStorage.Clear(); foreach (SpellCategoriesRecord categories in CliDB.SpellCategoriesStorage.Values) - { - if (categories.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(categories.SpellID).Categories = categories; - } + GetLoadHelper(categories.SpellID, categories.DifficultyID).Categories = categories; + CliDB.SpellCategoriesStorage.Clear(); foreach (SpellClassOptionsRecord classOptions in CliDB.SpellClassOptionsStorage.Values) - GetSpellInfoLoadHelper(classOptions.SpellID).ClassOptions = classOptions; + GetLoadHelper(classOptions.SpellID, 0).ClassOptions = classOptions; CliDB.SpellClassOptionsStorage.Clear(); foreach (SpellCooldownsRecord cooldowns in CliDB.SpellCooldownsStorage.Values) - { - if (cooldowns.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(cooldowns.SpellID).Cooldowns = cooldowns; - } + GetLoadHelper(cooldowns.SpellID, cooldowns.DifficultyID).Cooldowns = cooldowns; + CliDB.SpellCooldownsStorage.Clear(); foreach (SpellEquippedItemsRecord equippedItems in CliDB.SpellEquippedItemsStorage.Values) - GetSpellInfoLoadHelper(equippedItems.SpellID).EquippedItems = equippedItems; + GetLoadHelper(equippedItems.SpellID, 0).EquippedItems = equippedItems; CliDB.SpellEquippedItemsStorage.Clear(); foreach (SpellInterruptsRecord interrupts in CliDB.SpellInterruptsStorage.Values) - { - if (interrupts.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(interrupts.SpellID).Interrupts = interrupts; - } + GetLoadHelper(interrupts.SpellID, interrupts.DifficultyID).Interrupts = interrupts; + CliDB.SpellInterruptsStorage.Clear(); foreach (SpellLevelsRecord levels in CliDB.SpellLevelsStorage.Values) - { - if (levels.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(levels.SpellID).Levels = levels; - } + GetLoadHelper(levels.SpellID, levels.DifficultyID).Levels = levels; foreach (SpellMiscRecord misc in CliDB.SpellMiscStorage.Values) if (misc.DifficultyID == 0) - GetSpellInfoLoadHelper(misc.SpellID).Misc = misc; + GetLoadHelper(misc.SpellID, misc.DifficultyID).Misc = misc; + + foreach (SpellPowerRecord power in CliDB.SpellPowerStorage.Values) + { + uint difficulty = 0; + byte index = power.OrderIndex; + + SpellPowerDifficultyRecord powerDifficulty = CliDB.SpellPowerDifficultyStorage.LookupByKey(power.Id); + if (powerDifficulty != null) + { + difficulty = powerDifficulty.DifficultyID; + index = powerDifficulty.OrderIndex; + } + + GetLoadHelper(power.SpellID, difficulty).Powers[index] = power; + } foreach (SpellReagentsRecord reagents in CliDB.SpellReagentsStorage.Values) - GetSpellInfoLoadHelper(reagents.SpellID).Reagents = reagents; + GetLoadHelper(reagents.SpellID, 0).Reagents = reagents; CliDB.SpellReagentsStorage.Clear(); foreach (SpellScalingRecord scaling in CliDB.SpellScalingStorage.Values) - GetSpellInfoLoadHelper(scaling.SpellID).Scaling = scaling; + GetLoadHelper(scaling.SpellID, 0).Scaling = scaling; CliDB.SpellScalingStorage.Clear(); foreach (SpellShapeshiftRecord shapeshift in CliDB.SpellShapeshiftStorage.Values) - GetSpellInfoLoadHelper(shapeshift.SpellID).Shapeshift = shapeshift; + GetLoadHelper(shapeshift.SpellID, 0).Shapeshift = shapeshift; CliDB.SpellShapeshiftStorage.Clear(); foreach (SpellTargetRestrictionsRecord targetRestrictions in CliDB.SpellTargetRestrictionsStorage.Values) - { - if (targetRestrictions.DifficultyID == 0) // TODO: implement - GetSpellInfoLoadHelper(targetRestrictions.SpellID).TargetRestrictions = targetRestrictions; - } + GetLoadHelper(targetRestrictions.SpellID, targetRestrictions.DifficultyID).TargetRestrictions = targetRestrictions; + CliDB.SpellTargetRestrictionsStorage.Clear(); foreach (SpellTotemsRecord totems in CliDB.SpellTotemsStorage.Values) - GetSpellInfoLoadHelper(totems.SpellID).Totems = totems; + GetLoadHelper(totems.SpellID, 0).Totems = totems; CliDB.SpellTotemsStorage.Clear(); foreach (var visual in CliDB.SpellXSpellVisualStorage.Values) { - if (!visualsBySpell.ContainsKey(visual.SpellID)) - visualsBySpell[visual.SpellID] = new MultiMap(); - - visualsBySpell[visual.SpellID].Add(visual.DifficultyID, visual); + var visuals = GetLoadHelper(visual.SpellID, visual.DifficultyID).Visuals; + visuals.Add(visual); } - foreach (var spellEntry in CliDB.SpellNameStorage.Values) + // sorted with unconditional visuals being last + foreach (var data in loadData) + data.Value.Visuals.Sort((left, right) => { return right.CasterPlayerConditionID.CompareTo(left.CasterPlayerConditionID); }); + + foreach (var data in loadData) { - GetSpellInfoLoadHelper(spellEntry.Id).Entry = spellEntry; - mSpellInfoMap[spellEntry.Id] = new SpellInfo(loadData[spellEntry.Id], effectsBySpell.LookupByKey(spellEntry.Id), visualsBySpell.LookupByKey(spellEntry.Id)); + SpellNameRecord spellNameEntry = CliDB.SpellNameStorage.LookupByKey(data.Key.Id); + if (spellNameEntry == null) + continue; + + var visuals = data.Value.Visuals; // copy, need to ensure source remains unmodified + + // fill blanks + DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(data.Key.difficulty); + if (difficultyEntry != null) + { + do + { + SpellInfoLoadHelper fallbackData = loadData.LookupByKey((data.Key.Id, (Difficulty)difficultyEntry.FallbackDifficultyID)); + if (fallbackData != null) + { + if (data.Value.AuraOptions == null) + data.Value.AuraOptions = fallbackData.AuraOptions; + + if (data.Value.AuraRestrictions == null) + data.Value.AuraRestrictions = fallbackData.AuraRestrictions; + + if (data.Value.Categories == null) + data.Value.Categories = fallbackData.Categories; + + if (data.Value.Cooldowns == null) + data.Value.Cooldowns = fallbackData.Cooldowns; + + for (var i = 0; i < data.Value.Effects.Length; ++i) + if (data.Value.Effects[i] == null) + data.Value.Effects[i] = fallbackData.Effects[i]; + + if (data.Value.Interrupts == null) + data.Value.Interrupts = fallbackData.Interrupts; + + if (data.Value.Levels == null) + data.Value.Levels = fallbackData.Levels; + + if (data.Value.Misc == null) + data.Value.Misc = fallbackData.Misc; + + for (var i = 0; i < fallbackData.Powers.Length; ++i) + if (data.Value.Powers[i] == null) + data.Value.Powers[i] = fallbackData.Powers[i]; + + if (data.Value.TargetRestrictions == null) + data.Value.TargetRestrictions = fallbackData.TargetRestrictions; + + visuals.AddRange(fallbackData.Visuals); + } + + difficultyEntry = CliDB.DifficultyStorage.LookupByKey(difficultyEntry.FallbackDifficultyID); + } while (difficultyEntry != null); + } + + //first key = id, difficulty + //second key = id + + + mSpellInfoMap.Add(spellNameEntry.Id, new SpellInfo(spellNameEntry, data.Key.difficulty, data.Value, visuals)); } CliDB.SpellNameStorage.Clear(); @@ -2248,24 +2376,27 @@ namespace Game.Entities uint spellId = result.Read(0); uint attributes = result.Read(1); - SpellInfo spellInfo = GetSpellInfo(spellId); - if (spellInfo == null) + var spells = _GetSpellInfo(spellId); + if (spells == null) { Log.outError(LogFilter.Sql, "Table `spell_custom_attr` has wrong spell (entry: {0}), ignored.", spellId); continue; } - // TODO: validate attributes - if (attributes.HasAnyFlag((uint)SpellCustomAttributes.ShareDamage)) + foreach (SpellInfo spellInfo in spells) { - if (!spellInfo.HasEffect(SpellEffectName.SchoolDamage)) + // TODO: validate attributes + if (attributes.HasAnyFlag((uint)SpellCustomAttributes.ShareDamage)) { - Log.outError(LogFilter.Sql, "Spell {0} listed in table `spell_custom_attr` with SPELL_ATTR0_CU_SHARE_DAMAGE has no SPELL_EFFECT_SCHOOL_DAMAGE, ignored.", spellId); - continue; + if (!spellInfo.HasEffect(SpellEffectName.SchoolDamage)) + { + Log.outError(LogFilter.Sql, "Spell {0} listed in table `spell_custom_attr` with SPELL_ATTR0_CU_SHARE_DAMAGE has no SPELL_EFFECT_SCHOOL_DAMAGE, ignored.", spellId); + continue; + } } - } - spellInfo.AttributesCu |= (SpellCustomAttributes)attributes; + spellInfo.AttributesCu |= (SpellCustomAttributes)attributes; + } ++count; } while (result.NextRow()); @@ -2278,7 +2409,7 @@ namespace Game.Entities foreach (var spellInfo in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -2352,17 +2483,17 @@ namespace Game.Entities if (enchant.Effect[s] != ItemEnchantmentType.CombatSpell) continue; - SpellInfo procInfo = GetSpellInfo(enchant.EffectArg[s]); - if (procInfo == null) - continue; + foreach (SpellInfo procInfo in _GetSpellInfo(enchant.EffectArg[s])) + { - // if proced directly from enchantment, not via proc aura - // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly - // however its not expected to stack so this check is good - if (procInfo.HasAura(Difficulty.None, AuraType.ProcTriggerSpell)) - continue; + // if proced directly from enchantment, not via proc aura + // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly + // however its not expected to stack so this check is good + if (procInfo.HasAura(AuraType.ProcTriggerSpell)) + continue; - procInfo.AttributesCu |= SpellCustomAttributes.EnchantProc; + procInfo.AttributesCu |= SpellCustomAttributes.EnchantProc; + } } } break; @@ -2374,7 +2505,7 @@ namespace Game.Entities if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) { bool setFlag = false; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -2497,7 +2628,7 @@ namespace Game.Entities bool allNonBinary = true; bool overrideAttr = false; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -2508,7 +2639,7 @@ namespace Game.Entities { case AuraType.PeriodicTriggerSpell: case AuraType.PeriodicTriggerSpellWithValue: - SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell); + SpellInfo triggerSpell = Global.SpellMgr.GetSpellInfo(effect.TriggerSpell, Difficulty.None); if (triggerSpell != null) { overrideAttr = true; @@ -2535,7 +2666,7 @@ namespace Game.Entities foreach (var spellInfo in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -2543,7 +2674,7 @@ namespace Game.Entities if (effect.IsEffect() && (effect.TargetA.GetTarget() == Targets.DestTraj || effect.TargetB.GetTarget() == Targets.DestTraj)) { // Get triggered spell if any - SpellInfo spellInfoTrigger = GetSpellInfo(effect.TriggerSpell); + SpellInfo spellInfoTrigger = GetSpellInfo(effect.TriggerSpell, Difficulty.None); if (spellInfoTrigger != null) { float maxRangeMain = spellInfo.GetMaxRange(); @@ -2572,8 +2703,12 @@ namespace Game.Entities spellInfo.ConeAngle = 90.0f; } + // disable proc for magnet auras, they're handled differently + if (spellInfo.HasAura(AuraType.SpellMagnet)) + spellInfo.ProcFlags = 0; + // due to the way spell system works, unit would change orientation in Spell::_cast - if (spellInfo.HasAura(Difficulty.None, AuraType.ControlVehicle)) + if (spellInfo.HasAura(AuraType.ControlVehicle)) spellInfo.AttributesEx5 |= SpellAttr5.DontTurnDuringCast; if (spellInfo.ActiveIconFileDataId == 135754) // flight @@ -2936,7 +3071,7 @@ namespace Game.Entities break; case 71412: // Green Ooze Summon (Professor Putricide) case 71415: // Orange Ooze Summon (Professor Putricide) - spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.UnitAny); + spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.UnitTargetAny); break; case 71159: // Awaken Plagued Zombies spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(21); @@ -2949,7 +3084,7 @@ namespace Game.Entities spellInfo.GetEffect(1).Effect = 0; break; case 70911: // Unbound Plague (Professor Putricide) (needs target selection script) - spellInfo.GetEffect(0).TargetB = new SpellImplicitTargetInfo(Targets.UnitEnemy); + spellInfo.GetEffect(0).TargetB = new SpellImplicitTargetInfo(Targets.UnitTargetEnemy); break; case 71708: // Empowered Flare (Blood Prince Council) spellInfo.AttributesEx3 |= SpellAttr3.NoDoneBonus; @@ -2967,7 +3102,7 @@ namespace Game.Entities spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(9); // 30 seconds (missing) break; case 70936: // Summon Suppressor (needs target selection script) - spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.UnitAny); + spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.UnitTargetAny); spellInfo.GetEffect(0).TargetB = new SpellImplicitTargetInfo(); spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(157); // 90yd break; @@ -3138,7 +3273,7 @@ namespace Game.Entities foreach (var spellInfo in mSpellInfoMap.Values) { - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + foreach (SpellEffectInfo effect in spellInfo.GetEffects()) { if (effect == null) continue; @@ -3160,7 +3295,7 @@ namespace Game.Entities } // disable proc for magnet auras, they're handled differently - if (spellInfo.HasAura(Difficulty.None, AuraType.SpellMagnet)) + if (spellInfo.HasAura(AuraType.SpellMagnet)) spellInfo.ProcFlags = 0; if (spellInfo.ActiveIconFileDataId == 135754) // flight @@ -3233,7 +3368,7 @@ namespace Game.Entities foreach (var skillLine in CliDB.SkillLineAbilityStorage.Values) { - SpellInfo spellInfo = GetSpellInfo(skillLine.Spell); + SpellInfo spellInfo = GetSpellInfo(skillLine.Spell, Difficulty.None); if (spellInfo == null) continue; @@ -3275,7 +3410,7 @@ namespace Game.Entities byte race = result.Read(1); uint displayId = result.Read(2); - SpellInfo spellEntry = GetSpellInfo(spellId); + SpellInfo spellEntry = GetSpellInfo(spellId, Difficulty.None); if (spellEntry == null) { Log.outError(LogFilter.Sql, $"SpellID: {spellId} in `spell_totem_model` table could not be found in dbc, skipped."); @@ -3396,15 +3531,16 @@ namespace Game.Entities } // SpellInfo object management - public SpellInfo GetSpellInfo(uint spellId) + public bool HasSpellInfo(uint spellId, Difficulty difficulty) { - return mSpellInfoMap.LookupByKey(spellId); + var list = mSpellInfoMap.LookupByKey(spellId); + if (list.Count == 0) + return false; + + return list.Any(spellInfo => spellInfo.Difficulty == difficulty); } - public bool HasSpellInfo(uint spellId) - { - return mSpellInfoMap.ContainsKey(spellId); - } - public Dictionary GetSpellInfoStorage() + + public MultiMap GetSpellInfoStorage() { return mSpellInfoMap; } @@ -3519,7 +3655,7 @@ namespace Game.Entities MultiMap mSpellGroupSpell = new MultiMap(); Dictionary mSpellGroupStack = new Dictionary(); MultiMap mSpellSameEffectStack = new MultiMap(); - Dictionary mSpellProcMap = new Dictionary(); + Dictionary<(uint id, Difficulty difficulty), SpellProcEntry> mSpellProcMap = new Dictionary<(uint id, Difficulty difficulty), SpellProcEntry>(); Dictionary mSpellThreatMap = new Dictionary(); Dictionary mSpellPetAuraMap = new Dictionary(); MultiMap mSpellLinkedMap = new MultiMap(); @@ -3534,7 +3670,7 @@ namespace Game.Entities MultiMap mSkillLineAbilityMap = new MultiMap(); Dictionary> mPetLevelupSpellMap = new Dictionary>(); Dictionary mPetDefaultSpellsMap = new Dictionary(); // only spells not listed in related mPetLevelupSpellMap entry - Dictionary mSpellInfoMap = new Dictionary(); + MultiMap mSpellInfoMap = new MultiMap(); Dictionary, uint> mSpellTotemModel = new Dictionary, uint>(); Dictionary mBattlePets = new Dictionary(); @@ -3571,23 +3707,24 @@ namespace Game.Entities public class SpellInfoLoadHelper { - public SpellNameRecord Entry; - public SpellAuraOptionsRecord AuraOptions; public SpellAuraRestrictionsRecord AuraRestrictions; public SpellCastingRequirementsRecord CastingRequirements; public SpellCategoriesRecord Categories; public SpellClassOptionsRecord ClassOptions; public SpellCooldownsRecord Cooldowns; + public SpellEffectRecord[] Effects = new SpellEffectRecord[SpellConst.MaxEffects]; public SpellEquippedItemsRecord EquippedItems; public SpellInterruptsRecord Interrupts; public SpellLevelsRecord Levels; public SpellMiscRecord Misc; + public SpellPowerRecord[] Powers = new SpellPowerRecord[SpellConst.MaxPowersPerSpell]; public SpellReagentsRecord Reagents; public SpellScalingRecord Scaling; public SpellShapeshiftRecord Shapeshift; public SpellTargetRestrictionsRecord TargetRestrictions; public SpellTotemsRecord Totems; + public List Visuals = new List(); // only to group visuals when parsing sSpellXSpellVisualStore, not for loading } public class SpellThreatEntry diff --git a/Source/Game/Tools/CharacterDatabaseCleaner.cs b/Source/Game/Tools/CharacterDatabaseCleaner.cs index 075d0fff2..a951ee436 100644 --- a/Source/Game/Tools/CharacterDatabaseCleaner.cs +++ b/Source/Game/Tools/CharacterDatabaseCleaner.cs @@ -130,7 +130,7 @@ namespace Game static bool SpellCheck(uint spell_id) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, Difficulty.None); return spellInfo != null && !spellInfo.HasAttribute(SpellCustomAttributes.IsTalent); } diff --git a/Source/Scripts/Northrend/AzjolNerub/Ahnkahet/BossHeraldVolazj.cs b/Source/Scripts/Northrend/AzjolNerub/Ahnkahet/BossHeraldVolazj.cs index 899db11c3..f45b17f0e 100644 --- a/Source/Scripts/Northrend/AzjolNerub/Ahnkahet/BossHeraldVolazj.cs +++ b/Source/Scripts/Northrend/AzjolNerub/Ahnkahet/BossHeraldVolazj.cs @@ -117,7 +117,7 @@ namespace Scripts.Northrend.AzjolNerub.Ahnkahet.HeraldVolazj // phase the player target.CastSpell(target, SpellIds.InsanityTarget + insanityHandled, true); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.InsanityTarget + insanityHandled); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.InsanityTarget + insanityHandled, GetDifficulty()); if (spellInfo == null) return; diff --git a/Source/Scripts/Northrend/IcecrownCitadel/GunshipBattle.cs b/Source/Scripts/Northrend/IcecrownCitadel/GunshipBattle.cs index 7575a56bd..ce57f380c 100644 --- a/Source/Scripts/Northrend/IcecrownCitadel/GunshipBattle.cs +++ b/Source/Scripts/Northrend/IcecrownCitadel/GunshipBattle.cs @@ -1719,7 +1719,7 @@ Fall Time: 824 void HandleRemove(AuraEffect aurEff, AuraEffectHandleModes mode) { - SpellInfo damageInfo = Global.SpellMgr.GetSpellInfo(GunshipSpells.RocketPackDamage); + SpellInfo damageInfo = Global.SpellMgr.GetSpellInfo(GunshipSpells.RocketPackDamage, GetCastDifficulty()); GetTarget().CastCustomSpell(GunshipSpells.RocketPackDamage, SpellValueMod.BasePoint0, (int)(2 * (damageInfo.GetEffect(0).CalcValue() + aurEff.GetTickNumber() * aurEff.GetPeriod())), null, TriggerCastFlags.FullMask); GetTarget().CastSpell(null, GunshipSpells.RocketBurst, TriggerCastFlags.FullMask); } diff --git a/Source/Scripts/Northrend/IcecrownCitadel/IcecrownCitadelTeleport.cs b/Source/Scripts/Northrend/IcecrownCitadel/IcecrownCitadelTeleport.cs index c0cb6c736..64fd8b703 100644 --- a/Source/Scripts/Northrend/IcecrownCitadel/IcecrownCitadelTeleport.cs +++ b/Source/Scripts/Northrend/IcecrownCitadel/IcecrownCitadelTeleport.cs @@ -41,7 +41,7 @@ namespace Scripts.Northrend.IcecrownCitadel player.PlayerTalkClass.ClearMenus(); player.CLOSE_GOSSIP_MENU(); - SpellInfo spell = Global.SpellMgr.GetSpellInfo(TeleportSpells[gossipListId]); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(TeleportSpells[gossipListId], Difficulty.None); if (spell == null) return false; @@ -84,7 +84,7 @@ namespace Scripts.Northrend.IcecrownCitadel { if (player.IsInCombat()) { - SpellInfo spell = Global.SpellMgr.GetSpellInfo(TeleporterSpells.FROZEN_THRONE_TELEPORT); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(TeleporterSpells.FROZEN_THRONE_TELEPORT, Difficulty.None); if (spell != null) { ObjectGuid castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, player.GetMapId(), spell.Id, player.GetMap().GenerateLowGuid(HighGuid.Cast)); diff --git a/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs b/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs index e961cbe43..87d6c6625 100644 --- a/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs +++ b/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs @@ -519,7 +519,7 @@ namespace Scripts.Northrend.IcecrownCitadel if (target.HasAura(Spells.Impaled)) return false; - SpellEffectInfo effect = GetSpellInfo().GetEffect(target.GetMap().GetDifficultyID(), 0); + SpellEffectInfo effect = GetSpellInfo().GetEffect(0); if (effect != null) if (target.GetExactDist2d(GetOwner()) > effect.CalcRadius()) return false; diff --git a/Source/Scripts/Spells/DeathKnight.cs b/Source/Scripts/Spells/DeathKnight.cs index d5073f910..c8609b9a5 100644 --- a/Source/Scripts/Spells/DeathKnight.cs +++ b/Source/Scripts/Spells/DeathKnight.cs @@ -263,7 +263,7 @@ namespace Scripts.Spells.DeathKnight return; int amount = (int)(damageInfo.GetDamage() / 2); - SpellNonMeleeDamage log = new SpellNonMeleeDamage(drw, drw.GetVictim(), spellInfo.Id, spellInfo.GetSpellXSpellVisualId(drw), spellInfo.GetSchoolMask()); + SpellNonMeleeDamage log = new SpellNonMeleeDamage(drw, drw.GetVictim(), spellInfo, spellInfo.GetSpellXSpellVisualId(drw), spellInfo.GetSchoolMask()); log.damage = (uint)amount; drw.DealDamage(drw.GetVictim(), (uint)amount, null, DamageEffectType.Direct, spellInfo.GetSchoolMask(), spellInfo, true); drw.SendSpellNonMeleeDamageLog(log); diff --git a/Source/Scripts/Spells/Druid.cs b/Source/Scripts/Spells/Druid.cs index e4c992211..e373dfc60 100644 --- a/Source/Scripts/Spells/Druid.cs +++ b/Source/Scripts/Spells/Druid.cs @@ -701,7 +701,7 @@ namespace Scripts.Spells.Druid if (player.GetSkillValue(SkillType.Riding) < 75) return SpellCastResult.ApprenticeRidingRequirement; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(player.IsInWater() ? SpellIds.FormAquatic : SpellIds.FormStag); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(player.IsInWater() ? SpellIds.FormAquatic : SpellIds.FormStag, GetCastDifficulty()); return spellInfo.CheckLocation(player.GetMapId(), player.GetZoneId(), player.GetAreaId(), player); } @@ -758,7 +758,7 @@ namespace Scripts.Spells.Druid SpellCastResult CheckLocationForForm(uint spell) { Player player = GetTarget().ToPlayer(); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell, GetCastDifficulty()); return spellInfo.CheckLocation(player.GetMapId(), player.GetZoneId(), player.GetAreaId(), player); } } @@ -821,7 +821,7 @@ namespace Scripts.Spells.Druid SpellCastResult CheckLocationForForm(uint spell_id) { Player player = GetTarget().ToPlayer(); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, GetCastDifficulty()); if (!player.GetMap().IsOutdoors(player.GetPhaseShift(), player.GetPositionX(), player.GetPositionY(), player.GetPositionZ())) return SpellCastResult.OnlyOutdoors; @@ -900,9 +900,9 @@ namespace Scripts.Spells.Druid Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.Languish); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.Languish, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(damageInfo.GetDamage(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to damage done amount += (int)target.GetRemainingPeriodicAmount(caster.GetGUID(), SpellIds.Languish, AuraType.PeriodicDamage); diff --git a/Source/Scripts/Spells/Generic.cs b/Source/Scripts/Spells/Generic.cs index 8d8954a14..d1ac94621 100644 --- a/Source/Scripts/Spells/Generic.cs +++ b/Source/Scripts/Spells/Generic.cs @@ -1628,7 +1628,7 @@ namespace Scripts.Spells.Generic public override void Register() { - SpellInfo spell = Global.SpellMgr.GetSpellInfo(m_scriptSpellId); + SpellInfo spell = Global.SpellMgr.GetSpellInfo(m_scriptSpellId, Difficulty.None); if (spell.HasEffect(SpellEffectName.ScriptEffect)) OnEffectHitTarget.Add(new EffectHandler(HandleScriptEffect, SpellConst.EffectFirstFound, SpellEffectName.ScriptEffect)); diff --git a/Source/Scripts/Spells/Hunter.cs b/Source/Scripts/Spells/Hunter.cs index 5de2b7a46..0c852a740 100644 --- a/Source/Scripts/Spells/Hunter.cs +++ b/Source/Scripts/Spells/Hunter.cs @@ -434,7 +434,7 @@ namespace Scripts.Spells.Hunter // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath GetCaster().GetSpellHistory().ResetCooldowns(p => { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(p.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(p.Key, GetCastDifficulty()); //! If spellId in cooldown map isn't valid, the above will return a null pointer. if (spellInfo.SpellFamilyName == SpellFamilyNames.Hunter && diff --git a/Source/Scripts/Spells/Items.cs b/Source/Scripts/Spells/Items.cs index 58e739246..f766c2b56 100644 --- a/Source/Scripts/Spells/Items.cs +++ b/Source/Scripts/Spells/Items.cs @@ -555,9 +555,9 @@ namespace Scripts.Spells.Items uint spellId = 0; int amount = (int)(eventInfo.GetDamageInfo().GetDamage() * 0.4f); - if (eventInfo.GetDamageInfo().GetSpellInfo().HasEffect(Difficulty.None, SpellEffectName.Heal)) + if (eventInfo.GetDamageInfo().GetSpellInfo().HasEffect(SpellEffectName.Heal)) spellId = SpellIds.AlchemistStoneExtraHeal; - else if (eventInfo.GetDamageInfo().GetSpellInfo().HasEffect(Difficulty.None, SpellEffectName.Energize)) + else if (eventInfo.GetDamageInfo().GetSpellInfo().HasEffect(SpellEffectName.Energize)) spellId = SpellIds.AlchemistStoneExtraMana; if (spellId == 0) @@ -779,7 +779,7 @@ namespace Scripts.Spells.Items void HandleDummy(uint effIndex) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DeadlyPrecision); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DeadlyPrecision, GetCastDifficulty()); GetCaster().CastCustomSpell(spellInfo.Id, SpellValueMod.AuraStack, (int)spellInfo.StackAmount, GetCaster(), true); } diff --git a/Source/Scripts/Spells/Mage.cs b/Source/Scripts/Spells/Mage.cs index 4db0c0d42..bb6649e8e 100644 --- a/Source/Scripts/Spells/Mage.cs +++ b/Source/Scripts/Spells/Mage.cs @@ -149,7 +149,7 @@ namespace Scripts.Spells.Mage } GetTarget().SetHealth(GetTarget().CountPctFromMaxHealth(effect1.GetAmount())); - GetTarget().CastSpell(GetTarget(), GetAura().GetSpellEffectInfo(2).TriggerSpell, TriggerCastFlags.FullMask); + GetTarget().CastSpell(GetTarget(), GetSpellInfo().GetEffect(2).TriggerSpell, TriggerCastFlags.FullMask); GetTarget().CastSpell(GetTarget(), SpellIds.CauterizeDot, TriggerCastFlags.FullMask); GetTarget().CastSpell(GetTarget(), SpellIds.Cauterized, TriggerCastFlags.FullMask); } @@ -288,10 +288,10 @@ namespace Scripts.Spells.Mage { PreventDefaultAction(); - SpellInfo igniteDot = Global.SpellMgr.GetSpellInfo(SpellIds.Ignite); + SpellInfo igniteDot = Global.SpellMgr.GetSpellInfo(SpellIds.Ignite, GetCastDifficulty()); int pct = aurEff.GetAmount(); - int amount = (int)(MathFunctions.CalculatePct(eventInfo.GetDamageInfo().GetDamage(), pct) / igniteDot.GetMaxTicks(Difficulty.None)); + int amount = (int)(MathFunctions.CalculatePct(eventInfo.GetDamageInfo().GetDamage(), pct) / igniteDot.GetMaxTicks()); amount += (int)eventInfo.GetProcTarget().GetRemainingPeriodicAmount(eventInfo.GetActor().GetGUID(), SpellIds.Ignite, AuraType.PeriodicDamage); GetTarget().CastCustomSpell(SpellIds.Ignite, SpellValueMod.BasePoint0, amount, eventInfo.GetProcTarget(), true, null, aurEff); } @@ -464,7 +464,7 @@ namespace Scripts.Spells.Mage void Apply(AuraEffect aurEff, AuraEffectHandleModes mode) { List minions = new List(); - GetTarget().GetAllMinionsByEntry(minions, (uint)Global.SpellMgr.GetSpellInfo(SpellIds.RingOfFrostSummon).GetEffect(0).MiscValue); + GetTarget().GetAllMinionsByEntry(minions, (uint)Global.SpellMgr.GetSpellInfo(SpellIds.RingOfFrostSummon, GetCastDifficulty()).GetEffect(0).MiscValue); // Get the last summoned RoF, save it and despawn older ones foreach (var summon in minions) @@ -513,7 +513,7 @@ namespace Scripts.Spells.Mage void FilterTargets(List targets) { WorldLocation dest = GetExplTargetDest(); - float outRadius = Global.SpellMgr.GetSpellInfo(SpellIds.RingOfFrostSummon).GetEffect(0).CalcRadius(); + float outRadius = Global.SpellMgr.GetSpellInfo(SpellIds.RingOfFrostSummon, GetCastDifficulty()).GetEffect(0).CalcRadius(); float inRadius = 6.5f; targets.RemoveAll(target => diff --git a/Source/Scripts/Spells/Monk.cs b/Source/Scripts/Spells/Monk.cs index bf64348e9..7daddc0a7 100644 --- a/Source/Scripts/Spells/Monk.cs +++ b/Source/Scripts/Spells/Monk.cs @@ -110,7 +110,7 @@ namespace Scripts.Spells.Monk { if (GetExplTargetUnit().GetEntry() != BlackOxStatusEntry) { - SpellInfo singleTarget = Global.SpellMgr.GetSpellInfo(SpellIds.ProvokeSingleTarget); + SpellInfo singleTarget = Global.SpellMgr.GetSpellInfo(SpellIds.ProvokeSingleTarget, GetCastDifficulty()); SpellCastResult singleTargetExplicitResult = singleTarget.CheckExplicitTarget(GetCaster(), GetExplTargetUnit()); if (singleTargetExplicitResult != SpellCastResult.SpellCastOk) return singleTargetExplicitResult; diff --git a/Source/Scripts/Spells/Paladin.cs b/Source/Scripts/Spells/Paladin.cs index 6a29d047e..9b6933188 100644 --- a/Source/Scripts/Spells/Paladin.cs +++ b/Source/Scripts/Spells/Paladin.cs @@ -456,7 +456,7 @@ namespace Scripts.Spells.Paladin { public override bool Validate(SpellInfo spellInfo) { - SpellInfo firstRankSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.HolyShockR1); + SpellInfo firstRankSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.HolyShockR1, Difficulty.None); if (firstRankSpellInfo == null) return false; @@ -596,7 +596,7 @@ namespace Scripts.Spells.Paladin { if (eff.GetSpellInfo().GetSpellSpecific() == SpellSpecificType.Seal && eff.GetEffIndex() == 2) { - if (Global.SpellMgr.HasSpellInfo((uint)eff.GetAmount())) + if (Global.SpellMgr.HasSpellInfo((uint)eff.GetAmount(), GetCastDifficulty())) { spellId = (uint)eff.GetAmount(); break; @@ -923,9 +923,9 @@ namespace Scripts.Spells.Paladin Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.HolyMending); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.HolyMending, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(healInfo.GetHeal(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to damage done amount += (int)target.GetRemainingPeriodicAmount(caster.GetGUID(), SpellIds.HolyMending, AuraType.PeriodicHeal); diff --git a/Source/Scripts/Spells/Priest.cs b/Source/Scripts/Spells/Priest.cs index 3fc301081..0fdc728e5 100644 --- a/Source/Scripts/Spells/Priest.cs +++ b/Source/Scripts/Spells/Priest.cs @@ -409,8 +409,8 @@ namespace Scripts.Spells.Priest if (healInfo == null || healInfo.GetHeal() == 0) return; - SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.GlyphOfPrayerOfHealingHeal); - int heal = (int)(MathFunctions.CalculatePct(healInfo.GetHeal(), aurEff.GetAmount()) / triggeredSpellInfo.GetMaxTicks(Difficulty.None)); + SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.GlyphOfPrayerOfHealingHeal, GetCastDifficulty()); + int heal = (int)(MathFunctions.CalculatePct(healInfo.GetHeal(), aurEff.GetAmount()) / triggeredSpellInfo.GetMaxTicks()); GetTarget().CastCustomSpell(SpellIds.GlyphOfPrayerOfHealingHeal, SpellValueMod.BasePoint0, heal, eventInfo.GetProcTarget(), true, null, aurEff); } @@ -566,7 +566,7 @@ namespace Scripts.Spells.Priest SpellCastTargets targets = new SpellCastTargets(); targets.SetDst(destPos); targets.SetUnitTarget(GetCaster()); - GetHitUnit().CastSpell(targets, Global.SpellMgr.GetSpellInfo((uint)GetEffectValue()), null); + GetHitUnit().CastSpell(targets, Global.SpellMgr.GetSpellInfo((uint)GetEffectValue(), GetCastDifficulty()), null); } public override void Register() @@ -702,7 +702,7 @@ namespace Scripts.Spells.Priest public override bool Validate(SpellInfo spellInfo) { - SpellInfo firstRankSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.PenanceR1); + SpellInfo firstRankSpellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.PenanceR1, Difficulty.None); if (firstRankSpellInfo == null) return false; @@ -997,9 +997,9 @@ namespace Scripts.Spells.Priest if (healInfo == null || healInfo.GetHeal() == 0) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.BlessedHealing); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.BlessedHealing, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(healInfo.GetHeal(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to healing done Unit caster = eventInfo.GetActor(); @@ -1134,7 +1134,7 @@ namespace Scripts.Spells.Priest { SpellCastTargets targets = new SpellCastTargets(); targets.SetDst(destPos); - GetCaster().CastSpell(targets, Global.SpellMgr.GetSpellInfo(SpellIds.AngelicFeatherAreatrigger), null); + GetCaster().CastSpell(targets, Global.SpellMgr.GetSpellInfo(SpellIds.AngelicFeatherAreatrigger, GetCastDifficulty()), null); } } diff --git a/Source/Scripts/Spells/Shaman.cs b/Source/Scripts/Spells/Shaman.cs index f6b8803d3..42a11a0a0 100644 --- a/Source/Scripts/Spells/Shaman.cs +++ b/Source/Scripts/Spells/Shaman.cs @@ -612,7 +612,7 @@ namespace Scripts.Spells.Shaman void ResetCooldown() { - GetCaster().GetSpellHistory().RestoreCharge(Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurst).ChargeCategoryId); + GetCaster().GetSpellHistory().RestoreCharge(Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurst, GetCastDifficulty()).ChargeCategoryId); } public override void Register() @@ -747,9 +747,9 @@ namespace Scripts.Spells.Shaman if (damageInfo == null || damageInfo.GetDamage() == 0) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.Electrified); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.Electrified, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(damageInfo.GetDamage(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to damage done Unit caster = eventInfo.GetActor(); @@ -781,9 +781,9 @@ namespace Scripts.Spells.Shaman if (damageInfo == null || damageInfo.GetDamage() == 0) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurstBonusDamage); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurstBonusDamage, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(damageInfo.GetDamage(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to damage done Unit caster = eventInfo.GetActor(); @@ -847,9 +847,9 @@ namespace Scripts.Spells.Shaman if (healInfo == null || healInfo.GetHeal() == 0) return; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.ChainedHeal); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.ChainedHeal, GetCastDifficulty()); int amount = (int)MathFunctions.CalculatePct(healInfo.GetHeal(), aurEff.GetAmount()); - amount /= (int)spellInfo.GetMaxTicks(Difficulty.None); + amount /= (int)spellInfo.GetMaxTicks(); // Add remaining ticks to healing done Unit caster = eventInfo.GetActor(); diff --git a/Source/Scripts/Spells/Warlock.cs b/Source/Scripts/Spells/Warlock.cs index 2f72c57fc..ff043db27 100644 --- a/Source/Scripts/Spells/Warlock.cs +++ b/Source/Scripts/Spells/Warlock.cs @@ -226,7 +226,7 @@ namespace Scripts.Spells.Warlock // WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST; allowing him to cast the WARLOCK_DEMONIC_CIRCLE_TELEPORT. // If not in range remove the WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST. - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DemonicCircleTeleport); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DemonicCircleTeleport, GetCastDifficulty()); if (GetTarget().IsWithinDist(circle, spellInfo.GetMaxRange(true))) { @@ -338,7 +338,7 @@ namespace Scripts.Spells.Warlock break; case CreatureFamily.Voidwalker: { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DemonicEmpowermentVoidwalker); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.DemonicEmpowermentVoidwalker, GetCastDifficulty()); int hp = (int)targetCreature.CountPctFromMaxHealth(GetCaster().CalculateSpellDamage(targetCreature, spellInfo, 0)); targetCreature.CastCustomSpell(targetCreature, SpellIds.DemonicEmpowermentVoidwalker, hp, 0, 0, true); break; @@ -556,7 +556,7 @@ namespace Scripts.Spells.Warlock if (modOwner) modOwner.ApplySpellMod(GetId(), SpellModOp.Cost, ref damage); - SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, caster, GetSpellInfo().Id, GetAura().GetSpellXSpellVisualId(), GetSpellInfo().SchoolMask, GetAura().GetCastGUID()); + SpellNonMeleeDamage damageInfo = new SpellNonMeleeDamage(caster, caster, GetSpellInfo(), GetAura().GetSpellXSpellVisualId(), GetSpellInfo().SchoolMask, GetAura().GetCastGUID()); damageInfo.periodicLog = true; damageInfo.damage = damage; caster.DealSpellDamage(damageInfo, false); diff --git a/Source/Scripts/Spells/Warrior.cs b/Source/Scripts/Spells/Warrior.cs index d2d2c4432..73a57cada 100644 --- a/Source/Scripts/Spells/Warrior.cs +++ b/Source/Scripts/Spells/Warrior.cs @@ -823,7 +823,7 @@ namespace Scripts.Spells.Warrior //Get the Remaining Damage from the aura (if exist) int remainingDamage = (int)target.GetRemainingPeriodicAmount(target.GetGUID(), SpellIds.TraumaEffect, AuraType.PeriodicDamage); //Get 25% of damage from the spell casted (Slam & Whirlwind) plus Remaining Damage from Aura - int damage = (int)(MathFunctions.CalculatePct(eventInfo.GetDamageInfo().GetDamage(), aurEff.GetAmount()) / Global.SpellMgr.GetSpellInfo(SpellIds.TraumaEffect).GetMaxTicks(Difficulty.None)) + remainingDamage; + int damage = (int)(MathFunctions.CalculatePct(eventInfo.GetDamageInfo().GetDamage(), aurEff.GetAmount()) / Global.SpellMgr.GetSpellInfo(SpellIds.TraumaEffect, GetCastDifficulty()).GetMaxTicks()) + remainingDamage; GetCaster().CastCustomSpell(SpellIds.TraumaEffect, SpellValueMod.BasePoint0, damage, target, true); } diff --git a/Source/Scripts/World/DuelReset.cs b/Source/Scripts/World/DuelReset.cs index 20628d71a..411d737f7 100644 --- a/Source/Scripts/World/DuelReset.cs +++ b/Source/Scripts/World/DuelReset.cs @@ -99,7 +99,7 @@ namespace Scripts.World { DateTime now = GameTime.GetGameTimeSystemPoint(); uint cooldownDuration = pair.Value.CooldownEnd > now ? (uint)(pair.Value.CooldownEnd - now).TotalMilliseconds : 0; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); return spellInfo.RecoveryTime < 10 * Time.Minute * Time.InMilliseconds && spellInfo.CategoryRecoveryTime < 10 * Time.Minute * Time.InMilliseconds && !pair.Value.OnHold @@ -113,7 +113,7 @@ namespace Scripts.World // remove cooldowns on spells that have < 10 min CD and has no onHold player.GetSpellHistory().ResetCooldowns(pair => { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); return spellInfo.RecoveryTime < 10 * Time.Minute * Time.InMilliseconds && spellInfo.CategoryRecoveryTime < 10 * Time.Minute * Time.InMilliseconds && !pair.Value.OnHold; diff --git a/Source/Scripts/World/ItemScripts.cs b/Source/Scripts/World/ItemScripts.cs index ba5401b4c..d37001608 100644 --- a/Source/Scripts/World/ItemScripts.cs +++ b/Source/Scripts/World/ItemScripts.cs @@ -126,7 +126,7 @@ namespace Scripts.World disabled = true; break; case 34475: - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellArcaneCharges); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellArcaneCharges, player.GetMap().GetDifficultyID()); if (spellInfo != null) Spell.SendCastResult(player, spellInfo, 0, castId, SpellCastResult.NotOnGround); break; @@ -275,7 +275,7 @@ namespace Scripts.World if (!player.GetTransport() || player.GetAreaId() != ItemScriptConst.AreaIdShatteredStraits) { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellPetrovBomb); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(ItemScriptConst.SpellPetrovBomb, Difficulty.None); if (spellInfo != null) Spell.SendCastResult(player, spellInfo, 0, castId, SpellCastResult.NotHere); diff --git a/Source/Scripts/World/NpcSpecial.cs b/Source/Scripts/World/NpcSpecial.cs index 93a78d2cb..a3894a01a 100644 --- a/Source/Scripts/World/NpcSpecial.cs +++ b/Source/Scripts/World/NpcSpecial.cs @@ -1907,7 +1907,7 @@ namespace Scripts.World.NpcSpecial break; } - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo != null && spellInfo.GetEffect(0).Effect == SpellEffectName.SummonObjectWild) return (uint)spellInfo.GetEffect(0).MiscValue; diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 625ad4ef7..d201bae68 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1,8 +1,8 @@ --- MySQL dump 10.16 Distrib 10.1.6-MariaDB, for Win64 (AMD64) +-- MySQL dump 10.13 Distrib 5.7.29, for Linux (x86_64) -- -- Host: localhost Database: characters -- ------------------------------------------------------ --- Server version 10.1.6-MariaDB +-- Server version 5.7.29-0ubuntu0.18.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -166,8 +166,8 @@ DROP TABLE IF EXISTS `auction_bidders`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `auction_bidders` ( - `auctionId` int unsigned NOT NULL, - `playerGuid` bigint unsigned NOT NULL, + `auctionId` int(10) unsigned NOT NULL, + `playerGuid` bigint(20) unsigned NOT NULL, PRIMARY KEY (`auctionId`,`playerGuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; @@ -189,8 +189,8 @@ DROP TABLE IF EXISTS `auction_items`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `auction_items` ( - `auctionId` int unsigned NOT NULL, - `itemGuid` bigint unsigned NOT NULL, + `auctionId` int(10) unsigned NOT NULL, + `itemGuid` bigint(20) unsigned NOT NULL, PRIMARY KEY (`auctionId`,`itemGuid`), UNIQUE KEY `idx_itemGuid` (`itemGuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -511,6 +511,7 @@ CREATE TABLE `character_aura` ( `spell` int(10) unsigned NOT NULL, `effectMask` int(10) unsigned NOT NULL, `recalculateMask` int(10) unsigned NOT NULL DEFAULT '0', + `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0', `stackCount` tinyint(3) unsigned NOT NULL DEFAULT '1', `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', @@ -2942,26 +2943,26 @@ CREATE TABLE `item_instance_azerite` ( `xp` bigint(20) unsigned NOT NULL DEFAULT '0', `level` int(10) unsigned NOT NULL DEFAULT '1', `knowledgeLevel` int(10) unsigned NOT NULL DEFAULT '0', - `selectedAzeriteEssences1specId` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences1azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences1azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences1azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences1azeriteEssenceId4` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences2specId` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences2azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences2azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences2azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences2azeriteEssenceId4` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences3specId` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences3azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences3azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences3azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences3azeriteEssenceId4` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences4specId` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences4azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences4azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences4azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', - `selectedAzeriteEssences4azeriteEssenceId4` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences1specId` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId1` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId2` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId3` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId4` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences2specId` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId1` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId2` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId3` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId4` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences3specId` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId1` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId2` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId3` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId4` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences4specId` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId1` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId2` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId3` int(10) unsigned DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId4` int(10) unsigned DEFAULT '0', PRIMARY KEY (`itemGuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; @@ -3026,7 +3027,7 @@ LOCK TABLES `item_instance_azerite_milestone_power` WRITE; UNLOCK TABLES; -- --- Table structure for table `item_instance_azerite` +-- Table structure for table `item_instance_azerite_unlocked_essence` -- DROP TABLE IF EXISTS `item_instance_azerite_unlocked_essence`; @@ -3342,6 +3343,7 @@ CREATE TABLE `pet_aura` ( `spell` int(10) unsigned NOT NULL, `effectMask` int(10) unsigned NOT NULL, `recalculateMask` int(10) unsigned NOT NULL DEFAULT '0', + `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0', `stackCount` tinyint(3) unsigned NOT NULL DEFAULT '1', `maxDuration` int(11) NOT NULL DEFAULT '0', `remainTime` int(11) NOT NULL DEFAULT '0', @@ -3711,11 +3713,11 @@ INSERT INTO `updates` VALUES ('2015_09_10_00_characters.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-09-10 22:50:42',0), ('2015_10_16_00_characters.sql','E3A3FFF0CB42F04A8DCF0CE4362143C16E2083AF','ARCHIVED','2015-10-15 21:54:11',0), ('2015_11_06_00_characters_2015_10_12_00.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-11-06 23:43:27',0), -('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',15), +('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',0), ('2015_11_23_00_characters.sql','9FC828E9E48E8E2E9B99A5A0073D6614C5BFC6B5','ARCHIVED','2015-11-22 23:27:34',0), ('2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-01-04 23:07:40',0), ('2016_04_05_00_characters_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-04-05 20:34:41',0), -('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 02:24:14',30), +('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 02:24:14',0), ('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','ARCHIVED','2016-04-11 18:14:18',0), ('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','ARCHIVED','2016-05-07 00:00:00',0), ('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','ARCHIVED','2016-05-26 17:06:16',0), @@ -3731,7 +3733,7 @@ INSERT INTO `updates` VALUES ('2016_07_19_08_characters.sql','FB41FD2F8A7114FEE154021A9D47488C4B12E2A9','ARCHIVED','2016-07-19 14:36:29',0), ('2016_08_15_00_characters.sql','BF0B5F453384210CD77C54E262A19B888AAA4095','ARCHIVED','2016-08-14 18:14:32',0), ('2016_08_25_00_characters.sql','4AD506C3FCE54238EF452AC07EC562BD41A9D50C','ARCHIVED','2016-08-25 22:54:11',0), -('2016_10_17_00_characters.sql','A0EF594CD73690D46A46031137DB0E895F079235','ARCHIVED','2016-10-16 16:33:05',25), +('2016_10_17_00_characters.sql','A0EF594CD73690D46A46031137DB0E895F079235','ARCHIVED','2016-10-16 16:33:05',0), ('2016_10_25_00_characters.sql','CC894484561CE138C10B69D34F7831CEDFAF496B','ARCHIVED','2016-10-25 17:19:35',0), ('2016_11_06_00_characters.sql','C7EC8B65C1BE7722C53BAB79C52C1549054178C0','ARCHIVED','2016-11-06 23:05:44',0), ('2016_12_09_00_characters.sql','2A68E4187CE7F7294CBC3804AC39F48B2727E64E','ARCHIVED','2016-12-09 18:38:46',0), @@ -3740,42 +3742,43 @@ INSERT INTO `updates` VALUES ('2017_01_29_00_characters.sql','E7475DCC13A0910FF23BF0EFB731629950A73A0D','ARCHIVED','2017-01-29 15:00:00',0), ('2017_02_26_00_characters_2016_09_13_00_characters.sql','2EF7AD507D097ABC74FF1E98A65BEC03B12E51C6','ARCHIVED','2017-02-26 19:57:47',0), ('2017_04_15_00_characters.sql','F118BA33CD7DDF2EE5673C6749C2965EFFF53C23','ARCHIVED','2017-04-15 12:10:50',0), -('2017_04_19_00_characters.sql','5A36FD9015ED024BC085F995F72DC81B47CD1093','ARCHIVED','2017-04-18 23:16:18',30), +('2017_04_19_00_characters.sql','5A36FD9015ED024BC085F995F72DC81B47CD1093','ARCHIVED','2017-04-18 23:16:18',0), ('2017_05_08_00_characters.sql','86B5603EEBE1DE0EA56DBB264257967CFE583F46','ARCHIVED','2017-05-08 23:54:40',0), ('2017_05_14_00_characters.sql','3452261F366BFE76BB59C0AAA674FA1513042899','ARCHIVED','2017-05-14 17:29:04',0), ('2017_05_24_00_characters.sql','02701BF57589CD41456A748AEF425CBB2D3E6AD7','ARCHIVED','2017-05-24 22:00:00',0), ('2017_06_04_00_characters.sql','BC80D2B7515CC6E01701070D2DA466727F36DB5E','ARCHIVED','2017-06-04 14:43:26',0), ('2017_08_20_00_characters.sql','8C5BBF6AEAA6C7DE2F40A7D3878C8187A4729F13','ARCHIVED','2017-08-20 17:00:00',0), ('2017_08_20_01_characters.sql','2F50D5E6BF3888B8C5270D79228A1D0601FAFF1D','ARCHIVED','2017-08-20 17:52:21',0), -('2017_10_29_00_characters.sql','8CFC473E7E87E58C317A72016BF69E9050D3BC83','ARCHIVED','2017-04-19 00:07:40',25), +('2017_10_29_00_characters.sql','8CFC473E7E87E58C317A72016BF69E9050D3BC83','ARCHIVED','2017-04-19 00:07:40',0), ('2018_02_03_00_characters.sql','73E9BFD848D7A22F2A7DD89CF64E30E3A8689512','ARCHIVED','2018-02-03 23:52:42',0), ('2018_02_08_00_characters.sql','75FA162A9B85D678B26F972371265F1EC2C75187','ARCHIVED','2018-02-08 22:23:28',0), -('2018_02_19_00_characters.sql','75A0FFAFD0633921708DB0F72F9CC9796ACB960B','RELEASED','2018-02-19 22:33:32',117), -('2018_03_04_00_characters.sql','2A4CD2EE2547E718490706FADC78BF36F0DED8D6','RELEASED','2018-03-04 18:15:24',0), -('2018_04_28_00_characters.sql','CBD0FDC0F32DE3F456F7CE3D9CAD6933CD6A50F5','RELEASED','2018-04-28 12:44:09',0), -('2018_07_28_00_characters.sql','31F66AE7831251A8915625EC7F10FA138AB8B654','RELEASED','2018-07-28 18:30:19',0), -('2018_07_31_00_characters.sql','7DA8D4A4534520B23E6F5BBD5B8EE205B799C798','RELEASED','2018-07-31 20:54:39',0), -('2018_12_09_00_characters.sql','7FE9641C93ED762597C08F1E9B6649C9EC2F0E47','RELEASED','2018-09-18 23:34:29',0), -('2018_12_09_01_characters.sql','C80B936AAD94C58A0F33382CED08CFB4E0B6AC34','RELEASED','2018-10-10 22:05:28',0), -('2018_12_09_02_characters.sql','DBBA0C06985CE8AC4E6E7E94BD6B2673E9ADFAE2','RELEASED','2018-12-02 17:32:31',0), -('2019_06_08_00_characters.sql','6C5AF52AEF03BC019B96E7A07592C22660F9327B','RELEASED','2019-06-03 20:04:47',0), -('2019_06_08_01_characters.sql','55076AFAF4B55DB4E34029C269EE0C84315C31BA','RELEASED','2019-06-04 22:11:47',0), -('2019_06_25_00_characters.sql','B8CBF79DEE02B40B01424327D31E52C70335BEC6','RELEASED','2019-06-25 22:40:37',0), -('2019_07_15_00_characters.sql','E1C77F604FB2A2FE8B32258CD0C9EC71BEA4F0FF','RELEASED','2019-06-25 22:40:37',0), -('2019_10_26_00_characters.sql','F1090ACDEB876A7BB5ED8829373F6305A217949A','RELEASED','2019-10-25 23:04:42',0), -('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_30_00_characters.sql','D0678E62B651AECA60C2DD6989BF80BD999AD12B','RELEASED','2019-11-29 22:42:01',0), -('2019_12_05_00_characters.sql','EA381C9634A5646A3168F15DF4E06A708A622762','RELEASED','2019-12-05 20:56:58',0), -('2020_02_17_00_characters.sql','E1519A81D35F19B48B3C75A83A270CB4BA0B84F2','RELEASED','2020-02-17 21:55:17',0), -('2020_04_20_00_characters.sql','977B5E0C894E0A7E80B2A9626F17CA636A69BD22','RELEASED','2020-04-20 19:08:18',0), -('2020_04_24_00_characters.sql','85E2E0395A9457A53D73A9E0A7BB39B7E4C429BF','RELEASED','2020-04-24 22:04:59',0), -('2020_04_25_00_characters_2017_04_03_00_characters.sql','00FA3EFADAF807AC96619A3FE47216E21C3FCB19','RELEASED','2020-04-25 00:00:00',0), -('2020_04_26_00_characters_2017_04_12_00_characters.sql','86AA94DA9B1EA283101100886C10F648C0CE6494','RELEASED','2020-04-26 00:00:00',0), -('2020_04_26_01_characters_2017_04_12_01_characters.sql','5A8A1215E3A2356722F52CD7A64BBE03D21FBEA3','RELEASED','2020-04-26 00:00:00',0); - +('2018_02_19_00_characters.sql','75A0FFAFD0633921708DB0F72F9CC9796ACB960B','ARCHIVED','2018-02-19 22:33:32',0), +('2018_03_04_00_characters.sql','2A4CD2EE2547E718490706FADC78BF36F0DED8D6','ARCHIVED','2018-03-04 18:15:24',0), +('2018_04_28_00_characters.sql','CBD0FDC0F32DE3F456F7CE3D9CAD6933CD6A50F5','ARCHIVED','2018-04-28 12:44:09',0), +('2018_07_28_00_characters.sql','31F66AE7831251A8915625EC7F10FA138AB8B654','ARCHIVED','2018-07-28 18:30:19',0), +('2018_07_31_00_characters.sql','7DA8D4A4534520B23E6F5BBD5B8EE205B799C798','ARCHIVED','2018-07-31 20:54:39',0), +('2018_12_09_00_characters.sql','7FE9641C93ED762597C08F1E9B6649C9EC2F0E47','ARCHIVED','2018-09-18 23:34:29',0), +('2018_12_09_01_characters.sql','C80B936AAD94C58A0F33382CED08CFB4E0B6AC34','ARCHIVED','2018-10-10 22:05:28',0), +('2018_12_09_02_characters.sql','DBBA0C06985CE8AC4E6E7E94BD6B2673E9ADFAE2','ARCHIVED','2018-12-02 17:32:31',0), +('2019_06_08_00_characters.sql','6C5AF52AEF03BC019B96E7A07592C22660F9327B','ARCHIVED','2019-06-03 20:04:47',0), +('2019_06_08_01_characters.sql','55076AFAF4B55DB4E34029C269EE0C84315C31BA','ARCHIVED','2019-06-04 22:11:47',0), +('2019_06_25_00_characters.sql','B8CBF79DEE02B40B01424327D31E52C70335BEC6','ARCHIVED','2019-06-25 22:40:37',0), +('2019_07_15_00_characters.sql','E1C77F604FB2A2FE8B32258CD0C9EC71BEA4F0FF','ARCHIVED','2019-06-25 22:40:37',0), +('2019_10_26_00_characters.sql','F1090ACDEB876A7BB5ED8829373F6305A217949A','ARCHIVED','2019-10-25 23:04:42',0), +('2019_10_26_01_characters.sql','59D5860930D02AB77D2AAA704C564957A9143760','ARCHIVED','2019-10-26 22:04:46',0), +('2019_11_03_00_characters.sql','DC789597F85B890E9A7901B4443DAD9CAEE2A02A','ARCHIVED','2019-11-03 14:13:27',0), +('2019_11_12_00_characters.sql','D4C642B4D48DAE9F56329BDE51C258323A132A91','ARCHIVED','2019-11-12 16:31:29',0), +('2019_11_22_00_characters.sql','95DFA71DBD75542C098CD86E9C0051C9690902F0','ARCHIVED','2019-11-20 15:10:12',0), +('2019_11_30_00_characters.sql','D0678E62B651AECA60C2DD6989BF80BD999AD12B','ARCHIVED','2019-11-29 22:42:01',0), +('2019_12_05_00_characters.sql','EA381C9634A5646A3168F15DF4E06A708A622762','ARCHIVED','2019-12-05 20:56:58',0), +('2020_02_17_00_characters.sql','E1519A81D35F19B48B3C75A83A270CB4BA0B84F2','ARCHIVED','2020-02-17 21:55:17',0), +('2020_04_20_00_characters.sql','977B5E0C894E0A7E80B2A9626F17CA636A69BD22','ARCHIVED','2020-04-20 19:08:18',0), +('2020_04_24_00_characters.sql','85E2E0395A9457A53D73A9E0A7BB39B7E4C429BF','ARCHIVED','2020-04-24 22:04:59',0), +('2020_04_25_00_characters_2017_04_03_00_characters.sql','00FA3EFADAF807AC96619A3FE47216E21C3FCB19','ARCHIVED','2020-04-25 00:00:00',0), +('2020_04_26_00_characters_2017_04_12_00_characters.sql','86AA94DA9B1EA283101100886C10F648C0CE6494','ARCHIVED','2020-04-26 00:00:00',0), +('2020_04_26_01_characters_2017_04_12_01_characters.sql','5A8A1215E3A2356722F52CD7A64BBE03D21FBEA3','ARCHIVED','2020-04-26 00:00:00',0), +('2020_06_12_00_characters.sql','DF16C99EFACA4DFADDDF35644AAC63F9B4AA2BD6','ARCHIVED','2020-06-11 16:24:56',0), +('2020_06_17_00_characters.sql','C3EE0D751E4B97CDF15F3BE27AAAE3646514A358','ARCHIVED','2020-06-17 17:04:56',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; @@ -3803,7 +3806,8 @@ INSERT INTO `updates_include` VALUES ('$/sql/updates/characters','RELEASED'), ('$/sql/custom/characters','RELEASED'), ('$/sql/old/6.x/characters','ARCHIVED'), -('$/sql/old/7/characters','ARCHIVED'); +('$/sql/old/7/characters','ARCHIVED'), +('$/sql/old/8.x/characters','ARCHIVED'); /*!40000 ALTER TABLE `updates_include` ENABLE KEYS */; UNLOCK TABLES; @@ -3868,4 +3872,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2018-02-19 22:43:09 +-- Dump completed on 2020-06-17 17:04:58