From 3da0e167e6ebf211f8f305efb3dbb4b1182ac1c9 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 26 Dec 2017 15:07:05 -0500 Subject: [PATCH] Core/Spell: revamp of immunities system --- .../Framework/Constants/Spells/SpellConst.cs | 7 +- Source/Game/Entities/Unit/Unit.Combat.cs | 6 + Source/Game/Entities/Unit/Unit.Fields.cs | 8 +- Source/Game/Entities/Unit/Unit.Movement.cs | 2 +- Source/Game/Entities/Unit/Unit.Spells.cs | 215 ++++--- Source/Game/Entities/Unit/Unit.cs | 3 + Source/Game/Entities/Vehicle.cs | 4 +- Source/Game/Server/WorldManager.cs | 3 + Source/Game/Spells/Auras/AuraEffect.cs | 307 +--------- Source/Game/Spells/Spell.cs | 507 +++++++++-------- Source/Game/Spells/SpellInfo.cs | 525 +++++++++++++++++- Source/Game/Spells/SpellManager.cs | 15 + Source/Scripts/Northrend/Dalaran.cs | 2 +- 13 files changed, 942 insertions(+), 662 deletions(-) diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 1357bb1b5..30c75a201 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -302,6 +302,7 @@ namespace Framework.Constants Sapped = 30, Enraged = 31, Wounded = 32, + Max = 33, ImmuneToMovementImpairmentAndLossControlMask = ((1 << Charm) | (1 << Disoriented) | (1 << Fear) | (1 << Root) | (1 << Sleep) | (1 << Snare) | (1 << Stun) | @@ -1370,9 +1371,9 @@ namespace Framework.Constants IsArcaneConcentration = 0x800000, // 23 Only Mage Arcane Concentration Have This Flag Unk24 = 0x1000000, // 24 Unk25 = 0x2000000, // 25 - Unk26 = 0x4000000, // 26 Unaffected By School Immunity + UnaffectedByAuraSchoolImmune = 0x4000000, // 26 Unaffected By School Immunity Unk27 = 0x8000000, // 27 - Unk28 = 0x10000000, // 28 + IgnoreItemCheck = 0x10000000, // 28 Spell is cast without checking item requirements (charges/reagents/totem) CantCrit = 0x20000000, // 29 Spell Can'T Crit TriggeredCanTriggerProc = 0x40000000, // 30 Spell Can Trigger Even If Triggered FoodBuff = 0x80000000 // 31 Food Or Drink Buff (Like Well Fed) @@ -1539,7 +1540,7 @@ namespace Framework.Constants Unk17 = 0x20000, // 17 Only 27965 (Suicide) Spell. HasChargeEffect = 0x40000, // 18 Only Spells That Have Charge Among Effects. ZoneTeleport = 0x80000, // 19 Teleports To Specific Zones. - Unk20 = 0x100000, // 20 Blink, Divine Shield, Ice Block + UsableInStunFearConfusion = 0x100000, // 20 Blink, Divine Shield, Ice Block Unk21 = 0x200000, // 21 Not Set Unk22 = 0x400000, // 22 Unk23 = 0x800000, // 23 Motivate, Mutilate, Shattering Throw diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index d41db87ea..fa84f80a1 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -858,6 +858,12 @@ namespace Game.Entities } public uint DealDamage(Unit victim, uint damage, CleanDamage cleanDamage = null, DamageEffectType damagetype = DamageEffectType.Direct, SpellSchoolMask damageSchoolMask = SpellSchoolMask.Normal, SpellInfo spellProto = null, bool durabilityLoss = true) { + if (victim.IsImmunedToDamage(spellProto)) + { + SendSpellDamageImmune(victim, spellProto.Id, false); + return 0; + } + if (victim.IsAIEnabled) victim.GetAI().DamageTaken(this, ref damage); diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index fe05147d2..a587e09a7 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -85,7 +85,7 @@ namespace Game.Entities //Spells protected Dictionary m_currentSpells = new Dictionary((int)CurrentSpellTypes.Max); Dictionary CustomSpellValueMod = new Dictionary(); - MultiMap m_spellImmune = new MultiMap(); + MultiMap[] m_spellImmune = new MultiMap[(int)SpellImmunity.Max]; uint[] m_interruptMask = new uint[2]; protected int m_procDeep; bool m_AutoRepeatFirstCast; @@ -132,12 +132,6 @@ namespace Game.Entities ushort _meleeAnimKitId; } - public struct SpellImmune - { - public uint spellType; - public uint spellId; - } - public class DiminishingReturn { public DiminishingReturn() { } diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 47f46312f..83565ba64 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -1403,7 +1403,7 @@ namespace Game.Entities return GetPositionZ() - offset; } - Unit GetUnitBeingMoved() + public Unit GetUnitBeingMoved() { Player player = ToPlayer(); if (player) diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index d020c59c2..472c16907 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -794,20 +794,20 @@ namespace Game.Entities // Parry // For spells // Resist - public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spell, bool CanReflect) + public SpellMissInfo SpellHitResult(Unit victim, SpellInfo spellInfo, bool CanReflect) { + if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + return SpellMissInfo.None; + // Check for immune - if (victim.IsImmunedToSpell(spell)) + if (victim.IsImmunedToSpell(spellInfo)) return SpellMissInfo.Immune; // All positive spells can`t miss // @todo client not show miss log for this spells - so need find info for this in dbc and use it! - if (spell.IsPositive() + if (spellInfo.IsPositive() && (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell return SpellMissInfo.None; - // Check for immune - if (victim.IsImmunedToDamage(spell)) - return SpellMissInfo.Immune; if (this == victim) return SpellMissInfo.None; @@ -822,22 +822,22 @@ namespace Game.Entities int reflectchance = victim.GetTotalAuraModifier(AuraType.ReflectSpells); var mReflectSpellsSchool = victim.GetAuraEffectsByType(AuraType.ReflectSpellsSchool); foreach (var eff in mReflectSpellsSchool) - if (Convert.ToBoolean(eff.GetMiscValue() & (int)spell.GetSchoolMask())) + if (Convert.ToBoolean(eff.GetMiscValue() & (int)spellInfo.GetSchoolMask())) reflectchance += eff.GetAmount(); if (reflectchance > 0 && RandomHelper.randChance(reflectchance)) return SpellMissInfo.Reflect; } - switch (spell.DmgClass) + switch (spellInfo.DmgClass) { case SpellDmgClass.Ranged: case SpellDmgClass.Melee: - return MeleeSpellHitResult(victim, spell); + return MeleeSpellHitResult(victim, spellInfo); case SpellDmgClass.None: return SpellMissInfo.None; case SpellDmgClass.Magic: - return MagicSpellHitResult(victim, spell); + return MagicSpellHitResult(victim, spellInfo); } return SpellMissInfo.None; } @@ -845,11 +845,6 @@ namespace Game.Entities // Melee based spells hit result calculations SpellMissInfo MeleeSpellHitResult(Unit victim, SpellInfo spellInfo) { - // Spells with SPELL_ATTR3_IGNORE_HIT_RESULT will additionally fully ignore - // resist and deflect chances - if (spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) - return SpellMissInfo.None; - WeaponAttackType attType = WeaponAttackType.BaseAttack; // Check damage class instead of attack type to correctly handle judgements @@ -1433,10 +1428,11 @@ namespace Game.Entities { Spell spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled); if (spell) - if (spell.getState() != SpellState.Finished) - return spell.GetSpellInfo().HasAttribute(SpellAttr5.CanChannelWhenMoving) && spell.IsChannelActive(); + if (spell.getState() != SpellState.Finished && spell.IsChannelActive()) + if (!spell.GetSpellInfo().IsMoveAllowedChannel()) + return false; - return false; + return true; } bool HasBreakableByDamageAuraType(AuraType type, uint excludeAura) @@ -1552,24 +1548,35 @@ namespace Game.Entities SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType); } - public void ApplySpellImmune(uint spellId, SpellImmunity op, object type, bool apply) + public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellSchoolMask type, bool apply) + { + ApplySpellImmune(spellId, op, (uint)type, apply); + } + + public void ApplySpellImmune(uint spellId, SpellImmunity op, AuraType type, bool apply) + { + ApplySpellImmune(spellId, op, (uint)type, apply); + } + + public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellEffectName type, bool apply) + { + ApplySpellImmune(spellId, op, (uint)type, apply); + } + + public void ApplySpellImmune(uint spellId, SpellImmunity op, uint type, bool apply) { if (apply) { - m_spellImmune[op].RemoveAll(p => p.spellType == Convert.ToUInt32(type)); - - SpellImmune Immune = new SpellImmune(); - Immune.spellId = spellId; - Immune.spellType = Convert.ToUInt32(type); - m_spellImmune.Add(op, Immune); + m_spellImmune[(int)op].Add(type, spellId); } else { - foreach (var spell in m_spellImmune[op].ToList()) + var bounds = m_spellImmune[(int)op].LookupByKey(type); + foreach (var spell in bounds) { - if (spell.spellId == spellId && spell.spellType == Convert.ToUInt32(type)) + if (spell == spellId) { - m_spellImmune.Remove(op, spell); + m_spellImmune[(int)op].Remove(type, spell); break; } } @@ -1581,28 +1588,27 @@ namespace Game.Entities return false; // Single spell immunity. - var idList = m_spellImmune.LookupByKey(SpellImmunity.Id); - foreach (var immune in idList) - if (immune.spellType == spellInfo.Id) - return true; + var idList = m_spellImmune[(int)SpellImmunity.Id]; + if (idList.ContainsKey(spellInfo.Id)) + return true; if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) return false; - if (spellInfo.Dispel != 0) + uint dispel = (uint)spellInfo.Dispel; + if (dispel != 0) { - var dispelList = m_spellImmune.LookupByKey(SpellImmunity.Dispel); - foreach (var immune in dispelList) - if (immune.spellType == (int)spellInfo.Dispel) - return true; + var dispelList = m_spellImmune[(int)SpellImmunity.Dispel]; + if (dispelList.ContainsKey(dispel)) + return true; } // Spells that don't have effectMechanics. - if (spellInfo.Mechanic != 0) + uint mechanic = (uint)spellInfo.Mechanic; + if (mechanic != 0) { - var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic); - foreach (var immune in mechanicList) - if (immune.spellType == (int)spellInfo.Mechanic) + var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic]; + if (mechanicList.ContainsKey(mechanic)) return true; } @@ -1611,7 +1617,7 @@ namespace Game.Entities { // State/effect immunities applied by aura expect full spell immunity // Ignore effects with mechanic, they are supposed to be checked separately - if (effect == null || !effect.IsEffect()) + if (effect == null) continue; if (!IsImmunedToSpellEffect(spellInfo, effect.EffectIndex)) @@ -1624,13 +1630,13 @@ namespace Game.Entities if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects. return true; - if (spellInfo.Id != 42292 && spellInfo.Id != 59752) + if (!spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) { - var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School); - foreach (var immune in schoolList) + var schoolList = m_spellImmune[(int)SpellImmunity.School]; + foreach (var pair in schoolList) { - SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(immune.spellId); - if (Convert.ToBoolean(immune.spellType & (uint)spellInfo.GetSchoolMask()) + SpellInfo immuneSpellInfo = Global.SpellMgr.GetSpellInfo(pair.Value); + if (Convert.ToBoolean(pair.Key & (uint)spellInfo.GetSchoolMask()) && !(immuneSpellInfo != null && immuneSpellInfo.IsPositive() && spellInfo.IsPositive()) && !spellInfo.CanPierceImmuneAura(immuneSpellInfo)) return true; @@ -1642,18 +1648,18 @@ namespace Game.Entities public uint GetSchoolImmunityMask() { uint mask = 0; - var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.School); - foreach (var spell in mechanicList) - mask |= spell.spellType; + var mechanicList = m_spellImmune[(int)SpellImmunity.School]; + foreach (var pair in mechanicList) + mask |= pair.Key; return mask; } public uint GetMechanicImmunityMask() { uint mask = 0; - var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic); - foreach (var spell in mechanicList) - mask |= (uint)(1 << (int)spell.spellType); + var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic]; + foreach (var pair in mechanicList) + mask |= (1u << (int)pair.Value); return mask; } @@ -1668,75 +1674,76 @@ namespace Game.Entities // If m_immuneToEffect type contain this effect type, IMMUNE effect. uint eff = (uint)effect.Effect; - var effectList = m_spellImmune.LookupByKey(SpellImmunity.Effect); - foreach (var immune in effectList) - if (immune.spellType == eff) - return true; + var effectList = m_spellImmune[(int)SpellImmunity.Effect]; + if (effectList.ContainsKey(eff)) + return true; uint mechanic = (uint)effect.Mechanic; if (mechanic != 0) { - var mechanicList = m_spellImmune.LookupByKey(SpellImmunity.Mechanic); - foreach (var immune in mechanicList) - if (immune.spellType == mechanic) - return true; + var mechanicList = m_spellImmune[(int)SpellImmunity.Mechanic]; + if (mechanicList.ContainsKey(mechanic)) + return true; } - uint aura = (uint)effect.ApplyAuraName; - if (aura != 0) + if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) { - var list = m_spellImmune.LookupByKey(SpellImmunity.State); - foreach (var immune in list) - if (immune.spellType == aura) - if (!spellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) - return true; - - // Check for immune to application of harmful magical effects - var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool); - foreach (var immune in immuneAuraApply) - if (spellInfo.Dispel == DispelType.Magic && // Magic debuff - Convert.ToBoolean(immune.GetMiscValue() & (uint)spellInfo.GetSchoolMask()) && // Check school - !spellInfo.IsPositiveEffect(index)) // Harmful + uint aura = (uint)effect.ApplyAuraName; + if (aura != 0) + { + var list = m_spellImmune[(int)SpellImmunity.State]; + if (list.ContainsKey(aura)) return true; + + if (!spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + { + // Check for immune to application of harmful magical effects + var immuneAuraApply = GetAuraEffectsByType(AuraType.ModImmuneAuraApplySchool); + foreach (var auraEffect in immuneAuraApply) + if (Convert.ToBoolean(auraEffect.GetMiscValue() & (int)spellInfo.GetSchoolMask()) && // Check school + !spellInfo.IsPositiveEffect(index)) // Harmful + return true; + } + } } return false; } - public bool IsImmunedToDamage(SpellSchoolMask shoolMask) + public bool IsImmunedToDamage(SpellSchoolMask schoolMask) { // If m_immuneToSchool type contain this school type, IMMUNE damage. - var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School); + var schoolList = m_spellImmune[(int)SpellImmunity.School]; foreach (var immune in schoolList) - if (Convert.ToBoolean(immune.spellType & (uint)shoolMask)) + if (Convert.ToBoolean(immune.Key & (uint)schoolMask)) return true; // If m_immuneToDamage type contain magic, IMMUNE damage. - var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage); + var damageList = m_spellImmune[(int)SpellImmunity.Damage]; foreach (var immune in damageList) - if (Convert.ToBoolean(immune.spellType & (uint)shoolMask)) + if (Convert.ToBoolean(immune.Key & (uint)schoolMask)) return true; return false; } public bool IsImmunedToDamage(SpellInfo spellInfo) { - if (spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) + if (spellInfo == null) return false; - uint shoolMask = (uint)spellInfo.GetSchoolMask(); - if (spellInfo.Id != 42292 && spellInfo.Id != 59752) - { - // If m_immuneToSchool type contain this school type, IMMUNE damage. - var schoolList = m_spellImmune.LookupByKey(SpellImmunity.School); - foreach (var immune in schoolList) - if (Convert.ToBoolean(immune.spellType & shoolMask) && !spellInfo.CanPierceImmuneAura(Global.SpellMgr.GetSpellInfo(immune.spellId))) - return true; - } + if (spellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || spellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + return false; + + uint schoolMask = (uint)spellInfo.GetSchoolMask(); + // If m_immuneToSchool type contain this school type, IMMUNE damage. + 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))) + return true; // If m_immuneToDamage type contain magic, IMMUNE damage. - var damageList = m_spellImmune.LookupByKey(SpellImmunity.Damage); + var damageList = m_spellImmune[(int)SpellImmunity.Damage]; foreach (var immune in damageList) - if (Convert.ToBoolean(immune.spellType & shoolMask)) + if (Convert.ToBoolean(immune.Key & schoolMask)) return true; return false; @@ -2173,7 +2180,7 @@ namespace Game.Entities bool isSpellBlocked(Unit victim, SpellInfo spellProto, WeaponAttackType attackType = WeaponAttackType.BaseAttack) { // These spells can't be blocked - if (spellProto != null && spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock)) + if (spellProto != null && (spellProto.HasAttribute(SpellAttr0.ImpossibleDodgeParryBlock) || spellProto.HasAttribute(SpellAttr3.IgnoreHitResult))) return false; // Can't block when casting/controlled @@ -2657,28 +2664,6 @@ namespace Game.Entities return null; } - public void ApplySpellDispelImmunity(SpellInfo spellProto, DispelType type, bool apply) - { - ApplySpellImmune(spellProto.Id, SpellImmunity.Dispel, type, apply); - - if (apply && spellProto.HasAttribute(SpellAttr1.DispelAurasOnImmunity)) - { - // Create dispel mask by dispel type - uint dispelMask = SpellInfo.GetDispelMask(type); - // Dispel all existing auras vs current dispel type - var auras = GetAppliedAuras(); - foreach (var pair in auras) - { - SpellInfo spell = pair.Value.GetBase().GetSpellInfo(); - if ((spell.GetDispelMask() & dispelMask) != 0) - { - // Dispel aura - RemoveAura(pair); - } - } - } - } - public DiminishingLevels GetDiminishing(DiminishingGroup group) { DiminishingReturn diminish = m_Diminishing[(int)group]; diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index e03d2a529..7e4fb36ac 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -54,6 +54,9 @@ namespace Game.Entities m_modAttackSpeedPct = new float[] { 1.0f, 1.0f, 1.0f }; m_deathState = DeathState.Alive; + for (byte i = 0; i < (int)SpellImmunity.Max; ++i) + m_spellImmune[i] = new MultiMap(); + for (byte i = 0; i < (int)UnitMods.End; ++i) m_auraModifiersGroup[i] = new float[] { 0.0f, 100.0f, 1.0f, 0.0f, 1.0f }; diff --git a/Source/Game/Entities/Vehicle.cs b/Source/Game/Entities/Vehicle.cs index ee0df27eb..b092a9219 100644 --- a/Source/Game/Entities/Vehicle.cs +++ b/Source/Game/Entities/Vehicle.cs @@ -151,8 +151,8 @@ namespace Game.Entities _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolImmunity, true); _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.ModUnattackable, true); _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.SchoolAbsorb, true); - _me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Shield, true); - _me.ApplySpellImmune(0, SpellImmunity.Mechanic, Mechanics.Immune_Shield, true); + _me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Shield, true); + _me.ApplySpellImmune(0, SpellImmunity.Mechanic, (uint)Mechanics.Immune_Shield, true); // ... Resistance, Split damage, Change stats ... _me.ApplySpellImmune(0, SpellImmunity.State, AuraType.DamageShield, true); diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index 708a95336..12bc2be0d 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -377,6 +377,9 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo diminishing infos..."); Global.SpellMgr.LoadSpellInfoDiminishing(); + Log.outInfo(LogFilter.ServerLoading, "Loading SpellInfo immunity infos..."); + Global.SpellMgr.LoadSpellInfoImmunities(); + Log.outInfo(LogFilter.ServerLoading, "Loading PetFamilySpellsStore Data..."); Global.SpellMgr.LoadPetFamilySpellsStore(); diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index f8945e45c..1ce2c20fb 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -2703,7 +2703,7 @@ namespace Game.Spells { //Players on flying mounts must be immune to polymorph if (target.IsTypeId(TypeId.Player)) - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); + target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)Mechanics.Polymorph, apply); // Dragonmaw Illusion (overwrite mount model, mounted aura already applied) if (apply && target.HasAuraEffect(42016, 0) && target.GetMountID() != 0) @@ -2767,228 +2767,13 @@ namespace Game.Spells /*** IMMUNITY ***/ /*********************************************************/ [AuraEffectHandler(AuraType.MechanicImmunityMask)] - void HandleModStateImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply) + void HandleModMechanicImmunityMask(AuraApplication aurApp, AuraEffectHandleModes mode, bool apply) { if (!mode.HasAnyFlag(AuraEffectHandleModes.Real)) return; Unit target = aurApp.GetTarget(); - List aura_immunity_list = new List(); - - uint mechanic_immunity_list = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root) - | (1 << (int)Mechanics.Fear) | (1 << (int)Mechanics.Stun) - | (1 << (int)Mechanics.Sleep) | (1 << (int)Mechanics.Charm) - | (1 << (int)Mechanics.Sapped) | (1 << (int)Mechanics.Horror) - | (1 << (int)Mechanics.Polymorph) | (1 << (int)Mechanics.Disoriented) - | (1 << (int)Mechanics.Freeze) | (1 << (int)Mechanics.Turn); - - int miscVal = GetMiscValue(); - switch (miscVal) - { - case 27: - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Silence, apply); - aura_immunity_list.Add(AuraType.ModSilence); - break; - case 96: - case 1615: - { - if (HasAmount()) - { - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModConfuse); - aura_immunity_list.Add(AuraType.ModFear); - aura_immunity_list.Add(AuraType.ModRoot2); - } - break; - } - case 679: - { - if (GetId() == 57742) - { - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModConfuse); - aura_immunity_list.Add(AuraType.ModFear); - aura_immunity_list.Add(AuraType.ModRoot2); - } - break; - } - case 1557: - { - if (GetId() == 64187) - { - mechanic_immunity_list = (1 << (int)Mechanics.Stun); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - aura_immunity_list.Add(AuraType.ModStun); - } - else - { - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModConfuse); - aura_immunity_list.Add(AuraType.ModFear); - aura_immunity_list.Add(AuraType.ModRoot2); - } - break; - } - case 1614: - case 1694: - { - target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.AttackMe, apply); - aura_immunity_list.Add(AuraType.ModTaunt); - break; - } - case 1630: - { - if (!HasAmount()) - { - target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.AttackMe, apply); - aura_immunity_list.Add(AuraType.ModTaunt); - } - else - { - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModConfuse); - aura_immunity_list.Add(AuraType.ModFear); - aura_immunity_list.Add(AuraType.ModRoot2); - } - break; - } - case 477: - case 1733: - { - if (!HasAmount()) - { - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.KnockBack, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Effect, SpellEffectName.KnockBackDest, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModConfuse); - aura_immunity_list.Add(AuraType.ModFear); - aura_immunity_list.Add(AuraType.ModRoot2); - } - break; - } - case 878: - { - if (GetAmount() == 1) - { - mechanic_immunity_list = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Stun) - | (1 << (int)Mechanics.Disoriented) | (1 << (int)Mechanics.Freeze); - - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - aura_immunity_list.Add(AuraType.ModStun); - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - } - break; - } - default: - break; - } - - if (aura_immunity_list.Empty()) - { - if (Convert.ToBoolean(miscVal & (1 << 10))) - aura_immunity_list.Add(AuraType.ModStun); - if (Convert.ToBoolean(miscVal & (1 << 1))) - aura_immunity_list.Add(AuraType.Transform); - - // These flag can be recognized wrong: - if (Convert.ToBoolean(miscVal & (1 << 6))) - aura_immunity_list.Add(AuraType.ModDecreaseSpeed); - if (Convert.ToBoolean(miscVal & (1 << 0))) - { - aura_immunity_list.Add(AuraType.ModRoot); - aura_immunity_list.Add(AuraType.ModRoot2); - } - if (Convert.ToBoolean(miscVal & (1 << 2))) - aura_immunity_list.Add(AuraType.ModConfuse); - if (Convert.ToBoolean(miscVal & (1 << 9))) - aura_immunity_list.Add(AuraType.ModFear); - if (Convert.ToBoolean(miscVal & (1 << 7))) - aura_immunity_list.Add(AuraType.ModDisarm); - } - - // apply immunities - foreach (var iter in aura_immunity_list) - target.ApplySpellImmune(GetId(), SpellImmunity.State, iter, apply); - - if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)) - { - target.RemoveAurasWithMechanic(mechanic_immunity_list, AuraRemoveMode.Default, GetId()); - foreach (var iter in aura_immunity_list) - target.RemoveAurasByType(iter); - } + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } [AuraEffectHandler(AuraType.MechanicImmunity)] @@ -2998,52 +2783,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - uint mechanic; - - switch (GetId()) - { - case 34471: // The Beast Within - case 19574: // Bestial Wrath - mechanic = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Charm, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Disoriented, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Fear, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sleep, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Freeze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Knockout, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Polymorph, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Banish, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Shackle, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Turn, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Horror, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Daze, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Sapped, apply); - break; - case 42292: // PvP trinket - case 59752: // Every Man for Himself - case 53490: // Bullheaded - mechanic = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; - // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point - break; - case 54508: // Demonic Empowerment - mechanic = (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Snare, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Root, apply); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, Mechanics.Stun, apply); - break; - default: - if (GetMiscValue() < 1) - return; - mechanic = (uint)(1 << GetMiscValue()); - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, GetMiscValue(), apply); - break; - } - - if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)) - target.RemoveAurasWithMechanic(mechanic, AuraRemoveMode.Default, GetId()); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } [AuraEffectHandler(AuraType.EffectImmunity)] @@ -3053,8 +2793,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - - target.ApplySpellImmune(GetId(), SpellImmunity.Effect, GetMiscValue(), apply); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); // when removing flag aura, handle flag drop Player player = target.ToPlayer(); @@ -3078,11 +2817,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - - target.ApplySpellImmune(GetId(), SpellImmunity.State, GetMiscValue(), apply); - - if (apply && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity)) - target.RemoveAurasByType((AuraType)GetMiscValue(), ObjectGuid.Empty, GetBase()); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } [AuraEffectHandler(AuraType.SchoolImmunity)] @@ -3092,8 +2827,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - - target.ApplySpellImmune(GetId(), SpellImmunity.School, (uint)GetMiscValue(), (apply)); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); if (GetSpellInfo().Mechanic == Mechanics.Banish) { @@ -3103,9 +2837,9 @@ namespace Game.Spells { bool banishFound = false; var banishAuras = target.GetAuraEffectsByType(GetAuraType()); - foreach (var eff in banishAuras) + foreach (var aurEff in banishAuras) { - if (eff.GetSpellInfo().Mechanic == Mechanics.Banish) + if (aurEff.GetSpellInfo().Mechanic == Mechanics.Banish) { banishFound = true; break; @@ -3124,21 +2858,6 @@ namespace Game.Spells if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); - - /// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else - if ((apply) && GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) && GetSpellInfo().IsPositive()) //Only positive immunity removes auras - { - int schoolMask = GetMiscValue(); - target.RemoveAppliedAuras(aurApp1 => - { - SpellInfo spell = aurApp1.GetBase().GetSpellInfo(); - return Convert.ToBoolean((int)spell.GetSchoolMask() & schoolMask)//Check for school mask - && GetSpellInfo().CanDispelAura(spell) - && !aurApp1.IsPositive() //Don't remove positive spells - && !spell.IsPassive() // Don't remove passive auras - && spell.Id != GetId(); //Don't remove self - }); - } } [AuraEffectHandler(AuraType.DamageImmunity)] @@ -3148,8 +2867,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - - target.ApplySpellImmune(GetId(), SpellImmunity.Damage, (uint)GetMiscValue(), apply); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } [AuraEffectHandler(AuraType.DispelImmunity)] @@ -3159,8 +2877,7 @@ namespace Game.Spells return; Unit target = aurApp.GetTarget(); - - target.ApplySpellDispelImmunity(m_spellInfo, (DispelType)GetMiscValue(), (apply)); + m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } /*********************************************************/ @@ -4608,7 +4325,7 @@ namespace Game.Spells { // Recently Bandaged case 11196: - target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, GetMiscValue(), apply); + target.ApplySpellImmune(GetId(), SpellImmunity.Mechanic, (uint)GetMiscValue(), apply); break; // Unstable Power case 24658: diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 4b1a22d98..e8d99911c 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2091,7 +2091,7 @@ namespace Game.Spells return SpellMissInfo.Evade; // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case - if (m_spellInfo.Speed != 0.0f && (unit.IsImmunedToDamage(m_spellInfo) || unit.IsImmunedToSpell(m_spellInfo))) + if (m_spellInfo.Speed != 0.0f && unit.IsImmunedToSpell(m_spellInfo)) return SpellMissInfo.Immune; // disable effects to which unit is immune @@ -2523,7 +2523,8 @@ namespace Game.Spells if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreComboPoints) || m_CastItem != null || m_caster.m_playerMovingMe == null) m_needComboPoints = false; - SpellCastResult result = CheckCast(true); + uint param1 = 0, param2 = 0; + SpellCastResult result = CheckCast(true, ref param1, ref param2); // target is checked in too many locations and with different results to handle each of them // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks if (Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreTargetCheck) && result == SpellCastResult.BadTargets) @@ -2548,7 +2549,10 @@ namespace Game.Spells m_caster.ToPlayer().SetSpellModTakingSpell(this, false); } - SendCastResult(result); + if (param1 != 0 || param2 != 0) + SendCastResult(result, param1, param2); + else + SendCastResult(result); finish(false); return; @@ -2749,10 +2753,11 @@ namespace Game.Spells // skip check if done already (for instant cast spells for example) if (!skipCheck) { - SpellCastResult castResult = CheckCast(false); + uint param1 = 0, param2 = 0; + SpellCastResult castResult = CheckCast(false, ref param1, ref param2); if (castResult != SpellCastResult.SpellCastOk) { - SendCastResult(castResult); + SendCastResult(castResult, param1, param2); SendInterrupted(0); //restore spell mods if (m_caster.IsTypeId(TypeId.Player)) @@ -3316,7 +3321,7 @@ namespace Game.Spells m_caster.AttackStop(); } - static void FillSpellCastFailedArgs(T packet, ObjectGuid castId, SpellInfo spellInfo, SpellCastResult result, SpellCustomErrors customError, uint[] misc, Player caster) where T : CastFailedBase + static void FillSpellCastFailedArgs(T packet, ObjectGuid castId, SpellInfo spellInfo, SpellCastResult result, SpellCustomErrors customError, uint? param1, uint? param2, Player caster) where T : CastFailedBase { packet.CastID = castId; packet.SpellID = (int)spellInfo.Id; @@ -3325,112 +3330,183 @@ namespace Game.Spells switch (result) { case SpellCastResult.NotReady: - packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag) + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = 0;// unknown (value 1 update cooldowns on client flag) break; case SpellCastResult.RequiresSpellFocus: - packet.FailedArg1 = (int)spellInfo.RequiresSpellFocus; // SpellFocusObject.dbc id + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = (int)spellInfo.RequiresSpellFocus; // SpellFocusObject.dbc id break; case SpellCastResult.RequiresArea: // AreaTable.dbc id - // hardcode areas limitation case - switch (spellInfo.Id) + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else { - case 41617: // Cenarion Mana Salve - case 41619: // Cenarion Healing Salve - packet.FailedArg1 = 3905; - break; - case 41618: // Bottled Nethergon Energy - case 41620: // Bottled Nethergon Vapor - packet.FailedArg1 = 3842; - break; - case 45373: // Bloodberry Elixir - packet.FailedArg1 = 4075; - break; - default: // default case (don't must be) - packet.FailedArg1 = 0; - break; + // hardcode areas limitation case + switch (spellInfo.Id) + { + case 41617: // Cenarion Mana Salve + case 41619: // Cenarion Healing Salve + packet.FailedArg1 = 3905; + break; + case 41618: // Bottled Nethergon Energy + case 41620: // Bottled Nethergon Vapor + packet.FailedArg1 = 3842; + break; + case 45373: // Bloodberry Elixir + packet.FailedArg1 = 4075; + break; + default: // default case (don't must be) + packet.FailedArg1 = 0; + break; + } } break; case SpellCastResult.Totems: - if (spellInfo.Totem[0] != 0) - packet.FailedArg1 = (int)spellInfo.Totem[0]; - if (spellInfo.Totem[1] != 0) - packet.FailedArg2 = (int)spellInfo.Totem[1]; + if (param1.HasValue) + { + packet.FailedArg1 = (int)param1; + if (param2.HasValue) + packet.FailedArg2 = (int)param2; + } + else + { + if (spellInfo.Totem[0] != 0) + packet.FailedArg1 = (int)spellInfo.Totem[0]; + if (spellInfo.Totem[1] != 0) + packet.FailedArg2 = (int)spellInfo.Totem[1]; + } break; case SpellCastResult.TotemCategory: - if (spellInfo.TotemCategory[0] != 0) - packet.FailedArg1 = (int)spellInfo.TotemCategory[0]; - if (spellInfo.TotemCategory[1] != 0) - packet.FailedArg2 = (int)spellInfo.TotemCategory[1]; + if (param1.HasValue) + { + packet.FailedArg1 = (int)param1; + if (param2.HasValue) + packet.FailedArg2 = (int)param2; + } + else + { + if (spellInfo.TotemCategory[0] != 0) + packet.FailedArg1 = (int)spellInfo.TotemCategory[0]; + if (spellInfo.TotemCategory[1] != 0) + packet.FailedArg2 = (int)spellInfo.TotemCategory[1]; + } break; case SpellCastResult.EquippedItemClass: case SpellCastResult.EquippedItemClassMainhand: case SpellCastResult.EquippedItemClassOffhand: - packet.FailedArg1 = (int)spellInfo.EquippedItemClass; - packet.FailedArg2 = spellInfo.EquippedItemSubClassMask; + if (param1.HasValue && param2.HasValue) + { + packet.FailedArg1 = (int)param1; + packet.FailedArg2 = (int)param2; + } + else + { + packet.FailedArg1 = (int)spellInfo.EquippedItemClass; + packet.FailedArg2 = spellInfo.EquippedItemSubClassMask; + } break; case SpellCastResult.TooManyOfItem: { - uint item = 0; - foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) - if (effect.ItemType != 0) - item = effect.ItemType; - ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item); - if (proto != null && proto.GetItemLimitCategory() != 0) - packet.FailedArg1 = (int)proto.GetItemLimitCategory(); + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + { + uint item = 0; + foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(caster.GetMap().GetDifficultyID())) + if (effect.ItemType != 0) + item = effect.ItemType; + ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(item); + if (proto != null && proto.GetItemLimitCategory() != 0) + packet.FailedArg1 = (int)proto.GetItemLimitCategory(); + } break; } case SpellCastResult.PreventedByMechanic: - packet.FailedArg1 = (int)spellInfo.GetAllEffectsMechanicMask(); // SpellMechanic.dbc id + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = (int)spellInfo.GetAllEffectsMechanicMask(); // SpellMechanic.dbc id break; case SpellCastResult.NeedExoticAmmo: - packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct... + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = spellInfo.EquippedItemSubClassMask; // seems correct... break; case SpellCastResult.NeedMoreItems: - packet.FailedArg1 = 0; // Item id - packet.FailedArg2 = 0; // Item count? + if (param1.HasValue && param2.HasValue) + { + packet.FailedArg1 = (int)param1; + packet.FailedArg2 = (int)param2; + } + else + { + packet.FailedArg1 = 0; // Item id + packet.FailedArg2 = 0; // Item count? + } break; case SpellCastResult.MinSkill: - packet.FailedArg1 = 0; // SkillLine.dbc id - packet.FailedArg2 = 0; // required skill value + if (param1.HasValue && param2.HasValue) + { + packet.FailedArg1 = (int)param1; + packet.FailedArg2 = (int)param2; + } + else + { + packet.FailedArg1 = 0; // SkillLine.dbc id + packet.FailedArg2 = 0; // required skill value + } break; case SpellCastResult.FishingTooLow: - packet.FailedArg1 = 0; // required fishing skill + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = 0; // required fishing skill break; case SpellCastResult.CustomError: packet.FailedArg1 = (int)customError; break; case SpellCastResult.Silenced: - packet.FailedArg1 = 0; // Unknown + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else + packet.FailedArg1 = 0; // Unknown break; case SpellCastResult.Reagents: { - uint missingItem = 0; - for (uint i = 0; i < SpellConst.MaxReagents; i++) + if (param1.HasValue) + packet.FailedArg1 = (int)param1; + else { - if (spellInfo.Reagent[i] <= 0) - continue; - - uint itemid = (uint)spellInfo.Reagent[i]; - uint itemcount = spellInfo.ReagentCount[i]; - - if (!caster.HasItemCount(itemid, itemcount)) + uint missingItem = 0; + for (uint i = 0; i < SpellConst.MaxReagents; i++) { - missingItem = itemid; - break; - } - } + if (spellInfo.Reagent[i] <= 0) + continue; - packet.FailedArg1 = (int)missingItem; // first missing item + uint itemid = (uint)spellInfo.Reagent[i]; + uint itemcount = spellInfo.ReagentCount[i]; + + if (!caster.HasItemCount(itemid, itemcount)) + { + missingItem = itemid; + break; + } + } + + packet.FailedArg1 = (int)missingItem; // first missing item + } break; } case SpellCastResult.CantUntalent: { - if (misc != null) - { - TalentRecord talent = CliDB.TalentStorage.LookupByKey(misc[0]); - if (talent != null) - packet.FailedArg1 = (int)talent.SpellID; - } + Contract.Assert(param1.HasValue); + packet.FailedArg1 = (int)param1; break; } // TODO: SPELL_FAILED_NOT_STANDING @@ -3439,7 +3515,7 @@ namespace Game.Spells } } - public void SendCastResult(SpellCastResult result) + public void SendCastResult(SpellCastResult result, uint? param1 = null, uint? param2 = null) { if (result == SpellCastResult.SpellCastOk) return; @@ -3447,7 +3523,7 @@ namespace Game.Spells if (!m_caster.IsTypeId(TypeId.Player)) return; - if (m_caster.ToPlayer().GetSession().PlayerLoading()) // don't send cast results at loading time + if (m_caster.ToPlayer().IsLoading()) // don't send cast results at loading time return; if (_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DontReportCastError)) @@ -3455,11 +3531,11 @@ namespace Game.Spells CastFailed castFailed = new CastFailed(); castFailed.SpellXSpellVisualID = (int)m_SpellVisual; - FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, m_misc.GetRawData(), m_caster.ToPlayer()); + FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster.ToPlayer()); m_caster.ToPlayer().SendPacket(castFailed); } - public void SendPetCastResult(SpellCastResult result) + public void SendPetCastResult(SpellCastResult result, uint? param1 = null, uint? param2 = null) { if (result == SpellCastResult.SpellCastOk) return; @@ -3472,18 +3548,18 @@ namespace Game.Spells result = SpellCastResult.DontReport; PetCastFailed petCastFailed = new PetCastFailed(); - FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SpellCustomErrors.None, m_misc.GetRawData(), owner.ToPlayer()); + FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SpellCustomErrors.None, param1, param2, owner.ToPlayer()); owner.ToPlayer().SendPacket(petCastFailed); } - public static void SendCastResult(Player caster, SpellInfo spellInfo, uint spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SpellCustomErrors.None, uint[] misc = null) + public static void SendCastResult(Player caster, SpellInfo spellInfo, uint spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SpellCustomErrors.None, uint? param1 = null, uint? param2 = null) { if (result == SpellCastResult.SpellCastOk) return; CastFailed packet = new CastFailed(); packet.SpellXSpellVisualID = (int)spellVisual; - FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, misc, caster); + FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster); caster.SendPacket(packet); } @@ -4329,6 +4405,12 @@ namespace Game.Spells } public SpellCastResult CheckCast(bool strict) + { + uint param1 = 0, param2 = 0; + return CheckCast(strict, ref param1, ref param2); + } + + public SpellCastResult CheckCast(bool strict, ref uint param1, ref uint param2) { SpellCastResult castResult = SpellCastResult.SpellCastOk; // check death state @@ -4395,13 +4477,15 @@ namespace Game.Spells bool checkForm = true; // Ignore form req aura var ignore = m_caster.GetAuraEffectsByType(AuraType.ModIgnoreShapeshift); - foreach (var aura in ignore) + foreach (var aurEff in ignore) { - if (!aura.IsAffectingSpell(m_spellInfo)) + if (!aurEff.IsAffectingSpell(m_spellInfo)) continue; + checkForm = false; break; } + if (checkForm) { // Cannot be used in this stance/form @@ -4630,7 +4714,7 @@ namespace Game.Spells // always (except passive spells) check items (focus object can be required for any type casts) if (!m_spellInfo.IsPassive()) { - castResult = CheckItems(); + castResult = CheckItems(ref param1, ref param2); if (castResult != SpellCastResult.SpellCastOk) return castResult; } @@ -4650,7 +4734,7 @@ namespace Game.Spells if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreCasterAuras)) { - castResult = CheckCasterAuras(); + castResult = CheckCasterAuras(ref param1); if (castResult != SpellCastResult.SpellCastOk) return castResult; } @@ -4909,7 +4993,7 @@ namespace Game.Spells break; if (!m_caster.IsTypeId(TypeId.Player) // only players can open locks, gather etc. - // we need a go target in case of TARGET_GAMEOBJECT_TARGET + // we need a go target in case of TARGET_GAMEOBJECT_TARGET || (effect.TargetA.GetTarget() == Targets.GameobjectTarget && m_targets.GetGOTarget() == null)) return SpellCastResult.BadTargets; @@ -5139,7 +5223,10 @@ namespace Game.Spells if (talent == null) return SpellCastResult.DontReport; if (m_caster.GetSpellHistory().HasCooldown(talent.SpellID)) + { + param1 = talent.SpellID; return SpellCastResult.CantUntalent; + } break; } case SpellEffectName.GiveArtifactPower: @@ -5362,146 +5449,109 @@ namespace Game.Spells return CheckCast(true); } - SpellCastResult CheckCasterAuras() + SpellCastResult CheckCasterAuras(ref uint param1) { // spells totally immuned to caster auras (wsg flag drop, give marks etc) if (m_spellInfo.HasAttribute(SpellAttr6.IgnoreCasterAuras)) return SpellCastResult.SpellCastOk; - int school_immune = 0; - uint mechanic_immune = 0; - uint dispel_immune = 0; - - // Check if the spell grants school or mechanic immunity. - // We use bitmasks so the loop is done only once and not on every aura check below. - if (m_spellInfo.HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + bool usableWhileStunned = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned); + bool usableWhileFeared = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared); + bool usableWhileConfused = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused); + if (m_spellInfo.HasAttribute(SpellAttr7.UsableInStunFearConfusion)) { - foreach (SpellEffectInfo effect in GetEffects()) - { - if (effect == null) - continue; - - if (effect.ApplyAuraName == AuraType.SchoolImmunity) - school_immune |= effect.MiscValue; - else if (effect.ApplyAuraName == AuraType.MechanicImmunity) - mechanic_immune |= (uint)(1 << effect.MiscValue); - else if (effect.ApplyAuraName == AuraType.DispelImmunity) - dispel_immune |= SpellInfo.GetDispelMask((DispelType)effect.MiscValue); - } - // immune movement impairment and loss of control - if (m_spellInfo.Id == 42292 || m_spellInfo.Id == 59752 || m_spellInfo.Id == 19574 || m_spellInfo.Id == 53490) - mechanic_immune = (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + usableWhileStunned = true; + usableWhileFeared = true; + usableWhileConfused = true; } - bool usableInStun = m_spellInfo.HasAttribute(SpellAttr5.UsableWhileStunned); // Check whether the cast should be prevented by any state you might have. - SpellCastResult prevented_reason = SpellCastResult.SpellCastOk; - // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out - UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags); // Get unit state - if (Convert.ToBoolean(unitflag & UnitFlags.Stunned)) + SpellCastResult result = SpellCastResult.SpellCastOk; + // Get unit state + UnitFlags unitflag = (UnitFlags)m_caster.GetUInt32Value(UnitFields.Flags); + if (!m_caster.GetCharmerGUID().IsEmpty()) { - // spell is usable while stunned, check if caster has allowed stun auras, another stun types must prevent cast spell - if (usableInStun) - { - uint allowedStunMask = - 1 << (int)Mechanics.Stun - | 1 << (int)Mechanics.Freeze - | 1 << (int)Mechanics.Sapped - | 1 << (int)Mechanics.Sleep; - - bool foundNotStun = false; - var stunAuras = m_caster.GetAuraEffectsByType(AuraType.ModStun); - foreach (var auraEffect in stunAuras) - { - uint mechanicMask = auraEffect.GetSpellInfo().GetAllEffectsMechanicMask(); - if (mechanicMask != 0 && !Convert.ToBoolean(mechanicMask & allowedStunMask)) - { - foundNotStun = true; - break; - } - } - if (foundNotStun) - prevented_reason = SpellCastResult.Stunned; - } - else - prevented_reason = SpellCastResult.Stunned; + Unit charmer = m_caster.GetCharmer(); + if (charmer) + if (charmer.GetUnitBeingMoved() != m_caster && CheckCasterNotImmunedCharmAuras(ref param1)) + result = SpellCastResult.Charmed; } - else if (unitflag.HasAnyFlag(UnitFlags.Confused) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused)) - prevented_reason = SpellCastResult.Confused; - else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared)) - prevented_reason = SpellCastResult.Fleeing; - else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence)) - prevented_reason = SpellCastResult.Silenced; - else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify)) - prevented_reason = SpellCastResult.Pacified; + else if (unitflag.HasAnyFlag(UnitFlags.Stunned) && !usableWhileStunned && CheckCasterNotImmunedStunAuras(ref param1)) + result = SpellCastResult.Stunned; + else if (unitflag.HasAnyFlag(UnitFlags.Silenced) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence) && CheckCasterNotImmunedSilenceAuras(ref param1)) + result = SpellCastResult.Silenced; + else if (unitflag.HasAnyFlag(UnitFlags.Pacified) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify) && CheckCasterNotImmunedPacifyAuras(ref param1)) + result = SpellCastResult.Pacified; + else if (unitflag.HasAnyFlag(UnitFlags.Fleeing) && !usableWhileFeared && CheckCasterNotImmunedFearAuras(ref param1)) + result = SpellCastResult.Fleeing; + else if (unitflag.HasAnyFlag(UnitFlags.Confused) && !usableWhileConfused && CheckCasterNotImmunedDisorientAuras(ref param1)) + result = SpellCastResult.Confused; else if (m_caster.HasFlag(UnitFields.Flags2, UnitFlags2.NoActions) && m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.NoActions)) - prevented_reason = SpellCastResult.NoActions; + result = SpellCastResult.NoActions; // Attr must make flag drop spell totally immune from all effects - if (prevented_reason != SpellCastResult.SpellCastOk) - { - if (school_immune != 0 || mechanic_immune != 0 || dispel_immune != 0) - { - //Checking auras is needed now, because you are prevented by some state but the spell grants immunity. - foreach (var pair in m_caster.GetAppliedAuras()) - { - Aura aura = pair.Value.GetBase(); - SpellInfo auraInfo = aura.GetSpellInfo(); - if (Convert.ToBoolean(auraInfo.GetAllEffectsMechanicMask() & mechanic_immune)) - continue; - if (Convert.ToBoolean((int)auraInfo.GetSchoolMask() & school_immune) && !auraInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune)) - continue; - if (Convert.ToBoolean((int)auraInfo.GetDispelMask() & dispel_immune)) - continue; - - //Make a second check for spell failed so the right SPELL_FAILED message is returned. - //That is needed when your casting is prevented by multiple states and you are only immune to some of them. - foreach (SpellEffectInfo effect in GetEffects()) - { - if (effect == null) - continue; - - AuraEffect part = aura.GetEffect(effect.EffectIndex); - if (part != null) - { - switch (part.GetAuraType()) - { - case AuraType.ModStun: - if (!usableInStun || !Convert.ToBoolean(auraInfo.GetAllEffectsMechanicMask() & (1 << (int)Mechanics.Stun))) - return SpellCastResult.Stunned; - break; - case AuraType.ModConfuse: - if (!m_spellInfo.HasAttribute(SpellAttr5.UsableWhileConfused)) - return SpellCastResult.Confused; - break; - case AuraType.ModFear: - if (!m_spellInfo.HasAttribute(SpellAttr5.UsableWhileFeared)) - return SpellCastResult.Fleeing; - break; - case AuraType.ModSilence: - case AuraType.ModPacify: - case AuraType.ModPacifySilence: - if (m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Pacify)) - return SpellCastResult.Pacified; - else if (m_spellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence)) - return SpellCastResult.Silenced; - break; - default: - break; - } - } - - } - } - } - // You are prevented from casting and the spell casted does not grant immunity. Return a failed error. - else - return prevented_reason; - } + if (result != SpellCastResult.SpellCastOk) + return (param1 != 0) ? SpellCastResult.PreventedByMechanic : result; return SpellCastResult.SpellCastOk; } + // based on sub_00804430 from 12340 client + bool CheckCasterHasNotImmunedAuraType(AuraType auraType, ref uint param1) + { + // Checking auras is needed now, because you are prevented by some state but the spell grants immunity. + var auraEffects = m_caster.GetAuraEffectsByType(auraType); + if (auraEffects.Empty()) + return false; + + foreach (AuraEffect aurEff in auraEffects) + { + if (m_spellInfo.CanSpellCastOverrideAuraEffect(aurEff)) + continue; + + param1 = (uint)aurEff.GetSpellEffectInfo().Mechanic; + if (param1 == 0) + param1 = (uint)aurEff.GetSpellInfo().Mechanic; + return true; + } + + return false; + } + + bool CheckCasterNotImmunedCharmAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModCharm, ref param1) || + CheckCasterHasNotImmunedAuraType(AuraType.AoeCharm, ref param1) || + CheckCasterHasNotImmunedAuraType(AuraType.ModPossess, ref param1); + } + + bool CheckCasterNotImmunedStunAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModStun, ref param1); + } + + bool CheckCasterNotImmunedSilenceAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModSilence, ref param1) || + CheckCasterHasNotImmunedAuraType(AuraType.ModPacifySilence, ref param1); + } + + bool CheckCasterNotImmunedPacifyAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModPacify, ref param1) || + CheckCasterHasNotImmunedAuraType(AuraType.ModPacifySilence, ref param1); + } + + bool CheckCasterNotImmunedFearAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModFear, ref param1); + } + + bool CheckCasterNotImmunedDisorientAuras(ref uint param1) + { + return CheckCasterHasNotImmunedAuraType(AuraType.ModConfuse, ref param1); + } + SpellCastResult CheckArenaAndRatedBattlegroundCastRules() { bool isRatedBattleground = false; // NYI @@ -5727,13 +5777,15 @@ namespace Game.Spells return SpellCastResult.SpellCastOk; } - SpellCastResult CheckItems() + SpellCastResult CheckItems(ref uint param1, ref uint param2) { Player player = m_caster.ToPlayer(); - if (!player) return SpellCastResult.SpellCastOk; + if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreItemCheck)) + return SpellCastResult.SpellCastOk; + if (m_CastItem == null) { if (!m_castItemGUID.IsEmpty()) @@ -5809,13 +5861,11 @@ namespace Game.Spells // check target item if (!m_targets.GetItemTargetGUID().IsEmpty()) { - if (!m_caster.IsTypeId(TypeId.Player)) - return SpellCastResult.BadTargets; - - if (m_targets.GetItemTarget() == null) + Item item = m_targets.GetItemTarget(); + if (item == null) return SpellCastResult.ItemGone; - if (!m_targets.GetItemTarget().IsFitToSpellRequirements(m_spellInfo)) + if (!item.IsFitToSpellRequirements(m_spellInfo)) return SpellCastResult.EquippedItemClass; } // if not item target then required item must be equipped @@ -5868,7 +5918,10 @@ namespace Game.Spells } } if (!player.HasItemCount(itemid, itemcount)) + { + param1 = itemid; return SpellCastResult.Reagents; + } } } @@ -6073,21 +6126,26 @@ namespace Game.Spells } case SpellEffectName.Prospecting: { - if (m_targets.GetItemTarget() == null) + Item item = m_targets.GetItemTarget(); + if (!item) return SpellCastResult.CantBeProspected; //ensure item is a prospectable ore - if (!Convert.ToBoolean(m_targets.GetItemTarget().GetTemplate().GetFlags() & ItemFlags.IsProspectable)) + if (!Convert.ToBoolean(item.GetTemplate().GetFlags() & ItemFlags.IsProspectable)) return SpellCastResult.CantBeProspected; //prevent prospecting in trade slot - if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID()) + if (item.GetOwnerGUID() != m_caster.GetGUID()) return SpellCastResult.CantBeProspected; //Check for enough skill in jewelcrafting - uint item_prospectingskilllevel = m_targets.GetItemTarget().GetTemplate().GetRequiredSkillRank(); + uint item_prospectingskilllevel = item.GetTemplate().GetRequiredSkillRank(); if (item_prospectingskilllevel > player.GetSkillValue(SkillType.Jewelcrafting)) return SpellCastResult.LowCastlevel; //make sure the player has the required ores in inventory - if (m_targets.GetItemTarget().GetCount() < 5) + if (item.GetCount() < 5) + { + param1 = item.GetEntry(); + param2 = 5; return SpellCastResult.NeedMoreItems; + } if (!LootStorage.Prospecting.HaveLootFor(m_targets.GetItemTargetEntry())) return SpellCastResult.CantBeProspected; @@ -6096,21 +6154,26 @@ namespace Game.Spells } case SpellEffectName.Milling: { - if (m_targets.GetItemTarget() == null) + Item item = m_targets.GetItemTarget(); + if (!item) return SpellCastResult.CantBeMilled; //ensure item is a millable herb - if (!(m_targets.GetItemTarget().GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsMillable))) + if (!(item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.IsMillable))) return SpellCastResult.CantBeMilled; //prevent milling in trade slot - if (m_targets.GetItemTarget().GetOwnerGUID() != m_caster.GetGUID()) + if (item.GetOwnerGUID() != m_caster.GetGUID()) return SpellCastResult.CantBeMilled; //Check for enough skill in inscription - uint item_millingskilllevel = m_targets.GetItemTarget().GetTemplate().GetRequiredSkillRank(); + uint item_millingskilllevel = item.GetTemplate().GetRequiredSkillRank(); if (item_millingskilllevel > player.GetSkillValue(SkillType.Inscription)) return SpellCastResult.LowCastlevel; //make sure the player has the required herbs in inventory - if (m_targets.GetItemTarget().GetCount() < 5) + if (item.GetCount() < 5) + { + param1 = item.GetEntry(); + param2 = 5; return SpellCastResult.NeedMoreItems; + } if (!LootStorage.Milling.HaveLootFor(m_targets.GetItemTargetEntry())) return SpellCastResult.CantBeMilled; @@ -6675,7 +6738,7 @@ namespace Game.Spells { Log.outDebug(LogFilter.Spells, "Spell.LoadScripts: Script `{0}` for spell `{1}` is loaded now", script._GetScriptName(), m_spellInfo.Id); script.Register(); - } + } } void CallScriptBeforeCastHandlers() @@ -7145,7 +7208,7 @@ namespace Game.Spells return false; } - public static implicit operator bool (Spell spell) + public static implicit operator bool(Spell spell) { return spell != null; } diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index f90823ab5..fbf815d91 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -54,7 +54,7 @@ namespace Game.Spells _effects[pair.Key][effect.EffectIndex] = new SpellEffectInfo(scaling, this, effect.EffectIndex, effect); } } - } + } SpellName = data.Entry.Name; @@ -638,32 +638,35 @@ namespace Game.Spells return IsAffected(affectSpell.SpellFamilyName, mod.mask); } - public bool CanPierceImmuneAura(SpellInfo aura) + public bool CanPierceImmuneAura(SpellInfo auraSpellInfo) { + // aura can't be pierced + if (auraSpellInfo == null || auraSpellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) + return false; + // these spells pierce all avalible spells (Resurrection Sickness for example) if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) return true; - // these spells (Cyclone for example) can pierce all... | ...but not these (Divine shield, Ice block, Cyclone and Banish for example) - if (HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) - && !(aura != null && (aura.Mechanic == Mechanics.Immune_Shield || aura.Mechanic == Mechanics.Invulnerability || aura.Mechanic == Mechanics.Banish))) + // Dispels other auras on immunity, check if this spell makes the unit immune to aura + if (HasAttribute(SpellAttr1.DispelAurasOnImmunity) && CanSpellProvideImmunityAgainstAura(auraSpellInfo)) return true; return false; } - public bool CanDispelAura(SpellInfo aura) + public bool CanDispelAura(SpellInfo auraSpellInfo) { - // These spells (like Mass Dispel) can dispell all auras - if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability) && !aura.IsDeathPersistent()) - return true; - // These auras (like Divine Shield) can't be dispelled - if (aura.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) + if (auraSpellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) return false; + // These spells (like Mass Dispel) can dispel all auras + if (HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) + return true; + // These auras (Cyclone for example) are not dispelable - if (aura.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune)) + if (auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) || auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) return false; return true; @@ -1204,7 +1207,7 @@ namespace Game.Spells // if target is magnet (i.e Grounding Totem) the check is skipped //if (target.IsMagnet()) - //return true; + //return true; uint creatureType = target.GetCreatureTypeMask(); return TargetCreatureType == 0 || creatureType == 0 || Convert.ToBoolean(creatureType & TargetCreatureType); @@ -2017,6 +2020,478 @@ namespace Game.Spells return 8 * Time.InMilliseconds; } + public void _LoadImmunityInfo() + { + var loadImmunityInfoFn = new Action(effectInfo => + { + uint schoolImmunityMask = 0; + uint applyHarmfulAuraImmunityMask = 0; + uint mechanicImmunityMask = 0; + uint dispelImmunity = 0; + uint damageImmunityMask = 0; + + int miscVal = effectInfo.MiscValue; + int amount = effectInfo.CalcValue(); + + ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo(); + + switch (effectInfo.ApplyAuraName) + { + case AuraType.MechanicImmunityMask: + { + switch (miscVal) + { + case 96: // Free Friend, Uncontrollable Frenzy, Warlord's Presence + { + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + break; + } + case 1615: // Incite Rage, Wolf Spirit, Overload, Lightning Tendrils + { + switch (Id) + { + case 43292: // Incite Rage + case 49172: // Wolf Spirit + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + goto case 61869; + // no break intended + case 61869: // Overload + case 63481: + case 61887: // Lightning Tendrils + case 63486: + mechanicImmunityMask |= (1 << (int)Mechanics.Interrupt) | (1 << (int)Mechanics.Silence); + + immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBack); + immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBackDest); + break; + default: + break; + } + break; + } + case 679: // Mind Control, Avenging Fury + { + if (Id == 57742) // Avenging Fury + { + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + } + break; + } + case 1557: // Startling Roar, Warlord Roar, Break Bonds, Stormshield + { + if (Id == 64187) // Stormshield + { + mechanicImmunityMask |= (1 << (int)Mechanics.Stun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + } + else + { + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + } + break; + } + case 1614: // Fixate + case 1694: // Fixated, Lightning Tendrils + { + immuneInfo.SpellEffectImmune.Add(SpellEffectName.AttackMe); + immuneInfo.AuraTypeImmune.Add(AuraType.ModTaunt); + break; + } + case 1630: // Fervor, Berserk + { + if (Id == 64112) // Berserk + { + immuneInfo.SpellEffectImmune.Add(SpellEffectName.AttackMe); + immuneInfo.AuraTypeImmune.Add(AuraType.ModTaunt); + } + else + { + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + } + break; + } + case 477: // Bladestorm + case 1733: // Bladestorm, Killing Spree + { + if (amount == 0) + { + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + + immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBack); + immuneInfo.SpellEffectImmune.Add(SpellEffectName.KnockBackDest); + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + } + break; + } + case 878: // Whirlwind, Fog of Corruption, Determination + { + if (Id == 66092) // Determination + { + mechanicImmunityMask |= (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Stun) + | (1 << (int)Mechanics.Disoriented) | (1 << (int)Mechanics.Freeze); + + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + } + break; + } + default: + break; + } + + if (immuneInfo.AuraTypeImmune.Empty()) + { + if (miscVal.HasAnyFlag(1 << 10)) + immuneInfo.AuraTypeImmune.Add(AuraType.ModStun); + if (miscVal.HasAnyFlag(1 << 1)) + immuneInfo.AuraTypeImmune.Add(AuraType.Transform); + + // These flag can be recognized wrong: + if (miscVal.HasAnyFlag(1 << 6)) + immuneInfo.AuraTypeImmune.Add(AuraType.ModDecreaseSpeed); + if (miscVal.HasAnyFlag(1 << 0)) + { + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot); + immuneInfo.AuraTypeImmune.Add(AuraType.ModRoot2); + } + if (miscVal.HasAnyFlag(1 << 2)) + immuneInfo.AuraTypeImmune.Add(AuraType.ModConfuse); + if (miscVal.HasAnyFlag(1 << 9)) + immuneInfo.AuraTypeImmune.Add(AuraType.ModFear); + if (miscVal.HasAnyFlag(1 << 7)) + immuneInfo.AuraTypeImmune.Add(AuraType.ModDisarm); + } + break; + } + case AuraType.MechanicImmunity: + { + switch (Id) + { + case 34471: // The Beast Within + case 19574: // Bestial Wrath + case 42292: // PvP trinket + case 46227: // Medallion of Immunity + case 59752: // Every Man for Himself + case 53490: // Bullheaded + case 65547: // PvP Trinket + case 134946: // Supremacy of the Alliance + case 134956: // Supremacy of the Horde + case 195710: // Honorable Medallion + case 208683: // Gladiator's Medallion + mechanicImmunityMask |= (uint)Mechanics.ImmuneToMovementImpairmentAndLossControlMask; + break; + case 54508: // Demonic Empowerment + mechanicImmunityMask |= (1 << (int)Mechanics.Snare) | (1 << (int)Mechanics.Root) | (1 << (int)Mechanics.Stun); + break; + default: + if (miscVal < 1) + return; + + mechanicImmunityMask |= 1u << miscVal; + break; + } + break; + } + case AuraType.EffectImmunity: + { + immuneInfo.SpellEffectImmune.Add((SpellEffectName)miscVal); + break; + } + case AuraType.StateImmunity: + { + immuneInfo.AuraTypeImmune.Add((AuraType)miscVal); + break; + } + case AuraType.SchoolImmunity: + { + schoolImmunityMask |= (uint)miscVal; + break; + } + case AuraType.ModImmuneAuraApplySchool: + { + applyHarmfulAuraImmunityMask |= (uint)miscVal; + break; + } + case AuraType.DamageImmunity: + { + damageImmunityMask |= (uint)miscVal; + break; + } + case AuraType.DispelImmunity: + { + dispelImmunity = (uint)miscVal; + break; + } + default: + break; + } + + immuneInfo.SchoolImmuneMask = schoolImmunityMask; + immuneInfo.ApplyHarmfulAuraImmuneMask = applyHarmfulAuraImmunityMask; + immuneInfo.MechanicImmuneMask = mechanicImmunityMask; + immuneInfo.DispelImmune = dispelImmunity; + immuneInfo.DamageSchoolMask = damageImmunityMask; + }); + + foreach (var effects in _effects) + { + foreach (SpellEffectInfo effect in effects.Value) + { + if (effect == null) + continue; + + loadImmunityInfoFn(effect); + } + } + } + + public void ApplyAllSpellImmunitiesTo(Unit target, SpellEffectInfo effect, bool apply) + { + ImmunityInfo immuneInfo = effect.GetImmunityInfo(); + + uint schoolImmunity = immuneInfo.SchoolImmuneMask; + if (schoolImmunity != 0) + { + target.ApplySpellImmune(Id, SpellImmunity.School, schoolImmunity, apply); + + if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + { + target.RemoveAppliedAuras(aurApp => + { + SpellInfo auraSpellInfo = aurApp.GetBase().GetSpellInfo(); + return (((uint)auraSpellInfo.GetSchoolMask() & schoolImmunity) != 0 && // Check for school mask + CanDispelAura(auraSpellInfo) && + (IsPositive() != aurApp.IsPositive()) && // Check spell vs aura possitivity + !auraSpellInfo.IsPassive() && // Don't remove passive auras + auraSpellInfo.Id != Id); // Don't remove self + }); + } + } + + uint mechanicImmunity = immuneInfo.MechanicImmuneMask; + if (mechanicImmunity != 0) + { + for (uint i = 0; i < (int)Mechanics.Max; ++i) + if (Convert.ToBoolean(mechanicImmunity & (1 << (int)i))) + target.ApplySpellImmune(Id, SpellImmunity.Mechanic, i, apply); + + if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + target.RemoveAurasWithMechanic(mechanicImmunity, AuraRemoveMode.Default, Id); + } + + uint dispelImmunity = immuneInfo.DispelImmune; + if (dispelImmunity != 0) + { + target.ApplySpellImmune(Id, SpellImmunity.Dispel, dispelImmunity, apply); + + if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + { + target.RemoveAppliedAuras(aurApp => + { + SpellInfo spellInfo = aurApp.GetBase().GetSpellInfo(); + if ((uint)spellInfo.Dispel == dispelImmunity) + return true; + + return false; + }); + } + } + + uint damageImmunity = immuneInfo.DamageSchoolMask; + if (damageImmunity != 0) + target.ApplySpellImmune(Id, SpellImmunity.Damage, damageImmunity, apply); + + foreach (AuraType auraType in immuneInfo.AuraTypeImmune) + { + target.ApplySpellImmune(Id, SpellImmunity.State, auraType, apply); + if (apply && HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + target.RemoveAurasByType(auraType); + } + + foreach (SpellEffectName effectType in immuneInfo.SpellEffectImmune) + target.ApplySpellImmune(Id, SpellImmunity.Effect, effectType, apply); + } + + bool CanSpellProvideImmunityAgainstAura(SpellInfo auraSpellInfo) + { + if (auraSpellInfo == null) + return false; + + foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None)) + { + if (effectInfo == null) + continue; + + ImmunityInfo immuneInfo = effectInfo.GetImmunityInfo(); + + if (!auraSpellInfo.HasAttribute(SpellAttr1.UnaffectedBySchoolImmune) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + { + uint schoolImmunity = immuneInfo.SchoolImmuneMask; + if (schoolImmunity != 0) + if (((uint)auraSpellInfo.SchoolMask & schoolImmunity) != 0) + return true; + } + + uint mechanicImmunity = immuneInfo.MechanicImmuneMask; + if (mechanicImmunity != 0) + if ((mechanicImmunity & (1 << (int)auraSpellInfo.Mechanic)) != 0) + return true; + + uint dispelImmunity = immuneInfo.DispelImmune; + if (dispelImmunity != 0) + if ((uint)auraSpellInfo.Dispel == dispelImmunity) + return true; + + bool immuneToAllEffects = true; + foreach (SpellEffectInfo auraSpellEffectInfo in auraSpellInfo.GetEffectsForDifficulty(Difficulty.None)) + { + if (auraSpellEffectInfo == null) + continue; + + SpellEffectName effectName = auraSpellEffectInfo.Effect; + if (effectName == 0) + continue; + + if (!immuneInfo.SpellEffectImmune.Contains(effectName)) + { + immuneToAllEffects = false; + break; + } + + uint mechanic = (uint)auraSpellEffectInfo.Mechanic; + if (mechanic != 0) + { + if (!Convert.ToBoolean(immuneInfo.MechanicImmuneMask & (1 << (int)mechanic))) + { + immuneToAllEffects = false; + break; + } + } + + if (!auraSpellInfo.HasAttribute(SpellAttr3.IgnoreHitResult)) + { + AuraType auraName = auraSpellEffectInfo.ApplyAuraName; + if (auraName != 0) + { + bool isImmuneToAuraEffectApply = false; + if (!immuneInfo.AuraTypeImmune.Contains(auraName)) + isImmuneToAuraEffectApply = true; + + if (!isImmuneToAuraEffectApply && !auraSpellInfo.IsPositiveEffect(auraSpellEffectInfo.EffectIndex) && !auraSpellInfo.HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune)) + { + uint applyHarmfulAuraImmunityMask = immuneInfo.ApplyHarmfulAuraImmuneMask; + if (applyHarmfulAuraImmunityMask != 0) + if (((uint)auraSpellInfo.GetSchoolMask() & applyHarmfulAuraImmunityMask) != 0) + isImmuneToAuraEffectApply = true; + } + + if (!isImmuneToAuraEffectApply) + { + immuneToAllEffects = false; + break; + } + } + } + } + + if (immuneToAllEffects) + return true; + } + + return false; + } + + // based on client sub_007FDFA0 + public bool CanSpellCastOverrideAuraEffect(AuraEffect aurEff) + { + if (!HasAttribute(SpellAttr1.DispelAurasOnImmunity)) + return false; + + if (aurEff.GetSpellInfo().HasAttribute(SpellAttr0.UnaffectedByInvulnerability)) + return false; + + foreach (SpellEffectInfo effectInfo in GetEffectsForDifficulty(Difficulty.None)) + { + if (effectInfo == null) + continue; + + if (effectInfo.Effect != SpellEffectName.ApplyAura) + continue; + + uint miscValue = (uint)effectInfo.MiscValue; + switch (effectInfo.ApplyAuraName) + { + case AuraType.StateImmunity: + if (miscValue != (uint)aurEff.GetSpellEffectInfo().ApplyAuraName) + continue; + break; + case AuraType.SchoolImmunity: + case AuraType.ModImmuneAuraApplySchool: + if (aurEff.GetSpellInfo().HasAttribute(SpellAttr2.UnaffectedByAuraSchoolImmune) || !Convert.ToBoolean((uint)aurEff.GetSpellInfo().SchoolMask & miscValue)) + continue; + break; + case AuraType.DispelImmunity: + if (miscValue != (uint)aurEff.GetSpellInfo().Dispel) + continue; + break; + case AuraType.MechanicImmunity: + if (miscValue != (uint)aurEff.GetSpellInfo().Mechanic) + { + if (miscValue != (uint)aurEff.GetSpellEffectInfo().Mechanic) + continue; + } + break; + default: + continue; + } + + return true; + } + + return false; + } + public float GetMinRange(bool positive = false) { if (RangeEntry == null) @@ -2594,8 +3069,8 @@ namespace Game.Spells var visual = CliDB.SpellXSpellVisualStorage.LookupByKey(GetSpellXSpellVisualId(caster)); if (visual != null) { - //if (visual->LowViolenceSpellVisualID && forPlayer->GetViolenceLevel() operator 2) - // return visual->LowViolenceSpellVisualID; + //if (visual.LowViolenceSpellVisualID && forPlayer.GetViolenceLevel() operator 2) + // return visual.LowViolenceSpellVisualID; return visual.SpellVisualID; } @@ -3066,7 +3541,7 @@ namespace Game.Spells public bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) { return (AuraInterruptFlags[1] & (uint)flag) != 0; } public bool HasChannelInterruptFlag(SpellChannelInterruptFlags flag) { return (ChannelInterruptFlags[0] & (uint)flag) != 0; } - + #region Fields public uint Id; @@ -3213,6 +3688,8 @@ namespace Game.Spells Scaling.Coefficient = spellEffectScaling != null ? spellEffectScaling.Coefficient : 0.0f; Scaling.Variance = spellEffectScaling != null ? spellEffectScaling.Variance : 0.0f; Scaling.ResourceCoefficient = spellEffectScaling != null ? spellEffectScaling.ResourceCoefficient : 0.0f; + + _immunityInfo = new ImmunityInfo(); } public bool IsEffect() @@ -3551,6 +4028,8 @@ namespace Game.Spells return _data[(int)Effect].UsedTargetObjectType; } + public ImmunityInfo GetImmunityInfo() { return _immunityInfo; } + public class StaticData { public StaticData(SpellEffectImplicitTargetTypes implicittarget, SpellTargetObjectTypes usedtarget) @@ -3853,6 +4332,8 @@ namespace Game.Spells public float BonusCoefficientFromAP; public List ImplicitTargetConditions; public ScalingInfo Scaling; + + ImmunityInfo _immunityInfo; #endregion public struct ScalingInfo @@ -4208,5 +4689,17 @@ namespace Game.Spells public DiminishingLevels DiminishMaxLevel = DiminishingLevels.Immune; public int DiminishDurationLimit; } + + public class ImmunityInfo + { + public uint SchoolImmuneMask; + public uint ApplyHarmfulAuraImmuneMask; + public uint MechanicImmuneMask; + public uint DispelImmune; + public uint DamageSchoolMask; + + public List AuraTypeImmune = new List(); + public List SpellEffectImmune = new List(); + } } diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index f14a77bdd..da59ac65a 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2815,6 +2815,21 @@ namespace Game.Entities Log.outInfo(LogFilter.ServerLoading, "Loaded SpellInfo diminishing infos in {0} ms", Time.GetMSTimeDiffToNow(oldMSTime)); } + public void LoadSpellInfoImmunities() + { + uint oldMSTime = Time.GetMSTime(); + + foreach (SpellInfo spellInfo in mSpellInfoMap.Values) + { + if (spellInfo == null) + continue; + + spellInfo._LoadImmunityInfo(); + } + + Log.outInfo(LogFilter.ServerLoading, "Loaded SpellInfo immunity infos in {0} ms", Time.GetMSTimeDiffToNow(oldMSTime)); + } + public void LoadPetFamilySpellsStore() { Dictionary levelsBySpell = new Dictionary(); diff --git a/Source/Scripts/Northrend/Dalaran.cs b/Source/Scripts/Northrend/Dalaran.cs index 64bdd4b12..06d9b3918 100644 --- a/Source/Scripts/Northrend/Dalaran.cs +++ b/Source/Scripts/Northrend/Dalaran.cs @@ -60,7 +60,7 @@ namespace Scripts.Northrend public npc_mageguard_dalaran(Creature creature) : base(creature) { creature.SetFlag(UnitFields.Flags, UnitFlags.NonAttackable); - creature.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchools.Normal, true); + creature.ApplySpellImmune(0, SpellImmunity.Damage, (uint)SpellSchools.Normal, true); creature.ApplySpellImmune(0, SpellImmunity.Damage, SpellSchoolMask.Magic, true); }