From 0501481fcddfbb4b9a4d19812a3c3eec7794b8b5 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 28 Mar 2021 15:49:12 -0400 Subject: [PATCH] Core/Auras: Defined and implemented many new interrupt flags Port From (https://github.com/TrinityCore/TrinityCore/commit/9b5a46ca2bb3a4632cb9914e0899df611a47d935) --- Source/Framework/Constants/CliDBConst.cs | 2 - .../Framework/Constants/Spells/SpellConst.cs | 91 +++++++++------ .../Game/BattleGrounds/Zones/ArathiBasin.cs | 2 +- Source/Game/BattleGrounds/Zones/EyeofStorm.cs | 4 +- .../Game/BattleGrounds/Zones/WarsongGluch.cs | 4 +- Source/Game/Combat/ThreatManager.cs | 2 +- Source/Game/Entities/Player/Player.cs | 5 +- Source/Game/Entities/Unit/Unit.Combat.cs | 21 ++-- Source/Game/Entities/Unit/Unit.Fields.cs | 3 +- Source/Game/Entities/Unit/Unit.Movement.cs | 8 +- Source/Game/Entities/Unit/Unit.Spells.cs | 106 ++++++++++++------ Source/Game/Entities/Unit/Unit.cs | 30 ++++- Source/Game/Handlers/CharacterHandler.cs | 3 + Source/Game/Handlers/ChatHandler.cs | 11 +- Source/Game/Handlers/LootHandler.cs | 2 + Source/Game/Handlers/MovementHandler.cs | 6 +- Source/Game/Handlers/NPCHandler.cs | 2 +- Source/Game/Handlers/SpellHandler.cs | 2 + Source/Game/Spells/Auras/AuraEffect.cs | 43 +++---- Source/Game/Spells/Spell.cs | 23 ++-- Source/Game/Spells/SpellEffects.cs | 2 +- Source/Game/Spells/SpellInfo.cs | 35 ++++-- Source/Game/Spells/SpellManager.cs | 19 ++-- 23 files changed, 257 insertions(+), 169 deletions(-) diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index a857cb335..73e8ee0db 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -1604,8 +1604,6 @@ namespace Framework.Constants public enum MountFlags : ushort { - CanPitch = 0x4, // client checks MOVEMENTFLAG2_FULL_SPEED_PITCHING - CanSwim = 0x8, // client checks MOVEMENTFLAG_SWIMMING SelfMount = 0x02, // Player becomes the mount himself FactionSpecific = 0x04, PreferredSwimming = 0x10, diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index 1d3622013..e5cab5286 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -107,48 +107,71 @@ namespace Framework.Constants AbortOnDmg = 0x10 // _complete_ interrupt on direct damage //SPELL_INTERRUPT_UNK = 0x20 // unk, 564 of 727 spells having this spell start with "Glyph" } - public enum SpellChannelInterruptFlags - { - Interrupt = 0x08, // interrupt - Delay = 0x4000 - } public enum SpellAuraInterruptFlags : uint { - Hitbyspell = 0x01, // 0 Removed When Getting Hit By A Negative Spell? - TakeDamage = 0x02, // 1 Removed By Any Damage - Cast = 0x04, // 2 Cast Any Spells - Move = 0x08, // 3 Removed By Any Movement - Turning = 0x10, // 4 Removed By Any Turning - Jump = 0x20, // 5 Removed By Jumping - NotMounted = 0x40, // 6 Removed By Dismounting - NotAbovewater = 0x80, // 7 Removed By Entering Water - NotUnderwater = 0x100, // 8 Removed By Leaving Water - NotSheathed = 0x200, // 9 Removed By Unsheathing - Talk = 0x400, // 10 Talk To Npc / Loot? Action On Creature - Use = 0x800, // 11 Mine/Use/Open Action On Gameobject - MeleeAttack = 0x1000, // 12 Removed By Attacking - SpellAttack = 0x2000, // 13 ??? - Unk14 = 0x4000, // 14 - Transform = 0x8000, // 15 Removed By Transform? - Unk16 = 0x10000, // 16 - Mount = 0x20000, // 17 Misdirect, Aspect, Swim Speed - NotSeated = 0x40000, // 18 Removed By Standing Up (Used By Food And Drink Mostly And Sleep/Fake Death Like) - ChangeMap = 0x80000, // 19 Leaving Map/Getting Teleported - ImmuneOrLostSelection = 0x100000, // 20 Removed By Auras That Make You Invulnerable, Or Make Other To Lose Selection On You - Unk21 = 0x200000, // 21 - Teleported = 0x400000, // 22 - EnterPvpCombat = 0x800000, // 23 Removed By Entering Pvp Combat - DirectDamage = 0x1000000, // 24 Removed By Any Direct Damage - Landing = 0x2000000, // 25 Removed By Hitting The Ground - LeaveCombat = 0x80000000, // 31 removed by leaving combat + None = 0, + HostileActionReceived = 0x01, + Damage = 0x02, + Action = 0x04, + Moving = 0x08, + Turning = 0x10, + Anim = 0x20, + Dismount = 0x40, + UnderWater = 0x80, // TODO: disallow casting when swimming (SPELL_FAILED_ONLY_ABOVEWATER) + AboveWater = 0x100, // TODO: disallow casting when not swimming (SPELL_FAILED_ONLY_UNDERWATER) + Sheathing = 0x200, + Interacting = 0x400, // TODO: more than gossip, replace all the feign death removals by aura type + Looting = 0x800, + Attacking = 0x1000, + ItemUse = 0x2000, + DamageChannelDuration = 0x4000, + Shapeshifting = 0x8000, + ActionDelayed = 0x10000, + Mount = 0x20000, + Standing = 0x40000, + LeaveWorld = 0x80000, + StealthOrInvis = 0x100000, + InvulnerabilityBuff = 0x200000, + EnterWorld = 0x400000, + PvPActive = 0x800000, + NonPeriodicDamage = 0x1000000, + LandingOrFlight = 0x2000000, + Release = 0x4000000, + DamageCancelsScript = 0x8000000, // NYI dedicated aura script hook + EnteringCombat = 0x10000000, + Login = 0x20000000, + Summon = 0x40000000, + LeavingCombat = 0x80000000, - NotVictim = (Hitbyspell | TakeDamage | DirectDamage) + NotVictim = (HostileActionReceived | Damage | NonPeriodicDamage) } public enum SpellAuraInterruptFlags2 { - + None = 0, + Falling = 0x01, // NYI + Swimming = 0x02, // NYI + NotMoving = 0x04, // NYI + Ground = 0x08, // NYI + Transform = 0x10, // NYI + Jump = 0x20, + ChangeSpec = 0x40, // NYI + AbandonVehicle = 0x80, // NYI + StartOfEncounter = 0x100, // NYI + EndOfEncounter = 0x200, // NYI + Disconnect = 0x400, // NYI + EnteringInstance = 0x800, // NYI + DuelEnd = 0x1000, // NYI + LeaveArenaOrBattleground = 0x2000, // NYI + ChangeTalent = 0x4000, // NYI + ChangeGlyph = 0x8000, // NYI + SeamlessTransfer = 0x10000, // NYI + WarModeLeave = 0x20000, // NYI + TouchingGround = 0x40000, // NYI + ChromieTime = 0x80000, // NYI + SplineFlightOrFreeFlight = 0x100000, // NYI + ProcOrPeriodicAttacking = 0x200000 // NYI } // Enum with EffectRadiusIndex and their actual radius diff --git a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs index 721300135..e0804216a 100644 --- a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs +++ b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs @@ -427,7 +427,7 @@ namespace Game.BattleGrounds.Zones if (!(m_Nodes[node] == 0 || teamIndex == (int)m_Nodes[node] % 2)) return; - source.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + source.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); uint sound; // If node is neutral, change to contested if (m_Nodes[node] == ABNodeStatus.Neutral) diff --git a/Source/Game/BattleGrounds/Zones/EyeofStorm.cs b/Source/Game/BattleGrounds/Zones/EyeofStorm.cs index 0a78ca4a3..ad76c9ef5 100644 --- a/Source/Game/BattleGrounds/Zones/EyeofStorm.cs +++ b/Source/Game/BattleGrounds/Zones/EyeofStorm.cs @@ -672,7 +672,7 @@ namespace Game.BattleGrounds.Zones SetFlagPicker(player.GetGUID()); //get flag aura on player player.CastSpell(player, EotSMisc.SpellNetherstormFlag, true); - player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); if (player.GetTeam() == Team.Alliance) SendBroadcastText(EotSBroadcastTexts.TakenFlag, ChatMsg.BgSystemAlliance, player); @@ -803,7 +803,7 @@ namespace Game.BattleGrounds.Zones m_FlagState = EotSFlagState.WaitRespawn; player.RemoveAurasDueToSpell(EotSMisc.SpellNetherstormFlag); - player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); if (player.GetTeam() == Team.Alliance) { diff --git a/Source/Game/BattleGrounds/Zones/WarsongGluch.cs b/Source/Game/BattleGrounds/Zones/WarsongGluch.cs index c979333b2..67c75f96e 100644 --- a/Source/Game/BattleGrounds/Zones/WarsongGluch.cs +++ b/Source/Game/BattleGrounds/Zones/WarsongGluch.cs @@ -259,7 +259,7 @@ namespace Game.BattleGrounds.Zones Team winner = 0; - player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); if (player.GetTeam() == Team.Alliance) { if (!IsHordeFlagPickedup()) @@ -535,7 +535,7 @@ namespace Game.BattleGrounds.Zones //target_obj.Delete(); } - player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); } public override void RemovePlayer(Player player, ObjectGuid guid, Team team) diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index c047865a2..d0dbdddbe 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -473,7 +473,7 @@ namespace Game.Combat Cypher.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(SpellAuraInterruptFlags.TakeDamage))) + if (!noPriorityTargetFound && (target.IsImmunedToDamage(attacker.GetMeleeDamageSchoolMask()) || target.HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags.Damage))) { if (i != threatList.Count - 1) { diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index ce2adf3da..02cd2dbeb 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -1787,7 +1787,7 @@ namespace Game.Entities InterruptNonMeleeSpells(true); //remove auras before removing from map... - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ChangeMap | SpellAuraInterruptFlags.Move | SpellAuraInterruptFlags.Turning); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Moving | SpellAuraInterruptFlags.Turning); if (!GetSession().PlayerLogout() && !options.HasAnyFlag(TeleportToOptions.Seamless)) { @@ -2123,6 +2123,7 @@ namespace Game.Entities m_summon_expire = 0; UpdateCriteria(CriteriaTypes.AcceptedSummonings, 1); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Summon); m_summon_location.SetOrientation(GetOrientation()); TeleportTo(m_summon_location); @@ -4047,6 +4048,8 @@ namespace Game.Entities CastSpell(this, 20584, true); CastSpell(this, 8326, true); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Release); + // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK // there must be SMSG.STOP_MIRROR_TIMER diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index b785f752b..86e09759b 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -288,7 +288,7 @@ namespace Game.Entities else ToPlayer().OnCombatExit(); - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeaveCombat); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat); } public void ClearInPetCombat() @@ -630,7 +630,7 @@ namespace Game.Entities return; CombatStart(victim); - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.MeleeAttack); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Attacking); // ignore ranged case if (attType != WeaponAttackType.BaseAttack && attType != WeaponAttackType.OffAttack) @@ -712,7 +712,7 @@ namespace Game.Entities return; CombatStart(victim); - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.MeleeAttack); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Attacking); if (attType != WeaponAttackType.BaseAttack && attType != WeaponAttackType.OffAttack) return; // ignore ranged case @@ -993,14 +993,14 @@ namespace Game.Entities if (damagetype != DamageEffectType.NoDamage) { - // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras) + // interrupting auras with SpellAuraInterruptFlags.Damage before checking !damage (absorbed damage breaks that type of auras) if (spellProto != null) { if (!spellProto.HasAttribute(SpellAttr4.DamageDoesntBreakAuras)) - victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.TakeDamage, spellProto.Id); + victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, spellProto.Id); } else - victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.TakeDamage, 0); + victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Damage, 0); // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) if (damage == 0 && damagetype != DamageEffectType.DOT && cleanDamage != null && cleanDamage.absorbed_damage != 0) @@ -1140,7 +1140,7 @@ namespace Game.Entities victim.ModifyHealth(-(int)damage); if (damagetype == DamageEffectType.Direct || damagetype == DamageEffectType.SpellDirect) - victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.DirectDamage, spellProto != null ? spellProto.Id : 0); + victim.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NonPeriodicDamage, spellProto != null ? spellProto.Id : 0); if (!victim.IsTypeId(TypeId.Player)) { @@ -1179,6 +1179,7 @@ namespace Game.Entities { Spell spell = victim.GetCurrentSpell(CurrentSpellTypes.Generic); if (spell != null) + { if (spell.GetState() == SpellState.Preparing) { var interruptFlags = spell.m_spellInfo.InterruptFlags; @@ -1187,10 +1188,11 @@ namespace Game.Entities else if (interruptFlags.HasAnyFlag(SpellInterruptFlags.PushBack)) spell.Delayed(); } + } } Spell spell1 = victim.GetCurrentSpell(CurrentSpellTypes.Channeled); if (spell1 != null) - if (spell1.GetState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellChannelInterruptFlags.Delay) && damagetype != DamageEffectType.DOT) + if (spell1.GetState() == SpellState.Casting && spell1.m_spellInfo.HasChannelInterruptFlag(SpellAuraInterruptFlags.DamageChannelDuration) && damagetype != DamageEffectType.DOT) spell1.DelayedChannel(); } } @@ -1352,7 +1354,7 @@ namespace Game.Entities if (me != null && who.IsPvP() && (!who.IsTypeId(TypeId.Player) || me.duel == null || me.duel.opponent != who)) { me.UpdatePvP(true); - me.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterPvpCombat); + me.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive); } } public void SetInCombatWith(Unit enemy) @@ -1426,6 +1428,7 @@ namespace Game.Entities foreach (var unit in m_Controlled) unit.SetInCombatState(PvP, enemy); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat); ProcSkillsAndAuras(enemy, ProcFlags.EnterCombat, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index bb767b105..bf07e0b26 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -86,7 +86,8 @@ namespace Game.Entities protected Dictionary m_currentSpells = new((int)CurrentSpellTypes.Max); Dictionary CustomSpellValueMod = new(); MultiMap[] m_spellImmune = new MultiMap[(int)SpellImmunity.Max]; - uint[] m_interruptMask = new uint[2]; + SpellAuraInterruptFlags m_interruptMask; + SpellAuraInterruptFlags2 m_interruptMask2; protected int m_procDeep; bool m_AutoRepeatFirstCast; SpellHistory _spellHistory; diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index a8ac01360..a427ec676 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -582,7 +582,7 @@ namespace Game.Entities if (relocated) { - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Move); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Moving); // move and update visible state if need if (IsTypeId(TypeId.Player)) @@ -787,9 +787,9 @@ namespace Game.Entities { // remove appropriate auras if we are swimming/not swimming respectively if (inWater) - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotAbovewater); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.UnderWater); else - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotUnderwater); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.AboveWater); } public virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional liquidData) @@ -1348,7 +1348,7 @@ namespace Game.Entities RemoveVehicleKit(); } - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotMounted); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Dismount); // only resummon old pet if the player is already added to a map // this prevents adding a pet to a not created map which would otherwise cause a crash diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index b9efdffa5..d53dc279b 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1476,7 +1476,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().HasAuraInterruptFlag(SpellAuraInterruptFlags.TakeDamage)) + eff.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.Damage)) return true; return false; } @@ -2913,11 +2913,12 @@ namespace Game.Entities } public void UpdateInterruptMask() { - m_interruptMask.Clear(); + m_interruptMask = SpellAuraInterruptFlags.None; + m_interruptMask2 = SpellAuraInterruptFlags2.None; foreach (AuraApplication aurApp in m_interruptableAuras) { - for (var i = 0; i < m_interruptMask.Length; ++i) - m_interruptMask[i] |= aurApp.GetBase().GetSpellInfo().AuraInterruptFlags[i]; + m_interruptMask |= aurApp.GetBase().GetSpellInfo().AuraInterruptFlags; + m_interruptMask2 |= aurApp.GetBase().GetSpellInfo().AuraInterruptFlags2; } Spell spell = GetCurrentSpell(CurrentSpellTypes.Channeled); @@ -2925,8 +2926,8 @@ namespace Game.Entities { if (spell.GetState() == SpellState.Casting) { - for (var i = 0; i < m_interruptMask.Length; ++i) - m_interruptMask[i] |= spell.m_spellInfo.ChannelInterruptFlags[i]; + m_interruptMask |= spell.m_spellInfo.ChannelInterruptFlags; + m_interruptMask2 |= spell.m_spellInfo.ChannelInterruptFlags2; } } } @@ -3161,27 +3162,32 @@ namespace Game.Entities public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag, ObjectGuid guid = default) { - return HasNegativeAuraWithInterruptFlag((uint)flag, 0, guid); - } - - public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags2 flag, ObjectGuid guid = default) - { - return HasNegativeAuraWithInterruptFlag((uint)flag, 1, guid); - } - - public bool HasNegativeAuraWithInterruptFlag(uint flag, int index, ObjectGuid guid = default) - { - if (!Convert.ToBoolean(m_interruptMask[index] & flag)) + if (!HasInterruptFlag(flag)) return false; foreach (var aura in m_interruptableAuras) { - if (!aura.IsPositive() && Convert.ToBoolean(aura.GetBase().GetSpellInfo().AuraInterruptFlags[index] & flag) + if (!aura.IsPositive() && aura.GetBase().GetSpellInfo().HasAuraInterruptFlag(flag) && (guid.IsEmpty() || aura.GetBase().GetCasterGUID() == guid)) return true; } return false; } + + public bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags2 flag, ObjectGuid guid = default) + { + if (!HasInterruptFlag(flag)) + return false; + + foreach (var aura in m_interruptableAuras) + { + if (!aura.IsPositive() && aura.GetBase().GetSpellInfo().HasAuraInterruptFlag(flag) + && (guid.IsEmpty() || aura.GetBase().GetCasterGUID() == guid)) + return true; + } + return false; + } + bool HasNegativeAuraWithAttribute(SpellAttr0 flag, ObjectGuid guid = default) { foreach (var list in GetAppliedAuras()) @@ -3267,19 +3273,18 @@ namespace Game.Entities return dispelList; } + bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo spellInfo) + { + return false; + } + bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo spellInfo) + { + return flag == SpellAuraInterruptFlags.Moving && unit.HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spellInfo); + } + public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) { - 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)) + if (!HasInterruptFlag(flag)) return; // interrupt auras @@ -3287,8 +3292,7 @@ namespace Game.Entities { Aura aura = m_interruptableAuras[i].GetBase(); - if (Convert.ToBoolean(aura.GetSpellInfo().AuraInterruptFlags[index] & flag) && (except == 0 || aura.GetId() != except) - && !(Convert.ToBoolean(flag & (uint)SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, aura.GetSpellInfo()))) + if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) { uint removedAuras = m_removedAurasCount; RemoveAura(aura, AuraRemoveMode.Interrupt); @@ -3302,9 +3306,43 @@ namespace Game.Entities if (spell != null) { if (spell.GetState() == SpellState.Casting - && Convert.ToBoolean(spell.GetSpellInfo().ChannelInterruptFlags[index] & flag) + && spell.GetSpellInfo().HasChannelInterruptFlag(flag) && spell.GetSpellInfo().Id != except - && !(Convert.ToBoolean(flag & (uint)SpellAuraInterruptFlags.Move) && HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spell.GetSpellInfo()))) + && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) + InterruptNonMeleeSpells(false); + } + + UpdateInterruptMask(); + + } + + public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint except = 0) + { + if (!HasInterruptFlag(flag)) + return; + + // interrupt auras + for (var i = 0; i < m_interruptableAuras.Count; i++) + { + Aura aura = m_interruptableAuras[i].GetBase(); + + if (aura.GetSpellInfo().HasAuraInterruptFlag(flag) && (except == 0 || aura.GetId() != except) && !IsInterruptFlagIgnoredForSpell(flag, this, aura.GetSpellInfo())) + { + uint removedAuras = m_removedAurasCount; + RemoveAura(aura, AuraRemoveMode.Interrupt); + if (m_removedAurasCount > removedAuras + 1) + i = 0; + } + } + + // interrupt channeled spell + Spell spell = GetCurrentSpell(CurrentSpellTypes.Channeled); + if (spell != null) + { + if (spell.GetState() == SpellState.Casting + && spell.GetSpellInfo().HasChannelInterruptFlag(flag) + && spell.GetSpellInfo().Id != except + && !IsInterruptFlagIgnoredForSpell(flag, this, spell.GetSpellInfo())) InterruptNonMeleeSpells(false); } @@ -4173,7 +4211,7 @@ namespace Game.Entities return; // Sitdown on apply aura req seated - if (aura.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated) && !IsSitState()) + if (aura.GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing) && !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 1833e202d..87d61aad3 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -434,6 +434,13 @@ namespace Game.Entities } } + public override void AddToWorld() + { + base.AddToWorld(); + + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnterWorld); + } + public override void RemoveFromWorld() { // cleanup @@ -447,6 +454,7 @@ namespace Game.Entities RemoveCharmAuras(); RemoveAurasByType(AuraType.BindSight); RemoveNotOwnSingleTargetAuras(); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeaveWorld); RemoveAllGameObjects(); RemoveAllDynObjects(); @@ -1552,7 +1560,7 @@ namespace Game.Entities if (aurSpellInfo.HasAnyAuraInterruptFlag()) { m_interruptableAuras.Add(aurApp); - AddInterruptMask(aurSpellInfo.AuraInterruptFlags); + AddInterruptMask(aurSpellInfo.AuraInterruptFlags, aurSpellInfo.AuraInterruptFlags2); } AuraStateType aState = aura.GetSpellInfo().GetAuraState(); @@ -1562,10 +1570,14 @@ namespace Game.Entities aura._ApplyForTarget(this, caster, aurApp); return aurApp; } - public void AddInterruptMask(uint[] mask) + + bool HasInterruptFlag(SpellAuraInterruptFlags flags) { return m_interruptMask.HasFlag(flags); } + bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) { return m_interruptMask2.HasFlag(flags); } + + public void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2) { - for (int i = 0; i < m_interruptMask.Length; ++i) - m_interruptMask[i] |= mask[i]; + m_interruptMask |= flags; + m_interruptMask2 |= flags2; } void _UpdateAutoRepeatSpell() @@ -1673,6 +1685,13 @@ namespace Game.Entities SetPowerType(displayPower); } + public void SetSheath(SheathState sheathed) + { + SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.SheatheState), (byte)sheathed); + if (sheathed == SheathState.Unarmed) + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Sheathing); + } + public FactionTemplateRecord GetFactionTemplateEntry() { FactionTemplateRecord entry = CliDB.FactionTemplateStorage.LookupByKey(GetFaction()); @@ -2030,7 +2049,6 @@ namespace Game.Entities public void SetEmoteState(Emote emote) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.EmoteState), (int)emote); } public SheathState GetSheath() { return (SheathState)(byte)m_unitData.SheatheState; } - public void SetSheath(SheathState sheathed) { SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.SheatheState), (byte)sheathed); } public uint GetCombatTimer() { return combatTimer; } public UnitPVPStateFlags GetPvpFlags() { return (UnitPVPStateFlags)(byte)m_unitData.PvpFlags; } @@ -2364,7 +2382,7 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StandState), (byte)state); if (IsStandState()) - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotSeated); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Standing); if (IsTypeId(TypeId.Player)) { diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 33d300226..5eccc4bb7 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -825,6 +825,9 @@ namespace Game pCurrChar.SetInGuild(0); } } + + pCurrChar.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Login); + pCurrChar.SendInitialPacketsAfterAddToMap(); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_ONLINE); diff --git a/Source/Game/Handlers/ChatHandler.cs b/Source/Game/Handlers/ChatHandler.cs index 54552928a..c1afea4dd 100644 --- a/Source/Game/Handlers/ChatHandler.cs +++ b/Source/Game/Handlers/ChatHandler.cs @@ -571,9 +571,9 @@ namespace Game if (em == null) return; - uint emote_anim = em.EmoteId; + Emote emoteAnim = (Emote)em.EmoteId; - switch ((Emote)emote_anim) + switch (emoteAnim) { case Emote.StateSleep: case Emote.StateSit: @@ -582,13 +582,13 @@ namespace Game break; case Emote.StateDance: case Emote.StateRead: - GetPlayer().SetEmoteState((Emote)emote_anim); + GetPlayer().SetEmoteState(emoteAnim); break; default: // Only allow text-emotes for "dead" entities (feign death included) if (GetPlayer().HasUnitState(UnitState.Died)) break; - GetPlayer().HandleEmoteCommand((Emote)emote_anim); + GetPlayer().HandleEmoteCommand(emoteAnim); break; } @@ -611,6 +611,9 @@ namespace Game if (creature) creature.GetAI().ReceiveEmote(GetPlayer(), (TextEmotes)packet.EmoteID); } + + if (emoteAnim != Emote.OneshotNone) + _player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Anim); } [WorldPacketHandler(ClientOpcodes.ChatReportIgnored)] diff --git a/Source/Game/Handlers/LootHandler.cs b/Source/Game/Handlers/LootHandler.cs index ede0867f4..287935d94 100644 --- a/Source/Game/Handlers/LootHandler.cs +++ b/Source/Game/Handlers/LootHandler.cs @@ -297,6 +297,8 @@ namespace Game // interrupt cast if (GetPlayer().IsNonMeleeSpellCast(false)) GetPlayer().InterruptNonMeleeSpells(false); + + GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Looting); } [WorldPacketHandler(ClientOpcodes.LootRelease)] diff --git a/Source/Game/Handlers/MovementHandler.cs b/Source/Game/Handlers/MovementHandler.cs index 4be9ce398..e87db7853 100644 --- a/Source/Game/Handlers/MovementHandler.cs +++ b/Source/Game/Handlers/MovementHandler.cs @@ -137,8 +137,8 @@ namespace Game plrMover.HandleFall(movementInfo); // interrupt parachutes upon falling or landing in water - if (opcode == ClientOpcodes.MoveFallLand || opcode == ClientOpcodes.MoveStartSwim) - mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Landing); // Parachutes + if (opcode == ClientOpcodes.MoveFallLand || opcode == ClientOpcodes.MoveStartSwim || opcode == ClientOpcodes.MoveSetFly) + mover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LandingOrFlight); // Parachutes uint mstime = GameTime.GetGameTimeMS(); @@ -206,7 +206,7 @@ namespace Game if (opcode == ClientOpcodes.MoveJump) { - plrMover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Jump, 605); // Mind Control + plrMover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2.Jump); // Mind Control plrMover.ProcSkillsAndAuras(null, ProcFlags.Jump, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } } diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 02d16a73b..7e1e74544 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -141,7 +141,7 @@ namespace Game if (factionTemplateEntry != null) GetPlayer().GetReputationMgr().SetVisible(factionTemplateEntry); - GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk); + GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting); // Stop the npc if moving unit.PauseMovement(WorldConfig.GetUIntValue(WorldCfg.CreatureStopForPlayer)); diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 1c08322da..998a0810a 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -115,6 +115,8 @@ namespace Game } } + user.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ItemUse); + SpellCastTargets targets = new(user, packet.Cast); // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index dc3925e8d..d2bd68e90 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -919,7 +919,7 @@ namespace Game.Spells if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) { // drop flag at invisibiliy in bg - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } target.UpdateObjectVisibility(); } @@ -987,7 +987,7 @@ namespace Game.Spells if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) { // drop flag at stealth in bg - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } target.UpdateObjectVisibility(); } @@ -1113,14 +1113,7 @@ namespace Game.Spells Unit target = aurApp.GetTarget(); if (apply) - { PhasingHandler.AddPhase(target, (uint)GetMiscValueB(), true); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check - // drop flag at invisibiliy in bg - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); - } else PhasingHandler.RemovePhase(target, (uint)GetMiscValueB(), true); } @@ -1134,14 +1127,7 @@ namespace Game.Spells Unit target = aurApp.GetTarget(); if (apply) - { PhasingHandler.AddPhaseGroup(target, (uint)GetMiscValueB(), true); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check - // drop flag at invisibiliy in bg - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); - } else PhasingHandler.RemovePhaseGroup(target, (uint)GetMiscValueB(), true); } @@ -1226,6 +1212,9 @@ namespace Game.Spells if (transformSpellInfo == null || !GetSpellInfo().IsPositive()) target.SetDisplayId(modelid); } + + if (!shapeInfo.Flags.HasAnyFlag(SpellShapeshiftFormFlags.Stance)) + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Shapeshifting, GetId()); } else { @@ -1602,7 +1591,6 @@ namespace Game.Spells } } target.CombatStop(); - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); // prevent interrupt message if (GetCasterGUID() == target.GetGUID() && target.GetCurrentSpell(CurrentSpellTypes.Generic) != null) @@ -1647,10 +1635,7 @@ namespace Game.Spells // call functions which may have additional effects after chainging state of unit if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) - { target.CombatStop(); - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); - } } [AuraEffectHandler(AuraType.ModDisarm)] @@ -2686,8 +2671,9 @@ namespace Game.Spells m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); // when removing flag aura, handle flag drop + // TODO: this should be handled in aura script for flag spells using AfterEffectRemove hook Player player = target.ToPlayer(); - if (!apply && player != null && GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.ImmuneOrLostSelection)) + if (!apply && player != null && GetSpellInfo().HasAuraInterruptFlag(SpellAuraInterruptFlags.StealthOrInvis)) { if (player.InBattleground()) { @@ -2741,13 +2727,16 @@ namespace Game.Spells } } - if (apply && GetMiscValue() == (int)SpellSchoolMask.Normal) - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); + // TODO: should be changed to a proc script on flag spell (they have "Taken positive" proc flags in db2) + { + if (apply && GetMiscValue() == (int)SpellSchoolMask.Normal) + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); - // remove all flag auras (they are positive, but they must be removed when you are immune) - if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) - && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) - target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ImmuneOrLostSelection); + // remove all flag auras (they are positive, but they must be removed when you are immune) + if (GetSpellInfo().HasAttribute(SpellAttr1.DispelAurasOnImmunity) + && GetSpellInfo().HasAttribute(SpellAttr2.DamageReducedShield)) + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); + } } [AuraEffectHandler(AuraType.DamageImmunity)] diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 055ebc164..1e34d1a6c 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2007,7 +2007,7 @@ namespace Game.Spells // Failed Pickpocket, reveal rogue if (missInfo == SpellMissInfo.Resist && m_spellInfo.HasAttribute(SpellCustomAttributes.PickPocket) && unitTarget.IsTypeId(TypeId.Unit)) { - m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk); + m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting); unitTarget.ToCreature().EngageWithTarget(m_caster); } } @@ -2096,7 +2096,7 @@ namespace Game.Spells return SpellMissInfo.Evade; if (m_caster._IsValidAttackTarget(unit, m_spellInfo)) - unit.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Hitbyspell); + unit.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.HostileActionReceived); else if (m_caster.IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets @@ -2556,17 +2556,7 @@ namespace Game.Spells // stealth must be removed at cast starting (at show channel bar) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && m_spellInfo.IsBreakingStealth()) - { - m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Cast); - foreach (SpellEffectInfo effect in m_spellInfo.GetEffects()) - { - if (effect != null && effect.GetUsedTargetObjectType() == SpellTargetObjectTypes.Unit) - { - m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.SpellAttack); - break; - } - } - } + m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Action); m_caster.SetCurrentCastSpell(this); @@ -2917,6 +2907,7 @@ namespace Game.Spells if (!hitMask.HasAnyFlag(ProcFlagsHit.Critical)) hitMask |= ProcFlagsHit.Normal; + m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed); m_originalCaster.ProcSkillsAndAuras(null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); // Call CreatureAI hook OnSuccessfulSpellCast @@ -2943,13 +2934,13 @@ namespace Game.Spells m_caster.ModSpellDurationTime(m_spellInfo, ref duration, this); m_spellState = SpellState.Casting; - m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags); + m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags, m_spellInfo.ChannelInterruptFlags2); SendChannelStart((uint)duration); } else if (duration == -1) { m_spellState = SpellState.Casting; - m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags); + m_caster.AddInterruptMask(m_spellInfo.ChannelInterruptFlags, m_spellInfo.ChannelInterruptFlags2); SendChannelStart((uint)duration); } } @@ -4591,7 +4582,7 @@ namespace Game.Spells // skip stuck spell to allow use it in falling case and apply spell limitations at movement SpellEffectInfo effect = m_spellInfo.GetEffect(0); if ((!m_caster.HasUnitMovementFlag(MovementFlag.FallingFar) || (effect != null && effect.Effect != SpellEffectName.Stuck)) && - (IsAutoRepeat() || m_spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated))) + (IsAutoRepeat() || m_spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing))) return SpellCastResult.Moving; } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 8ec3127b6..b8f1f55b3 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -2698,7 +2698,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.HasChannelInterruptFlag(SpellChannelInterruptFlags.Interrupt)))) + || (i == CurrentSpellTypes.Channeled))) { if (m_originalCaster != null) { diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 81b7c328b..bcd6c38af 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -179,8 +179,10 @@ namespace Game.Spells if (_interrupt != null) { InterruptFlags = (SpellInterruptFlags)_interrupt.InterruptFlags; - Array.Copy(_interrupt.AuraInterruptFlags, AuraInterruptFlags, 2); - Array.Copy(_interrupt.ChannelInterruptFlags, ChannelInterruptFlags, 2); + AuraInterruptFlags = (SpellAuraInterruptFlags)_interrupt.AuraInterruptFlags[0]; + AuraInterruptFlags2 = (SpellAuraInterruptFlags2)_interrupt.AuraInterruptFlags[1]; + ChannelInterruptFlags = (SpellAuraInterruptFlags)_interrupt.ChannelInterruptFlags[0]; + ChannelInterruptFlags2 = (SpellAuraInterruptFlags2)_interrupt.ChannelInterruptFlags[1]; } // SpellLevelsEntry @@ -559,7 +561,7 @@ namespace Game.Spells public bool IsMoveAllowedChannel() { - return IsChanneled() && (HasAttribute(SpellAttr5.CanChannelWhenMoving) || !ChannelInterruptFlags[0].HasAnyFlag((uint)(SpellAuraInterruptFlags.Move | SpellAuraInterruptFlags.Turning))); + return IsChanneled() && (HasAttribute(SpellAttr5.CanChannelWhenMoving) || !ChannelInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.Moving | SpellAuraInterruptFlags.Turning)); } public bool NeedsComboPoints() @@ -1447,7 +1449,7 @@ namespace Game.Spells case SpellFamilyNames.Generic: { // Food / Drinks (mostly) - if (HasAuraInterruptFlag(SpellAuraInterruptFlags.NotSeated)) + if (HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing)) { bool food = false; bool drink = false; @@ -2405,6 +2407,9 @@ namespace Game.Spells auraSpellInfo.Id != Id); // Don't remove self }); } + + if (apply && (schoolImmunity & (uint)SpellSchoolMask.Normal) != 0) + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.InvulnerabilityBuff); } uint mechanicImmunity = immuneInfo.MechanicImmuneMask; @@ -2438,8 +2443,13 @@ namespace Game.Spells uint damageImmunity = immuneInfo.DamageSchoolMask; if (damageImmunity != 0) + { target.ApplySpellImmune(Id, SpellImmunity.Damage, damageImmunity, apply); + if (apply && (damageImmunity & (uint)SpellSchoolMask.Normal) != 0) + target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.InvulnerabilityBuff); + } + foreach (AuraType auraType in immuneInfo.AuraTypeImmune) { target.ApplySpellImmune(Id, SpellImmunity.State, auraType, apply); @@ -3599,12 +3609,13 @@ namespace Game.Spells public bool HasAttribute(SpellAttr14 attribute) { return Convert.ToBoolean(AttributesEx14 & attribute); } public bool HasAttribute(SpellCustomAttributes attribute) { return Convert.ToBoolean(AttributesCu & attribute); } - public bool HasAnyAuraInterruptFlag() { return AuraInterruptFlags.Any(flag => 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; } + public bool HasAnyAuraInterruptFlag() { return AuraInterruptFlags != SpellAuraInterruptFlags.None || AuraInterruptFlags2 != SpellAuraInterruptFlags2.None; } + public bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) { return AuraInterruptFlags.HasAnyFlag(flag); } + public bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) { return AuraInterruptFlags2.HasAnyFlag(flag); } + public bool HasChannelInterruptFlag(SpellAuraInterruptFlags flag) { return ChannelInterruptFlags.HasAnyFlag(flag); } + public bool HasChannelInterruptFlag(SpellAuraInterruptFlags2 flag) { return ChannelInterruptFlags2.HasAnyFlag(flag); } + #region Fields public uint Id { get; set; } public Difficulty Difficulty { get; set; } @@ -3648,8 +3659,10 @@ namespace Game.Spells public uint StartRecoveryCategory { get; set; } public uint StartRecoveryTime { get; set; } public SpellInterruptFlags InterruptFlags { get; set; } - public uint[] AuraInterruptFlags { get; set; } = new uint[2]; - public uint[] ChannelInterruptFlags { get; set; } = new uint[2]; + public SpellAuraInterruptFlags AuraInterruptFlags { get; set; } + public SpellAuraInterruptFlags2 AuraInterruptFlags2 { get; set; } + public SpellAuraInterruptFlags ChannelInterruptFlags { get; set; } + public SpellAuraInterruptFlags2 ChannelInterruptFlags2 { get; set; } 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 55734f749..e525de897 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2546,10 +2546,10 @@ namespace Game.Entities spellInfo.StartRecoveryCategory = spellsResult.Read(37); spellInfo.StartRecoveryTime = spellsResult.Read(38); spellInfo.InterruptFlags = (SpellInterruptFlags)spellsResult.Read(39); - spellInfo.AuraInterruptFlags[0] = spellsResult.Read(40); - spellInfo.AuraInterruptFlags[1] = spellsResult.Read(41); - spellInfo.ChannelInterruptFlags[0] = spellsResult.Read(42); - spellInfo.ChannelInterruptFlags[1] = spellsResult.Read(43); + spellInfo.AuraInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read(40); + spellInfo.AuraInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read(41); + spellInfo.ChannelInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read(42); + spellInfo.ChannelInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read(43); spellInfo.ProcFlags = (ProcFlags)spellsResult.Read(44); spellInfo.ProcChance = spellsResult.Read(45); spellInfo.ProcCharges = spellsResult.Read(46); @@ -3175,7 +3175,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[0] = (uint)(SpellAuraInterruptFlags.Hitbyspell | SpellAuraInterruptFlags.TakeDamage); + spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags.HostileActionReceived | SpellAuraInterruptFlags.Damage; break; case 71838: // Drain Life - Bryntroll Normal case 71839: // Drain Life - Bryntroll Heroic @@ -3210,7 +3210,7 @@ namespace Game.Entities spellInfo.AttributesEx |= SpellAttr1.NoThreat; break; case 29726: // Test Ribbon Pole Channel - spellInfo.InterruptFlags &= ~SpellInterruptFlags.Interrupt;//AURA_INTERRUPT_FLAG_CAST + spellInfo.ChannelInterruptFlags &= ~SpellAuraInterruptFlags.Action;//AURA_INTERRUPT_FLAG_CAST break; case 42767: // Sic'em spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.UnitNearbyEntry); @@ -3284,7 +3284,8 @@ namespace Game.Entities break; case 63414: // Spinning Up (Mimiron) spellInfo.GetEffect(0).TargetB = new SpellImplicitTargetInfo(Targets.UnitCaster); - spellInfo.ChannelInterruptFlags.Clear(); + spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags.None; + spellInfo.ChannelInterruptFlags2 = SpellAuraInterruptFlags2.None; break; case 63036: // Rocket Strike (Mimiron) spellInfo.Speed = 0; @@ -3508,7 +3509,7 @@ namespace Game.Entities spellInfo.GetEffect(0).MaxRadiusEntry = CliDB.SpellRadiusStorage.LookupByKey(EffectRadiusIndex.Yards45); break; case 24314: // Threatening Gaze - spellInfo.AuraInterruptFlags[0] |= (uint)(SpellAuraInterruptFlags.Cast | SpellAuraInterruptFlags.Move | SpellAuraInterruptFlags.Jump); + spellInfo.AuraInterruptFlags |= SpellAuraInterruptFlags.Action | SpellAuraInterruptFlags.Moving | SpellAuraInterruptFlags.Anim; break; case 783: // Travel Form (dummy) - cannot be cast indoors. spellInfo.Attributes |= SpellAttr0.OutdoorsOnly; @@ -3546,7 +3547,7 @@ namespace Game.Entities break; // Blaze of Glory case 99252: - spellInfo.AuraInterruptFlags[0] |= (uint)SpellAuraInterruptFlags.ChangeMap; + spellInfo.AuraInterruptFlags |= SpellAuraInterruptFlags.LeaveWorld; break; // ENDOF FIRELANDS SPELLS