diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 0748d338f..21a16f357 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -141,6 +141,11 @@ namespace Framework.Constants NotVictim = (Hitbyspell | TakeDamage | DirectDamage) } + public enum SpellAuraInterruptFlags2 + { + + } + // Enum with EffectRadiusIndex and their actual radius public enum EffectRadiusIndex { diff --git a/Source/Game/AI/CoreAI/UnitAI.cs b/Source/Game/AI/CoreAI/UnitAI.cs index d120ccc10..d923a512d 100644 --- a/Source/Game/AI/CoreAI/UnitAI.cs +++ b/Source/Game/AI/CoreAI/UnitAI.cs @@ -249,7 +249,7 @@ namespace Game.AI float range = spellInfo.GetMaxRange(false); DefaultTargetSelector targetSelector = new DefaultTargetSelector(me, range, playerOnly, -(int)spellId); - if (!spellInfo.AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.NotVictim) + if (!spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotVictim) && targetSelector.Check(me.GetVictim())) target = me.GetVictim(); else diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index 38d66b3ff..cb79beea4 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -381,7 +381,7 @@ namespace Game.Combat Contract.Assert(target); // if the ref has status online the target must be there ! // some units are prefered in comparison to others - if (!noPriorityTargetFound && (target.IsImmunedToDamage(attacker.GetMeleeDamageSchoolMask()) || target.HasNegativeAuraWithInterruptFlag((uint)SpellAuraInterruptFlags.TakeDamage))) + if (!noPriorityTargetFound && (target.IsImmunedToDamage(attacker.GetMeleeDamageSchoolMask()) || target.HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags.TakeDamage))) { if (i != threatList.Count - 1) { diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index fbc93bd0e..d41db87ea 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -1083,12 +1083,8 @@ namespace Game.Entities } Spell spell1 = victim.GetCurrentSpell(CurrentSpellTypes.Channeled); if (spell1 != null) - if (spell1.getState() == SpellState.Casting) - { - var channelInterruptFlags = spell1.m_spellInfo.ChannelInterruptFlags; - if (((channelInterruptFlags & SpellChannelInterruptFlags.Delay) != 0) && (damagetype != DamageEffectType.DOT)) - spell1.DelayedChannel(); - } + if (spell1.getState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellChannelInterruptFlags.Delay) && damagetype != DamageEffectType.DOT) + spell1.DelayedChannel(); } } // last damage from duel opponent diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index 65c9beaea..0a8ce7268 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -86,7 +86,7 @@ namespace Game.Entities protected Dictionary m_currentSpells = new Dictionary((int)CurrentSpellTypes.Max); Dictionary CustomSpellValueMod = new Dictionary(); MultiMap m_spellImmune = new MultiMap(); - uint m_interruptMask; + uint[] m_interruptMask = new uint[2]; protected int m_procDeep; bool m_AutoRepeatFirstCast; SpellHistory _spellHistory; diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 986e46a94..be4d8f55b 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1444,7 +1444,7 @@ namespace Game.Entities var auras = GetAuraEffectsByType(type); foreach (var eff in auras) if ((excludeAura == 0 || excludeAura != eff.GetSpellInfo().Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction - eff.GetSpellInfo().AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.TakeDamage)) + eff.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.TakeDamage)) return true; return false; } @@ -2891,14 +2891,22 @@ namespace Game.Entities } public void UpdateInterruptMask() { - m_interruptMask = 0; - foreach (var app in m_interruptableAuras) - m_interruptMask |= (uint)app.GetBase().GetSpellInfo().AuraInterruptFlags; + m_interruptMask.Initialize(); + foreach (AuraApplication aurApp in m_interruptableAuras) + { + for (var i = 0; i < m_interruptMask.Length; ++i) + m_interruptMask[i] |= aurApp.GetBase().GetSpellInfo().AuraInterruptFlags[i]; + } Spell spell = GetCurrentSpell(CurrentSpellTypes.Channeled); if (spell != null) + { if (spell.getState() == SpellState.Casting) - m_interruptMask |= (uint)spell.m_spellInfo.ChannelInterruptFlags; + { + for (var i = 0; i < m_interruptMask.Length; ++i) + m_interruptMask[i] |= spell.m_spellInfo.ChannelInterruptFlags[i]; + } + } } // Auras @@ -3178,13 +3186,24 @@ namespace Game.Entities return false; } - public bool HasNegativeAuraWithInterruptFlag(uint flag, ObjectGuid guid = default(ObjectGuid)) + public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default(ObjectGuid)) { - if (!Convert.ToBoolean(m_interruptMask & flag)) + return HasNegativeAuraWithInterruptFlag((uint)flag, 0, guid); + } + + public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags2 flag, ObjectGuid guid = default(ObjectGuid)) + { + return HasNegativeAuraWithInterruptFlag((uint)flag, 1, guid); + } + + public bool HasNegativeAuraWithInterruptFlag(uint flag, int index, ObjectGuid guid = default(ObjectGuid)) + { + if (!Convert.ToBoolean(m_interruptMask[index] & flag)) return false; + foreach (var aura in m_interruptableAuras) { - if (!aura.IsPositive() && Convert.ToBoolean((uint)aura.GetBase().GetSpellInfo().AuraInterruptFlags & flag) + if (!aura.IsPositive() && Convert.ToBoolean(aura.GetBase().GetSpellInfo().AuraInterruptFlags[index] & flag) && (guid.IsEmpty() || aura.GetBase().GetCasterGUID() == guid)) return true; } @@ -3271,7 +3290,17 @@ namespace Game.Entities public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) { - if (!Convert.ToBoolean(m_interruptMask & (uint)flag)) + RemoveAurasWithInterruptFlags((uint)flag, 0, except); + } + + public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint except = 0) + { + RemoveAurasWithInterruptFlags((uint)flag, 1, except); + } + + void RemoveAurasWithInterruptFlags(uint flag, int index, uint except = 0) + { + if (!Convert.ToBoolean(m_interruptMask[index] & flag)) return; // interrupt auras @@ -3279,8 +3308,8 @@ namespace Game.Entities { Aura aura = m_interruptableAuras[i].GetBase(); - if (Convert.ToBoolean(aura.GetSpellInfo().AuraInterruptFlags & flag) && (except == 0 || aura.GetId() != except) - && !(Convert.ToBoolean(flag & SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, aura.GetSpellInfo()))) + if (Convert.ToBoolean(aura.GetSpellInfo().AuraInterruptFlags[index] & flag) && (except == 0 || aura.GetId() != except) + && !(Convert.ToBoolean(flag & (uint)SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, aura.GetSpellInfo()))) { uint removedAuras = m_removedAurasCount; RemoveAura(aura); @@ -3292,14 +3321,17 @@ namespace Game.Entities // interrupt channeled spell Spell spell = GetCurrentSpell(CurrentSpellTypes.Channeled); if (spell != null) + { if (spell.getState() == SpellState.Casting - && Convert.ToBoolean((uint)spell.m_spellInfo.ChannelInterruptFlags & (uint)flag) - && spell.m_spellInfo.Id != except - && !(Convert.ToBoolean(flag & SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spell.GetSpellInfo()))) + && Convert.ToBoolean(spell.GetSpellInfo().ChannelInterruptFlags[index] & flag) + && spell.GetSpellInfo().Id != except + && !(Convert.ToBoolean(flag & (uint)SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spell.GetSpellInfo()))) InterruptNonMeleeSpells(false); + } UpdateInterruptMask(); } + public void RemoveAurasWithMechanic(uint mechanic_mask, AuraRemoveMode removemode = AuraRemoveMode.Default, uint except = 0) { foreach (var app in GetAppliedAuras()) @@ -3931,7 +3963,7 @@ namespace Game.Entities m_appliedAuras.Remove(pair); - if (aura.GetSpellInfo().AuraInterruptFlags != 0) + if (aura.GetSpellInfo().HasAnyAuraInterruptFlag()) { m_interruptableAuras.Remove(aurApp); UpdateInterruptMask(); @@ -4119,7 +4151,7 @@ namespace Game.Entities return; // Sitdown on apply aura req seated - if (aura.GetSpellInfo().AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.NotSeated) && !IsSitState()) + if (aura.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated) && !IsSitState()) SetStandState(UnitStandStateType.Sit); Unit caster = aura.GetCaster(); diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 551be89ac..e03d2a529 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1875,10 +1875,10 @@ namespace Game.Entities AuraApplication aurApp = new AuraApplication(this, caster, aura, effMask); m_appliedAuras.Add(aurId, aurApp); - if (aurSpellInfo.AuraInterruptFlags != 0) + if (aurSpellInfo.HasAnyAuraInterruptFlag()) { m_interruptableAuras.Add(aurApp); - AddInterruptMask((uint)aurSpellInfo.AuraInterruptFlags); + AddInterruptMask(aurSpellInfo.AuraInterruptFlags); } AuraStateType aState = aura.GetSpellInfo().GetAuraState(); @@ -1888,7 +1888,11 @@ namespace Game.Entities aura._ApplyForTarget(this, caster, aurApp); return aurApp; } - public void AddInterruptMask(uint mask) { m_interruptMask |= mask; } + public void AddInterruptMask(uint[] mask) + { + for (int i = 0; i < m_interruptMask.Length; ++i) + m_interruptMask[i] |= mask[i]; + } void _UpdateAutoRepeatSpell() { diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 83759ff5b..f8945e45c 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -3058,7 +3058,7 @@ namespace Game.Spells // when removing flag aura, handle flag drop Player player = target.ToPlayer(); - if (!apply && player != null && (GetSpellInfo().AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.ImmuneOrLostSelection))) + if (!apply && player != null && GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.ImmuneOrLostSelection)) { if (player.InBattleground()) { diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index dc6bf53de..103528464 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2987,13 +2987,13 @@ namespace Game.Spells m_caster.ModSpellDurationTime(m_spellInfo, ref duration, this); m_spellState = SpellState.Casting; - m_caster.AddInterruptMask((uint)m_spellInfo.ChannelInterruptFlags); + m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags); SendChannelStart((uint)duration); } else if (duration == -1) { m_spellState = SpellState.Casting; - m_caster.AddInterruptMask((uint)m_spellInfo.ChannelInterruptFlags); + m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags); SendChannelStart((uint)duration); } } @@ -4484,7 +4484,7 @@ namespace Game.Spells // skip stuck spell to allow use it in falling case and apply spell limitations at movement SpellEffectInfo effect = GetEffect(0); if ((!m_caster.HasUnitMovementFlag(MovementFlag.FallingFar) || (effect != null && effect.Effect != SpellEffectName.Stuck)) && - (IsAutoRepeat() || (m_spellInfo.AuraInterruptFlags & SpellAuraInterruptFlags.NotSeated) != 0)) + (IsAutoRepeat() || m_spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated))) return SpellCastResult.Moving; } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 5f8950d1f..303b7b6cd 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -2849,7 +2849,7 @@ namespace Game.Spells || (spell.getState() == SpellState.Preparing && spell.GetCastTime() > 0.0f)) && (curSpellInfo.PreventionType.HasAnyFlag(SpellPreventionType.Silence)) && ((i == CurrentSpellTypes.Generic && curSpellInfo.InterruptFlags.HasAnyFlag(SpellInterruptFlags.Interrupt)) - || (i == CurrentSpellTypes.Channeled && curSpellInfo.ChannelInterruptFlags.HasAnyFlag(SpellChannelInterruptFlags.Interrupt)))) + || (i == CurrentSpellTypes.Channeled && curSpellInfo.HasChannelInterruptFlag(SpellChannelInterruptFlags.Interrupt)))) { if (m_originalCaster != null) { diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 83c832be9..fdae285f9 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -191,8 +191,8 @@ namespace Game.Spells { InterruptFlags = (SpellInterruptFlags)_interrupt.InterruptFlags; // TODO: 6.x these flags have 2 parts - AuraInterruptFlags = (SpellAuraInterruptFlags)_interrupt.AuraInterruptFlags[0]; - ChannelInterruptFlags = (SpellChannelInterruptFlags)_interrupt.ChannelInterruptFlags[0]; + AuraInterruptFlags = _interrupt.AuraInterruptFlags; + ChannelInterruptFlags = _interrupt.ChannelInterruptFlags; } // SpellLevelsEntry @@ -1367,7 +1367,7 @@ namespace Game.Spells case SpellFamilyNames.Generic: { // Food / Drinks (mostly) - if (AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.NotSeated)) + if (HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated)) { bool food = false; bool drink = false; @@ -3051,6 +3051,13 @@ namespace Game.Spells public bool HasAttribute(SpellAttr13 attribute) { return Convert.ToBoolean(AttributesEx13 & attribute); } public bool HasAttribute(SpellCustomAttributes attribute) { return Convert.ToBoolean(AttributesCu & attribute); } + public bool HasAnyAuraInterruptFlag() { return AuraInterruptFlags.Any(flag => { return flag != 0; }); } + public bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) { return (AuraInterruptFlags[0] & (uint)flag) != 0; } + 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; uint CategoryId; @@ -3091,8 +3098,8 @@ namespace Game.Spells public uint StartRecoveryCategory { get; set; } public uint StartRecoveryTime { get; set; } public SpellInterruptFlags InterruptFlags { get; set; } - public SpellAuraInterruptFlags AuraInterruptFlags { get; set; } - public SpellChannelInterruptFlags ChannelInterruptFlags { get; set; } + public uint[] AuraInterruptFlags { get; set; } = new uint[2]; + public uint[] ChannelInterruptFlags { get; set; } = new uint[2]; public ProcFlags ProcFlags { get; set; } public uint ProcChance { get; set; } public uint ProcCharges { get; set; } diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index dd1515ec0..e1d12aa74 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2389,7 +2389,7 @@ namespace Game.Entities spellInfo.GetEffect(0).BasePoints = 0;// force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)" break; case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with - spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags.Hitbyspell | SpellAuraInterruptFlags.TakeDamage; + spellInfo.AuraInterruptFlags[0] = (uint)(SpellAuraInterruptFlags.Hitbyspell | SpellAuraInterruptFlags.TakeDamage); break; case 71838: // Drain Life - Bryntroll Normal case 71839: // Drain Life - Bryntroll Heroic @@ -2488,7 +2488,7 @@ namespace Game.Entities break; case 63414: // Spinning Up (Mimiron) spellInfo.GetEffect(0).TargetB = new SpellImplicitTargetInfo(Targets.UnitCaster); - spellInfo.ChannelInterruptFlags = 0; + spellInfo.ChannelInterruptFlags.Initialize(); break; case 63036: // Rocket Strike (Mimiron) spellInfo.Speed = 0; @@ -2698,7 +2698,7 @@ namespace Game.Entities spellInfo.GetEffect(0).MaxRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(EffectRadiusIndex.Yards45); break; case 24314: // Threatening Gaze - spellInfo.AuraInterruptFlags |= SpellAuraInterruptFlags.Cast | SpellAuraInterruptFlags.Move | SpellAuraInterruptFlags.Jump; + spellInfo.AuraInterruptFlags[0] |= (uint)(SpellAuraInterruptFlags.Cast | SpellAuraInterruptFlags.Move | SpellAuraInterruptFlags.Jump); break; case 5420: // Tree of Life (Passive) spellInfo.Stances = 1 << ((int)ShapeShiftForm.TreeOfLife - 1); @@ -2722,12 +2722,53 @@ namespace Game.Entities break; // ENDOF ISLE OF CONQUEST SPELLS // + // FIRELANDS SPELLS + // Torment Searcher + case 99253: + spellInfo.GetEffect(0).MaxRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(EffectRadiusIndex.Yards15); + break; + // Torment Damage + case 99256: + spellInfo.Attributes |= SpellAttr0.Negative1; + break; + // Blaze of Glory + case 99252: + spellInfo.AuraInterruptFlags[0] |= (uint)SpellAuraInterruptFlags.ChangeMap; + break; + // ENDOF FIRELANDS SPELLS case 102445: // Summon Master Li Fei spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.DestDb); break; } } + foreach (var spellInfo in mSpellInfoMap.Values) + { + foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None)) + { + if (effect == null) + continue; + switch (effect.Effect) + { + case SpellEffectName.Charge: + case SpellEffectName.ChargeDest: + case SpellEffectName.Jump: + case SpellEffectName.JumpDest: + case SpellEffectName.LeapBack: + if (spellInfo.Speed == 0 && spellInfo.SpellFamilyName == 0) + spellInfo.Speed = MotionMaster.SPEED_CHARGE; + break; + } + + if (effect.TargetA.GetSelectionCategory() == SpellTargetSelectionCategories.Cone || effect.TargetB.GetSelectionCategory() == SpellTargetSelectionCategories.Cone) + if (MathFunctions.fuzzyEq(spellInfo.ConeAngle, 0.0f)) + spellInfo.ConeAngle = 90.0f; + } + + if (spellInfo.ActiveIconFileDataId == 135754) // flight + spellInfo.Attributes |= SpellAttr0.Passive; + } + SummonPropertiesRecord properties = CliDB.SummonPropertiesStorage.LookupByKey(121); if (properties != null) properties.Type = SummonType.Totem;