From cf15d538cc1e70ebc7cd07ae2bb713012d0527ec Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sat, 7 May 2022 14:56:20 -0400 Subject: [PATCH] Core/Spells: Load entire proc flags array from db2 Port From (https://github.com/TrinityCore/TrinityCore/commit/3844c79adb749432b0f41b9b1aecde7287b9f765) --- .../Framework/Constants/Spells/SpellConst.cs | 9 + Source/Framework/Dynamic/FlagArray.cs | 173 ++++++++++-------- .../DataStorage/ClientReader/DB6Storage.cs | 2 +- Source/Game/Entities/Unit/Unit.Combat.cs | 22 +-- Source/Game/Entities/Unit/Unit.Fields.cs | 10 +- Source/Game/Entities/Unit/Unit.Spells.cs | 20 +- Source/Game/Entities/Unit/Unit.cs | 2 +- Source/Game/Handlers/MovementHandler.cs | 3 +- Source/Game/Maps/Instances/InstanceScript.cs | 3 +- Source/Game/Spells/Auras/AuraEffect.cs | 28 +-- Source/Game/Spells/Spell.cs | 124 ++++++++----- Source/Game/Spells/SpellEffects.cs | 4 +- Source/Game/Spells/SpellInfo.cs | 4 +- Source/Game/Spells/SpellManager.cs | 120 ++++++------ Source/Scripts/Spells/Items.cs | 2 +- 15 files changed, 292 insertions(+), 234 deletions(-) diff --git a/Source/Framework/Constants/Spells/SpellConst.cs b/Source/Framework/Constants/Spells/SpellConst.cs index a5ff29d69..874ae7742 100644 --- a/Source/Framework/Constants/Spells/SpellConst.cs +++ b/Source/Framework/Constants/Spells/SpellConst.cs @@ -2507,6 +2507,15 @@ namespace Framework.Constants MeleeBasedTriggerMask = (DoneMeleeAutoAttack | TakenMeleeAutoAttack | DoneSpellMeleeDmgClass | TakenSpellMeleeDmgClass | DoneRangedAutoAttack | TakenRangedAutoAttack | DoneSpellRangedDmgClass | TakenSpellRangedDmgClass) } + + public enum ProcFlags2 + { + None = 0x00, + TargetDies = 0x01, + Knockback = 0x02, + CastSuccessful = 0x04 + } + public enum ProcFlagsSpellPhase { None = 0x0, diff --git a/Source/Framework/Dynamic/FlagArray.cs b/Source/Framework/Dynamic/FlagArray.cs index cb453b9d4..e4ffa1313 100644 --- a/Source/Framework/Dynamic/FlagArray.cs +++ b/Source/Framework/Dynamic/FlagArray.cs @@ -19,104 +19,119 @@ using System; namespace Framework.Dynamic { - public class FlagArray128 + public class FlagsArray where T : struct { - public FlagArray128(params uint[] parts) + protected dynamic[] _storage; + + public FlagsArray(uint length) { - _values = new uint[4]; - for (var i = 0; i < parts.Length; ++i) - _values[i] = parts[i]; + _storage = new dynamic[length]; } - public FlagArray128(int[] parts) + public FlagsArray(params T[] parts) { - _values = new uint[4]; + _storage = new dynamic[parts.Length]; for (var i = 0; i < parts.Length; ++i) - _values[i] = (uint)parts[i]; + _storage[i] = parts[i]; } + public FlagsArray(T[] parts, uint length) + { + _storage = new dynamic[length]; + for (var i = 0; i < length && i < parts.Length; ++i) + _storage[i] = parts[i]; + } + + public static bool operator <(FlagsArray left, FlagsArray right) + { + for (var i = left._storage.Length; i > 0; --i) + { + if ((dynamic)left._storage[i - 1] < right._storage[i - 1]) + return true; + else if ((dynamic)left._storage[i - 1] > right._storage[i - 1]) + return false; + } + return false; + } + public static bool operator >(FlagsArray left, FlagsArray right) + { + for (var i = left._storage.Length; i > 0; --i) + { + if ((dynamic)left._storage[i - 1] > right._storage[i - 1]) + return true; + else if ((dynamic)left._storage[i - 1] < right._storage[i - 1]) + return false; + } + return false; + } + + public static FlagArray128 operator &(FlagsArray left, FlagsArray right) + { + FlagArray128 fl = new(); + for (var i = 0; i < left._storage.Length; ++i) + fl[i] = left._storage[i] & right._storage[i]; + return fl; + } + public static FlagArray128 operator |(FlagsArray left, FlagsArray right) + { + FlagArray128 fl = new(); + for (var i = 0; i < left._storage.Length; ++i) + fl[i] = left._storage[i] | right._storage[i]; + return fl; + } + public static FlagArray128 operator ^(FlagsArray left, FlagsArray right) + { + FlagArray128 fl = new(); + for (var i = 0; i < left._storage.Length; ++i) + fl[i] = left._storage[i] ^ right._storage[i]; + return fl; + } + + public static implicit operator bool(FlagsArray left) + { + for (var i = 0; i < left._storage.Length; ++i) + if (left._storage[i] != 0) + return true; + + return false; + } + + public T this[int i] + { + get + { + return _storage[i]; + } + set + { + _storage[i] = value; + } + } + } + + public class FlagArray128 : FlagsArray + { + public FlagArray128(params uint[] parts) : base(parts, 4) { } + public bool IsEqual(params uint[] parts) { - for (var i = 0; i < _values.Length; ++i) - if (_values[i] == parts[i]) + for (var i = 0; i < _storage.Length; ++i) + if (_storage[i] == parts[i]) return false; return true; } + public bool HasFlag(params uint[] parts) + { + return (_storage[0] & parts[0] || _storage[1] & parts[1] || _storage[2] & parts[2] || _storage[3] & parts[3]); + } + public void Set(params uint[] parts) { for (var i = 0; i < parts.Length; ++i) - _values[i] = parts[i]; + _storage[i] = parts[i]; } - - public static bool operator <(FlagArray128 left, FlagArray128 right) - { - for (var i = left._values.Length; i > 0; --i) - { - if (left._values[i - 1] < right._values[i - 1]) - return true; - else if (left._values[i - 1] > right._values[i - 1]) - return false; - } - return false; - } - public static bool operator >(FlagArray128 left, FlagArray128 right) - { - for (var i = left._values.Length; i > 0; --i) - { - if (left._values[i - 1] > right._values[i - 1]) - return true; - else if (left._values[i - 1] < right._values[i - 1]) - return false; - } - return false; - } - - public static FlagArray128 operator &(FlagArray128 left, FlagArray128 right) - { - FlagArray128 fl = new(); - for (var i = 0; i < left._values.Length; ++i) - fl[i] = left._values[i] & right._values[i]; - return fl; - } - public static FlagArray128 operator |(FlagArray128 left, FlagArray128 right) - { - FlagArray128 fl = new(); - for (var i = 0; i < left._values.Length; ++i) - fl[i] = left._values[i] | right._values[i]; - return fl; - } - public static FlagArray128 operator ^(FlagArray128 left, FlagArray128 right) - { - FlagArray128 fl = new(); - for (var i = 0; i < left._values.Length; ++i) - fl[i] = left._values[i] ^ right._values[i]; - return fl; - } - - public static implicit operator bool (FlagArray128 left) - { - for (var i = 0; i < left._values.Length; ++i) - if (left._values[i] != 0) - return true; - - return false; - } - - public uint this[int i] - { - get - { - return _values[i]; - } - set - { - _values[i] = value; - } - } - - uint[] _values { get; set; } } public class FlaggedArray where T : struct diff --git a/Source/Game/DataStorage/ClientReader/DB6Storage.cs b/Source/Game/DataStorage/ClientReader/DB6Storage.cs index a02f0d984..cdda9bddf 100644 --- a/Source/Game/DataStorage/ClientReader/DB6Storage.cs +++ b/Source/Game/DataStorage/ClientReader/DB6Storage.cs @@ -180,7 +180,7 @@ namespace Game.DataStorage } else if (type == typeof(FlagArray128)) { - f.SetValue(obj, new FlagArray128(ReadArray(result, dbIndex, 4))); + f.SetValue(obj, new FlagArray128(ReadArray(result, dbIndex, 4))); dbIndex += 4; } break; diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index c18907a6f..d7a4b93d3 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -47,7 +47,7 @@ namespace Game.Entities InterruptNonMeleeSpells(false); RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.EnteringCombat); - ProcSkillsAndAuras(this, null, ProcFlags.EnterCombat, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + ProcSkillsAndAuras(this, null, new ProcFlagsInit(ProcFlags.EnterCombat), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } public virtual void AtExitCombat() @@ -793,14 +793,14 @@ namespace Game.Entities // proc only once for victim Unit owner = attacker.GetOwner(); if (owner != null) - ProcSkillsAndAuras(owner, victim, ProcFlags.Kill, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + ProcSkillsAndAuras(owner, victim, new ProcFlagsInit(ProcFlags.Kill), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } if (!victim.IsCritter()) - ProcSkillsAndAuras(attacker, victim, ProcFlags.Kill, ProcFlags.Killed, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + ProcSkillsAndAuras(attacker, victim, new ProcFlagsInit(ProcFlags.Kill), new ProcFlagsInit(ProcFlags.Killed), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); // Proc auras on death - must be before aura/combat remove - ProcSkillsAndAuras(victim, victim, ProcFlags.None, ProcFlags.Death, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + ProcSkillsAndAuras(victim, victim, new ProcFlagsInit(ProcFlags.None), new ProcFlagsInit(ProcFlags.Death), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); // update get killing blow achievements, must be done before setDeathState to be able to require auras on target // and before Spirit of Redemption as it also removes auras @@ -1026,8 +1026,8 @@ namespace Game.Entities damageInfo.TargetState = 0; damageInfo.AttackType = attackType; - damageInfo.ProcAttacker = ProcFlags.None; - damageInfo.ProcVictim = ProcFlags.None; + damageInfo.ProcAttacker = new ProcFlagsInit(); + damageInfo.ProcVictim = new ProcFlagsInit(); damageInfo.CleanDamage = 0; damageInfo.HitOutCome = MeleeHitOutcome.Evade; @@ -1041,12 +1041,12 @@ namespace Game.Entities switch (attackType) { case WeaponAttackType.BaseAttack: - damageInfo.ProcAttacker = ProcFlags.DoneMeleeAutoAttack | ProcFlags.DoneMainHandAttack; - damageInfo.ProcVictim = ProcFlags.TakenMeleeAutoAttack; + damageInfo.ProcAttacker = new ProcFlagsInit(ProcFlags.DoneMeleeAutoAttack | ProcFlags.DoneMainHandAttack); + damageInfo.ProcVictim = new ProcFlagsInit(ProcFlags.TakenMeleeAutoAttack); break; case WeaponAttackType.OffAttack: - damageInfo.ProcAttacker = ProcFlags.DoneMeleeAutoAttack | ProcFlags.DoneOffHandAttack; - damageInfo.ProcVictim = ProcFlags.TakenMeleeAutoAttack; + damageInfo.ProcAttacker = new ProcFlagsInit(ProcFlags.DoneMeleeAutoAttack | ProcFlags.DoneOffHandAttack); + damageInfo.ProcVictim = new ProcFlagsInit(ProcFlags.TakenMeleeAutoAttack); damageInfo.HitInfo = HitInfo.OffHand; break; default: @@ -1185,7 +1185,7 @@ namespace Game.Entities // Calculate absorb resist if (damageInfo.Damage > 0) { - damageInfo.ProcVictim |= ProcFlags.TakenDamage; + damageInfo.ProcVictim.Or(ProcFlags.TakenDamage); // Calculate absorb & resists DamageInfo dmgInfo = new(damageInfo); CalcAbsorbResist(dmgInfo); diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index 2e057bab4..43ca652ce 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -162,7 +162,7 @@ namespace Game.Entities public class ProcEventInfo { - public ProcEventInfo(Unit actor, Unit actionTarget, Unit procTarget, ProcFlags typeMask, ProcFlagsSpellType spellTypeMask, + public ProcEventInfo(Unit actor, Unit actionTarget, Unit procTarget, ProcFlagsInit typeMask, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) { _actor = actor; @@ -181,7 +181,7 @@ namespace Game.Entities public Unit GetActionTarget() { return _actionTarget; } public Unit GetProcTarget() { return _procTarget; } - public ProcFlags GetTypeMask() { return _typeMask; } + public ProcFlagsInit GetTypeMask() { return _typeMask; } public ProcFlagsSpellType GetSpellTypeMask() { return _spellTypeMask; } public ProcFlagsSpellPhase GetSpellPhaseMask() { return _spellPhaseMask; } public ProcFlagsHit GetHitMask() { return _hitMask; } @@ -217,7 +217,7 @@ namespace Game.Entities Unit _actor; Unit _actionTarget; Unit _procTarget; - ProcFlags _typeMask; + ProcFlagsInit _typeMask; ProcFlagsSpellType _spellTypeMask; ProcFlagsSpellPhase _spellPhaseMask; ProcFlagsHit _hitMask; @@ -444,8 +444,8 @@ namespace Game.Entities // Helper public WeaponAttackType AttackType { get; set; } - public ProcFlags ProcAttacker { get; set; } - public ProcFlags ProcVictim { get; set; } + public ProcFlagsInit ProcAttacker { get; set; } + public ProcFlagsInit ProcVictim { get; set; } public uint CleanDamage { get; set; } // Used only for rage calculation public MeleeHitOutcome HitOutCome { get; set; } // TODO: remove this field (need use TargetState) } diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 3d96c37bf..83d636547 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1419,28 +1419,28 @@ namespace Game.Entities return false; } - - public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) + + public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlagsInit typeMaskActor, ProcFlagsInit typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) { WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack; - if (typeMaskActor != 0 && actor != null) + if (typeMaskActor && actor != null) actor.ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType); - if (typeMaskActionTarget != 0 && actionTarget) + if (typeMaskActionTarget && actionTarget) actionTarget.ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType); if (actor != null) actor.TriggerAurasProcOnEvent(null, null, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); } - void ProcSkillsAndReactives(bool isVictim, Unit procTarget, ProcFlags typeMask, ProcFlagsHit hitMask, WeaponAttackType attType) + void ProcSkillsAndReactives(bool isVictim, Unit procTarget, ProcFlagsInit typeMask, ProcFlagsHit hitMask, WeaponAttackType attType) { // Player is loaded now - do not allow passive spell casts to proc if (IsPlayer() && ToPlayer().GetSession().PlayerLoading()) return; // For melee/ranged based attack need update skills and set some Aura states if victim present - if (typeMask.HasAnyFlag(ProcFlags.MeleeBasedTriggerMask) && procTarget) + if (typeMask.HasFlag(ProcFlags.MeleeBasedTriggerMask) && procTarget) { // If exist crit/parry/dodge/block need update aura state (for victim and attacker) if (hitMask.HasAnyFlag(ProcFlagsHit.Critical | ProcFlagsHit.Parry | ProcFlagsHit.Dodge | ProcFlagsHit.Block)) @@ -1508,12 +1508,12 @@ namespace Game.Entities } } - void TriggerAurasProcOnEvent(List myProcAuras, List targetProcAuras, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) + void TriggerAurasProcOnEvent(List myProcAuras, List targetProcAuras, Unit actionTarget, ProcFlagsInit typeMaskActor, ProcFlagsInit typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) { // prepare data for self trigger ProcEventInfo myProcEventInfo = new(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); List> myAurasTriggeringProc = new(); - if (typeMaskActor != 0) + if (typeMaskActor) { GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo); @@ -1537,12 +1537,12 @@ namespace Game.Entities // prepare data for target trigger ProcEventInfo targetProcEventInfo = new(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo); List> targetAurasTriggeringProc = new(); - if (typeMaskActionTarget != 0 && actionTarget) + if (typeMaskActionTarget && actionTarget) actionTarget.GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo); TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc); - if (typeMaskActionTarget != 0 && actionTarget) + if (typeMaskActionTarget && actionTarget) actionTarget.TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc); } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 106a077c9..2c100a1de 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -3513,7 +3513,7 @@ namespace Game.Entities caster.SendSpellNonMeleeDamageLog(log); // break 'Fear' and similar auras - ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, ProcFlags.None, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null); + ProcSkillsAndAuras(damageInfo.GetAttacker(), caster, new ProcFlagsInit(ProcFlags.None), new ProcFlagsInit(ProcFlags.TakenSpellMagicDmgClassNeg), ProcFlagsSpellType.Damage, ProcFlagsSpellPhase.Hit, ProcFlagsHit.None, null, damageInfo, null); } } } diff --git a/Source/Game/Handlers/MovementHandler.cs b/Source/Game/Handlers/MovementHandler.cs index 38c9ccd12..8e5b8f8af 100644 --- a/Source/Game/Handlers/MovementHandler.cs +++ b/Source/Game/Handlers/MovementHandler.cs @@ -24,6 +24,7 @@ using Game.Maps; using Game.Movement; using Game.Networking; using Game.Networking.Packets; +using Game.Spells; using System; using System.Collections.Generic; using System.Linq; @@ -205,7 +206,7 @@ namespace Game if (opcode == ClientOpcodes.MoveJump) { plrMover.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2.Jump); // Mind Control - Unit.ProcSkillsAndAuras(plrMover, null, ProcFlags.Jump, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + Unit.ProcSkillsAndAuras(plrMover, null, new ProcFlagsInit(ProcFlags.Jump), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); } } } diff --git a/Source/Game/Maps/Instances/InstanceScript.cs b/Source/Game/Maps/Instances/InstanceScript.cs index ce296600f..1e9d0a844 100644 --- a/Source/Game/Maps/Instances/InstanceScript.cs +++ b/Source/Game/Maps/Instances/InstanceScript.cs @@ -22,6 +22,7 @@ using Game.Entities; using Game.Groups; using Game.Networking.Packets; using Game.Scenarios; +using Game.Spells; using System; using System.Collections.Generic; using System.Text; @@ -367,7 +368,7 @@ namespace Game.Maps var playerList = instance.GetPlayers(); foreach (var player in playerList) if (player.IsAlive()) - Unit.ProcSkillsAndAuras(player, null, ProcFlags.EncounterStart, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); + Unit.ProcSkillsAndAuras(player, null, new ProcFlagsInit(ProcFlags.EncounterStart), new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); break; } case EncounterState.Fail: diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 8c8f9bf35..3932d23a9 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -90,7 +90,7 @@ namespace Game.Spells case AuraType.Transform: case AuraType.ModRoot2: m_canBeRecalculated = false; - if (m_spellInfo.ProcFlags == 0) + if (!m_spellInfo.ProcFlags) break; amount = (int)(GetBase().GetUnitOwner().CountPctFromMaxHealth(10)); break; @@ -5065,14 +5065,14 @@ namespace Game.Spells Unit.DealDamageMods(caster, target, ref damage, ref absorb); // Set trigger flag - ProcFlags procAttacker = ProcFlags.DonePeriodic; - ProcFlags procVictim = ProcFlags.TakenPeriodic; + ProcFlagsInit procAttacker = new ProcFlagsInit(ProcFlags.DonePeriodic); + ProcFlagsInit procVictim = new ProcFlagsInit(ProcFlags.TakenPeriodic); ProcFlagsHit hitMask = damageInfo.GetHitMask(); if (damage != 0) { hitMask |= crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; - procVictim |= ProcFlags.TakenDamage; + procVictim.Or(ProcFlags.TakenDamage); } int overkill = (int)(damage - target.GetHealth()); @@ -5156,14 +5156,14 @@ namespace Game.Spells log.HitInfo |= HitInfo.CriticalHit; // Set trigger flag - ProcFlags procAttacker = ProcFlags.DonePeriodic; - ProcFlags procVictim = ProcFlags.TakenPeriodic; + ProcFlagsInit procAttacker = new ProcFlagsInit(ProcFlags.DonePeriodic); + ProcFlagsInit procVictim = new ProcFlagsInit(ProcFlags.TakenPeriodic); ProcFlagsHit hitMask = damageInfo.GetHitMask(); if (damage != 0) { hitMask |= crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; - procVictim |= ProcFlags.TakenDamage; + procVictim.Or(ProcFlags.TakenDamage); } int new_damage = (int)Unit.DealDamage(caster, target, damage, cleanDamage, DamageEffectType.DOT, GetSpellInfo().GetSchoolMask(), GetSpellInfo(), false); @@ -5182,7 +5182,7 @@ namespace Game.Spells caster.HealBySpell(healInfo); caster.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); - Unit.ProcSkillsAndAuras(caster, caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, null, null, healInfo); + Unit.ProcSkillsAndAuras(caster, caster, new ProcFlagsInit(ProcFlags.DonePeriodic), new ProcFlagsInit(ProcFlags.TakenPeriodic), ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, hitMask, null, null, healInfo); caster.SendSpellNonMeleeDamageLog(log); } @@ -5214,7 +5214,7 @@ namespace Game.Spells HealInfo healInfo = new(caster, target, damage, GetSpellInfo(), GetSpellInfo().GetSchoolMask()); caster.HealBySpell(healInfo); - Unit.ProcSkillsAndAuras(caster, target, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Normal, null, null, healInfo); + Unit.ProcSkillsAndAuras(caster, target, new ProcFlagsInit(ProcFlags.DonePeriodic), new ProcFlagsInit(ProcFlags.TakenPeriodic), ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Normal, null, null, healInfo); } void HandlePeriodicHealAurasTick(Unit target, Unit caster) @@ -5271,8 +5271,8 @@ namespace Game.Spells if (GetAuraType() == AuraType.ObsModHealth) return; - ProcFlags procAttacker = ProcFlags.DonePeriodic; - ProcFlags procVictim = ProcFlags.TakenPeriodic; + ProcFlagsInit procAttacker = new ProcFlagsInit(ProcFlags.DonePeriodic); + ProcFlagsInit procVictim = new ProcFlagsInit(ProcFlags.TakenPeriodic); ProcFlagsHit hitMask = crit ? ProcFlagsHit.Critical : ProcFlagsHit.Normal; // ignore item heals if (GetBase().GetCastItemGUID().IsEmpty()) @@ -5426,13 +5426,13 @@ namespace Game.Spells Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); // Set trigger flag - ProcFlags procAttacker = ProcFlags.DonePeriodic; - ProcFlags procVictim = ProcFlags.TakenPeriodic; + ProcFlagsInit procAttacker = new ProcFlagsInit(ProcFlags.DonePeriodic); + ProcFlagsInit procVictim = new ProcFlagsInit(ProcFlags.TakenPeriodic); ProcFlagsHit hitMask = Unit.CreateProcHitMask(damageInfo, SpellMissInfo.None); ProcFlagsSpellType spellTypeMask = ProcFlagsSpellType.NoDmgHeal; if (damageInfo.damage != 0) { - procVictim |= ProcFlags.TakenDamage; + procVictim.Or(ProcFlags.TakenDamage); spellTypeMask |= ProcFlagsSpellType.Damage; } diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 8dc58757a..b10c83823 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -1698,29 +1698,29 @@ namespace Game.Spells // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask) //========================================================================================== - m_procVictim = m_procAttacker = 0; + m_procVictim = m_procAttacker = new ProcFlagsInit(); // Get data for type of attack and fill base info for trigger switch (m_spellInfo.DmgClass) { case SpellDmgClass.Melee: - m_procAttacker = ProcFlags.DoneSpellMeleeDmgClass; + m_procAttacker = new ProcFlagsInit(ProcFlags.DoneSpellMeleeDmgClass); if (m_attackType == WeaponAttackType.OffAttack) - m_procAttacker |= ProcFlags.DoneOffHandAttack; + m_procAttacker.Or(ProcFlags.DoneOffHandAttack); else - m_procAttacker |= ProcFlags.DoneMainHandAttack; - m_procVictim = ProcFlags.TakenSpellMeleeDmgClass; + m_procAttacker.Or(ProcFlags.DoneMainHandAttack); + m_procVictim = new ProcFlagsInit(ProcFlags.TakenSpellMeleeDmgClass); break; case SpellDmgClass.Ranged: // Auto attack if (m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) { - m_procAttacker = ProcFlags.DoneRangedAutoAttack; - m_procVictim = ProcFlags.TakenRangedAutoAttack; + m_procAttacker = new ProcFlagsInit(ProcFlags.DoneRangedAutoAttack); + m_procVictim = new ProcFlagsInit(ProcFlags.TakenRangedAutoAttack); } else // Ranged spell attack { - m_procAttacker = ProcFlags.DoneSpellRangedDmgClass; - m_procVictim = ProcFlags.TakenSpellRangedDmgClass; + m_procAttacker = new ProcFlagsInit(ProcFlags.DoneSpellRangedDmgClass); + m_procVictim = new ProcFlagsInit(ProcFlags.TakenSpellRangedDmgClass); } break; default: @@ -1728,8 +1728,8 @@ namespace Game.Spells Convert.ToBoolean(m_spellInfo.EquippedItemSubClassMask & (1 << (int)ItemSubClassWeapon.Wand)) && m_spellInfo.HasAttribute(SpellAttr2.AutorepeatFlag)) // Wands auto attack { - m_procAttacker = ProcFlags.DoneRangedAutoAttack; - m_procVictim = ProcFlags.TakenRangedAutoAttack; + m_procAttacker = new ProcFlagsInit(ProcFlags.DoneRangedAutoAttack); + m_procVictim = new ProcFlagsInit(ProcFlags.TakenRangedAutoAttack); } break; // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers @@ -1741,18 +1741,18 @@ namespace Game.Spells m_spellInfo.Id == 57879 || // Snake Trap - done this way to avoid double proc m_spellInfo.SpellFamilyFlags[2].HasAnyFlag(0x00024000u))) // Explosive and Immolation Trap { - m_procAttacker |= ProcFlags.DoneTrapActivation; + m_procAttacker.Or(ProcFlags.DoneTrapActivation); // also fill up other flags (TargetInfo::DoDamageAndTriggers only fills up flag if both are not set) - m_procAttacker |= ProcFlags.DoneSpellMagicDmgClassNeg; - m_procVictim |= ProcFlags.TakenSpellMagicDmgClassNeg; + m_procAttacker.Or(ProcFlags.DoneSpellMagicDmgClassNeg); + m_procVictim.Or(ProcFlags.TakenSpellMagicDmgClassNeg); } // Hellfire Effect - trigger as DOT if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Warlock && m_spellInfo.SpellFamilyFlags[0].HasAnyFlag(0x00000040u)) { - m_procAttacker = ProcFlags.DonePeriodic; - m_procVictim = ProcFlags.TakenPeriodic; + m_procAttacker = new ProcFlagsInit(ProcFlags.DonePeriodic); + m_procVictim = new ProcFlagsInit(ProcFlags.TakenPeriodic); } } @@ -2882,13 +2882,13 @@ namespace Game.Spells return; // Handle procs on cast - ProcFlags procAttacker = m_procAttacker; - if (procAttacker == 0) + ProcFlagsInit procAttacker = m_procAttacker; + if (!procAttacker) { if (m_spellInfo.DmgClass == SpellDmgClass.Magic) - procAttacker = IsPositive() ? ProcFlags.DoneSpellMagicDmgClassPos : ProcFlags.DoneSpellMagicDmgClassNeg; + procAttacker = new ProcFlagsInit(IsPositive() ? ProcFlags.DoneSpellMagicDmgClassPos : ProcFlags.DoneSpellMagicDmgClassNeg); else - procAttacker = IsPositive() ? ProcFlags.DoneSpellNoneDmgClassPos : ProcFlags.DoneSpellNoneDmgClassNeg; + procAttacker = new ProcFlagsInit(IsPositive() ? ProcFlags.DoneSpellNoneDmgClassPos : ProcFlags.DoneSpellNoneDmgClassNeg); } ProcFlagsHit hitMask = m_hitMask; @@ -2898,7 +2898,7 @@ namespace Game.Spells if (!_triggeredCastFlags.HasAnyFlag(TriggerCastFlags.IgnoreAuraInterruptFlags) && !m_spellInfo.HasAttribute(SpellAttr2.IgnoreActionAuraInterruptFlags)) m_originalCaster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.ActionDelayed); - Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); + Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Cast, hitMask, this, null, null); // Call CreatureAI hook OnSuccessfulSpellCast Creature caster = m_originalCaster.ToCreature(); @@ -3144,16 +3144,16 @@ namespace Game.Spells if (!m_originalCaster) return; - ProcFlags procAttacker = m_procAttacker; - if (procAttacker == 0) + ProcFlagsInit procAttacker = m_procAttacker; + if (!procAttacker) { if (m_spellInfo.DmgClass == SpellDmgClass.Magic) - procAttacker = IsPositive() ? ProcFlags.DoneSpellMagicDmgClassPos : ProcFlags.DoneSpellMagicDmgClassNeg; + procAttacker = new ProcFlagsInit(IsPositive() ? ProcFlags.DoneSpellMagicDmgClassPos : ProcFlags.DoneSpellMagicDmgClassNeg); else - procAttacker = IsPositive() ? ProcFlags.DoneSpellNoneDmgClassPos : ProcFlags.DoneSpellNoneDmgClassNeg; + procAttacker = new ProcFlagsInit(IsPositive() ? ProcFlags.DoneSpellNoneDmgClassPos : ProcFlags.DoneSpellNoneDmgClassNeg); } - Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, ProcFlags.None, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null); + Unit.ProcSkillsAndAuras(m_originalCaster, null, procAttacker, new ProcFlagsInit(ProcFlags.None), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Finish, m_hitMask, this, null, null); } void SendSpellCooldown() @@ -7047,7 +7047,7 @@ namespace Game.Spells { return m_originalCaster != null ? m_originalCaster : m_caster.ToUnit(); } - + bool IsValidDeadOrAliveTarget(Unit target) { if (target.IsAlive()) @@ -7865,8 +7865,8 @@ namespace Game.Spells // ****************************************** // Spell trigger system // ****************************************** - internal ProcFlags m_procAttacker; // Attacker trigger flags - internal ProcFlags m_procVictim; // Victim trigger flags + internal ProcFlagsInit m_procAttacker; // Attacker trigger flags + internal ProcFlagsInit m_procVictim; // Victim trigger flags internal ProcFlagsHit m_hitMask; // ***************************************** @@ -8028,7 +8028,7 @@ namespace Game.Spells TransportGUID.Clear(); TransportOffset.Relocate(0, 0, 0, 0); } - + public SpellDestination(WorldObject wObj) : this() { TransportGUID = wObj.GetTransGUID(); @@ -8190,8 +8190,8 @@ namespace Game.Spells if (caster != null) { // Fill base trigger info - ProcFlags procAttacker = spell.m_procAttacker; - ProcFlags procVictim = spell.m_procVictim; + ProcFlagsInit procAttacker = spell.m_procAttacker; + ProcFlagsInit procVictim = spell.m_procVictim; ProcFlagsSpellType procSpellType = ProcFlagsSpellType.None; ProcFlagsHit hitMask = ProcFlagsHit.None; @@ -8200,7 +8200,7 @@ namespace Game.Spells (spell.CanExecuteTriggersOnHit(EffectMask) || MissCondition == SpellMissInfo.Immune || MissCondition == SpellMissInfo.Immune2); // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now - if (canEffectTrigger && procAttacker == 0 && procVictim == 0) + if (canEffectTrigger && !procAttacker && !procVictim) { bool positive = true; if (spell.m_damage > 0) @@ -8226,25 +8226,25 @@ namespace Game.Spells case SpellDmgClass.Magic: if (positive) { - procAttacker |= ProcFlags.DoneSpellMagicDmgClassPos; - procVictim |= ProcFlags.TakenSpellMagicDmgClassPos; + procAttacker.Or(ProcFlags.DoneSpellMagicDmgClassPos); + procVictim.Or(ProcFlags.TakenSpellMagicDmgClassPos); } else { - procAttacker |= ProcFlags.DoneSpellMagicDmgClassNeg; - procVictim |= ProcFlags.TakenSpellMagicDmgClassNeg; + procAttacker.Or(ProcFlags.DoneSpellMagicDmgClassNeg); + procVictim.Or(ProcFlags.TakenSpellMagicDmgClassNeg); } break; case SpellDmgClass.None: if (positive) { - procAttacker |= ProcFlags.DoneSpellNoneDmgClassPos; - procVictim |= ProcFlags.TakenSpellNoneDmgClassPos; + procAttacker.Or(ProcFlags.DoneSpellNoneDmgClassPos); + procVictim.Or(ProcFlags.TakenSpellNoneDmgClassPos); } else { - procAttacker |= ProcFlags.DoneSpellNoneDmgClassNeg; - procVictim |= ProcFlags.TakenSpellNoneDmgClassNeg; + procAttacker.Or(ProcFlags.DoneSpellNoneDmgClassNeg); + procVictim.Or(ProcFlags.TakenSpellNoneDmgClassNeg); } break; } @@ -8297,7 +8297,7 @@ namespace Game.Spells Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); hitMask |= Unit.CreateProcHitMask(damageInfo, MissCondition); - procVictim |= ProcFlags.TakenDamage; + procVictim.Or(ProcFlags.TakenDamage); spell.m_damage = (int)damageInfo.damage; @@ -8482,7 +8482,7 @@ namespace Game.Spells spell.CallScriptAfterHitHandlers(); } } - + public class SpellValue { public SpellValue(SpellInfo proto, WorldObject caster) @@ -8934,7 +8934,7 @@ namespace Game.Spells ProcFlagsSpellPhase spellPhaseMask = ProcFlagsSpellPhase.None; ProcFlagsHit hitMask = ProcFlagsHit.Reflect; - Unit.ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, null, null, null); + Unit.ProcSkillsAndAuras(caster, _victim, new ProcFlagsInit(typeMaskActor), new ProcFlagsInit(typeMaskActionTarget), spellTypeMask, spellPhaseMask, hitMask, null, null, null); return true; } @@ -8988,7 +8988,7 @@ namespace Game.Spells Targets = targets; } } - + public class CastSpellExtraArgs { public TriggerCastFlags TriggerFlags; @@ -9061,7 +9061,7 @@ namespace Game.Spells } return this; } - + public CastSpellExtraArgs SetTriggeringAura(AuraEffect triggeringAura) { TriggeringAura = triggeringAura; @@ -9106,6 +9106,38 @@ namespace Game.Spells public List GenericVictimTargets = new(); public List TradeSkillTargets = new(); public List FeedPetTargets = new(); + } + public class ProcFlagsInit : FlagsArray + { + public ProcFlagsInit(ProcFlags procFlags = 0, ProcFlags2 procFlags2 = 0) : base(2) + { + _storage[0] = (int)procFlags; + _storage[1] = (int)procFlags2; + } + + public ProcFlagsInit(params int[] flags) : base(flags) { } + + public ProcFlagsInit Or(ProcFlags procFlags) + { + _storage[0] |= (int)procFlags; + return this; + } + + public ProcFlagsInit Or(ProcFlags2 procFlags2) + { + _storage[1] |= (int)procFlags2; + return this; + } + + public bool HasFlag(ProcFlags procFlags) + { + return (_storage[0] & procFlags) != 0; + } + + public bool HasFlag(ProcFlags2 procFlags) + { + return (_storage[1] & procFlags) != 0; + } } } \ No newline at end of file diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 0aaefb7fe..272afeb56 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -2627,9 +2627,9 @@ namespace Game.Spells duration = unitTarget.ModSpellDuration(m_spellInfo, unitTarget, duration, false, 1u << (int)effectInfo.EffectIndex); unitTarget.GetSpellHistory().LockSpellSchool(curSpellInfo.GetSchoolMask(), TimeSpan.FromMilliseconds(duration)); if (m_spellInfo.DmgClass == SpellDmgClass.Magic) - Unit.ProcSkillsAndAuras(unitCaster, unitTarget, ProcFlags.DoneSpellMagicDmgClassNeg, ProcFlags.TakenSpellMagicDmgClassNeg, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null); + Unit.ProcSkillsAndAuras(unitCaster, unitTarget, new ProcFlagsInit(ProcFlags.DoneSpellMagicDmgClassNeg), new ProcFlagsInit(ProcFlags.TakenSpellMagicDmgClassNeg), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null); else if (m_spellInfo.DmgClass == SpellDmgClass.Melee) - Unit.ProcSkillsAndAuras(unitCaster, unitTarget, ProcFlags.DoneSpellMeleeDmgClass, ProcFlags.TakenSpellMeleeDmgClass, ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null); + Unit.ProcSkillsAndAuras(unitCaster, unitTarget, new ProcFlagsInit(ProcFlags.DoneSpellMeleeDmgClass), new ProcFlagsInit(ProcFlags.TakenSpellMeleeDmgClass), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.Hit, ProcFlagsHit.Interrupt, null, null, null); } SendSpellInterruptLog(unitTarget, curSpellInfo.Id); unitTarget.InterruptSpell(i, false); diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 944ac8eaa..dcbd9fdae 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -94,7 +94,7 @@ namespace Game.Spells SpellAuraOptionsRecord _options = data.AuraOptions; if (_options != null) { - ProcFlags = (ProcFlags)_options.ProcTypeMask[0]; + ProcFlags = new ProcFlagsInit(_options.ProcTypeMask); ProcChance = _options.ProcChance; ProcCharges = (uint)_options.ProcCharges; ProcCooldown = _options.ProcCategoryRecovery; @@ -3948,7 +3948,7 @@ namespace Game.Spells public SpellAuraInterruptFlags2 AuraInterruptFlags2 { get; set; } public SpellAuraInterruptFlags ChannelInterruptFlags { get; set; } public SpellAuraInterruptFlags2 ChannelInterruptFlags2 { get; set; } - public ProcFlags ProcFlags { get; set; } + public ProcFlagsInit ProcFlags { get; set; } public uint ProcChance { get; set; } public uint ProcCharges { get; set; } public uint ProcCooldown { get; set; } diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index 7f1a48ed8..cfcfbd8b2 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -459,7 +459,7 @@ namespace Game.Entities public static bool CanSpellTriggerProcOnEvent(SpellProcEntry procEntry, ProcEventInfo eventInfo) { // proc type doesn't match - if ((eventInfo.GetTypeMask() & procEntry.ProcFlags) == 0) + if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags)) return false; // check XP or honor target requirement @@ -484,7 +484,7 @@ namespace Game.Entities } // always trigger for these types - if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death)) + if (eventInfo.GetTypeMask().HasFlag(ProcFlags.Killed | ProcFlags.Kill | ProcFlags.Death)) return true; // check school mask (if set) for other trigger types @@ -1293,8 +1293,8 @@ namespace Game.Entities // 0 1 2 3 4 5 6 SQLResult result = DB.World.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, " + - //7 8 9 10 11 12 13 14 15 16 - "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, DisableEffectsMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc"); + //7 8 9 10 11 12 13 14 15 16 17 + "ProcFlags, ProcFlags2, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, DisableEffectsMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc"); uint count = 0; if (!result.IsEmpty()) @@ -1331,16 +1331,16 @@ namespace Game.Entities baseProcEntry.SchoolMask = (SpellSchoolMask)result.Read(1); baseProcEntry.SpellFamilyName = (SpellFamilyNames)result.Read(2); baseProcEntry.SpellFamilyMask = new FlagArray128(result.Read(3), result.Read(4), result.Read(5), result.Read(6)); - baseProcEntry.ProcFlags = (ProcFlags)result.Read(7); - baseProcEntry.SpellTypeMask = (ProcFlagsSpellType)result.Read(8); - baseProcEntry.SpellPhaseMask = (ProcFlagsSpellPhase)result.Read(9); - baseProcEntry.HitMask = (ProcFlagsHit)result.Read(10); - baseProcEntry.AttributesMask = (ProcAttributes)result.Read(11); - baseProcEntry.DisableEffectsMask = result.Read(12); - baseProcEntry.ProcsPerMinute = result.Read(13); - baseProcEntry.Chance = result.Read(14); - baseProcEntry.Cooldown = result.Read(15); - baseProcEntry.Charges = result.Read(16); + baseProcEntry.ProcFlags = new ProcFlagsInit(result.Read(7), result.Read(8), 2); + baseProcEntry.SpellTypeMask = (ProcFlagsSpellType)result.Read(9); + baseProcEntry.SpellPhaseMask = (ProcFlagsSpellPhase)result.Read(10); + baseProcEntry.HitMask = (ProcFlagsHit)result.Read(11); + baseProcEntry.AttributesMask = (ProcAttributes)result.Read(12); + baseProcEntry.DisableEffectsMask = result.Read(13); + baseProcEntry.ProcsPerMinute = result.Read(14); + baseProcEntry.Chance = result.Read(15); + baseProcEntry.Cooldown = result.Read(16); + baseProcEntry.Charges = result.Read(17); while (spellInfo != null) { @@ -1352,7 +1352,7 @@ namespace Game.Entities SpellProcEntry procEntry = baseProcEntry; // take defaults from dbcs - if (procEntry.ProcFlags == 0) + if (!procEntry.ProcFlags) procEntry.ProcFlags = spellInfo.ProcFlags; if (procEntry.Charges == 0) procEntry.Charges = spellInfo.ProcCharges; @@ -1376,21 +1376,21 @@ namespace Game.Entities Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has negative value in `ProcsPerMinute` field", spellInfo.Id); procEntry.ProcsPerMinute = 0; } - if (procEntry.ProcFlags == 0) + if (!procEntry.ProcFlags) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} doesn't have `ProcFlags` value defined, proc will not be triggered", spellInfo.Id); if (Convert.ToBoolean(procEntry.SpellTypeMask & ~ProcFlagsSpellType.MaskAll)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has wrong `SpellTypeMask` set: {1}", spellInfo.Id, procEntry.SpellTypeMask); - if (procEntry.SpellTypeMask != 0 && !Convert.ToBoolean(procEntry.ProcFlags & (ProcFlags.SpellMask))) + if (procEntry.SpellTypeMask != 0 && !procEntry.ProcFlags.HasFlag(ProcFlags.SpellMask)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has `SpellTypeMask` value defined, but it won't be used for defined `ProcFlags` value", spellInfo.Id); - if (procEntry.SpellPhaseMask == 0 && Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.ReqSpellPhaseMask)) + if (procEntry.SpellPhaseMask == 0 && procEntry.ProcFlags.HasFlag(ProcFlags.ReqSpellPhaseMask)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} doesn't have `SpellPhaseMask` value defined, but it's required for defined `ProcFlags` value, proc will not be triggered", spellInfo.Id); if (Convert.ToBoolean(procEntry.SpellPhaseMask & ~ProcFlagsSpellPhase.MaskAll)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has wrong `SpellPhaseMask` set: {1}", spellInfo.Id, procEntry.SpellPhaseMask); - if (procEntry.SpellPhaseMask != 0 && !Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.ReqSpellPhaseMask)) + if (procEntry.SpellPhaseMask != 0 && !procEntry.ProcFlags.HasFlag(ProcFlags.ReqSpellPhaseMask)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has `SpellPhaseMask` value defined, but it won't be used for defined `ProcFlags` value", spellInfo.Id); if (Convert.ToBoolean(procEntry.HitMask & ~ProcFlagsHit.MaskAll)) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has wrong `HitMask` set: {1}", spellInfo.Id, procEntry.HitMask); - if (procEntry.HitMask != 0 && !(Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.TakenHitMask) || (Convert.ToBoolean(procEntry.ProcFlags & ProcFlags.DoneHitMask) && (procEntry.SpellPhaseMask == 0 || Convert.ToBoolean(procEntry.SpellPhaseMask & (ProcFlagsSpellPhase.Hit | ProcFlagsSpellPhase.Finish)))))) + if (procEntry.HitMask != 0 && !(procEntry.ProcFlags.HasFlag(ProcFlags.TakenHitMask) || (procEntry.ProcFlags.HasFlag(ProcFlags.DoneHitMask) && (procEntry.SpellPhaseMask == 0 || Convert.ToBoolean(procEntry.SpellPhaseMask & (ProcFlagsSpellPhase.Hit | ProcFlagsSpellPhase.Finish)))))) Log.outError(LogFilter.Sql, "`spell_proc` table entry for spellId {0} has `HitMask` value defined, but it won't be used for defined `ProcFlags` and `SpellPhaseMask` values", spellInfo.Id); foreach (var spellEffectInfo in spellInfo.GetEffects()) if ((procEntry.DisableEffectsMask & (1u << (int)spellEffectInfo.EffectIndex)) != 0 && !spellEffectInfo.IsAura()) @@ -1448,7 +1448,7 @@ namespace Game.Entities continue; // Nothing to do if no flags set - if (spellInfo.ProcFlags == 0) + if (!spellInfo.ProcFlags) continue; bool addTriggerFlag = false; @@ -1476,7 +1476,7 @@ namespace Game.Entities // many proc auras with taken procFlag mask don't have attribute "can proc with triggered" // they should proc nevertheless (example mage armor spells with judgement) - if (!addTriggerFlag && spellInfo.ProcFlags.HasAnyFlag(ProcFlags.TakenHitMask)) + if (!addTriggerFlag && spellInfo.ProcFlags.HasFlag(ProcFlags.TakenHitMask)) { switch (auraName) { @@ -1496,7 +1496,7 @@ namespace Game.Entities { if (spellEffectInfo.IsAura()) { - Log.outError(LogFilter.Sql, $"Spell Id {spellInfo.Id} has DBC ProcFlags {spellInfo.ProcFlags}, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly."); + Log.outError(LogFilter.Sql, $"Spell Id {spellInfo.Id} has DBC ProcFlags 0x{spellInfo.ProcFlags[0]:X} 0x{spellInfo.ProcFlags[1]:X}, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly."); break; } } @@ -1552,7 +1552,7 @@ namespace Game.Entities procEntry.AttributesMask = 0; procEntry.DisableEffectsMask = nonProcMask; - if (spellInfo.ProcFlags.HasAnyFlag(ProcFlags.Kill)) + if (spellInfo.ProcFlags.HasFlag(ProcFlags.Kill)) procEntry.AttributesMask |= ProcAttributes.ReqExpOrHonor; if (addTriggerFlag) procEntry.AttributesMask |= ProcAttributes.TriggeredCanProc; @@ -2467,13 +2467,13 @@ namespace Game.Entities "ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex, " + //35 36 37 38 39 40 41 "RecoveryTime, CategoryRecoveryTime, StartRecoveryCategory, StartRecoveryTime, InterruptFlags, AuraInterruptFlags1, AuraInterruptFlags2, " + - //42 43 44 45 46 47 48 49 50 51 - "ChannelInterruptFlags1, ChannelInterruptFlags2, ProcFlags, ProcChance, ProcCharges, ProcCooldown, ProcBasePPM, MaxLevel, BaseLevel, SpellLevel, " + - //52 53 54 55 56 57 58 59 60 + //42 43 44 45 46 47 48 49 50 51 52 + "ChannelInterruptFlags1, ChannelInterruptFlags2, ProcFlags, ProcFlags2, ProcChance, ProcCharges, ProcCooldown, ProcBasePPM, MaxLevel, BaseLevel, SpellLevel, " + + //53 54 55 56 57 58 59 60 61 "DurationIndex, RangeIndex, Speed, LaunchDelay, StackAmount, EquippedItemClass, EquippedItemSubClassMask, EquippedItemInventoryTypeMask, ContentTuningId, " + - //61 62 63 64 65 66 67 68 69 70 + //62 63 64 65 66 67 68 69 70 71 "SpellName, ConeAngle, ConeWidth, MaxTargetLevel, MaxAffectedTargets, SpellFamilyName, SpellFamilyFlags1, SpellFamilyFlags2, SpellFamilyFlags3, SpellFamilyFlags4, " + - //71 72 73 74 75 + //72 73 74 75 76 "DmgClass, PreventionType, AreaGroupId, SchoolMask, ChargeCategoryId FROM serverside_spell"); if (!spellsResult.IsEmpty()) @@ -2488,7 +2488,7 @@ namespace Game.Entities continue; } - mServersideSpellNames.Add(new(spellId, spellsResult.Read(61))); + mServersideSpellNames.Add(new(spellId, spellsResult.Read(62))); SpellInfo spellInfo = new(mServersideSpellNames.Last().Name, difficulty, spellEffects[(spellId, difficulty)]); spellInfo.CategoryId = spellsResult.Read(2); @@ -2533,34 +2533,34 @@ namespace Game.Entities 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); - spellInfo.ProcCooldown = spellsResult.Read(47); - spellInfo.ProcBasePPM = spellsResult.Read(48); - spellInfo.MaxLevel = spellsResult.Read(49); - spellInfo.BaseLevel = spellsResult.Read(50); - spellInfo.SpellLevel = spellsResult.Read(51); - spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(spellsResult.Read(52)); - spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(spellsResult.Read(53)); - spellInfo.Speed = spellsResult.Read(54); - spellInfo.LaunchDelay = spellsResult.Read(55); - spellInfo.StackAmount = spellsResult.Read(56); - spellInfo.EquippedItemClass = (ItemClass)spellsResult.Read(57); - spellInfo.EquippedItemSubClassMask = spellsResult.Read(58); - spellInfo.EquippedItemInventoryTypeMask = spellsResult.Read(59); - spellInfo.ContentTuningId = spellsResult.Read(60); - spellInfo.ConeAngle = spellsResult.Read(62); - spellInfo.Width = spellsResult.Read(63); - spellInfo.MaxTargetLevel = spellsResult.Read(64); - spellInfo.MaxAffectedTargets = spellsResult.Read(65); - spellInfo.SpellFamilyName = (SpellFamilyNames)spellsResult.Read(66); - spellInfo.SpellFamilyFlags = new FlagArray128(spellsResult.Read(67), spellsResult.Read(68), spellsResult.Read(69), spellsResult.Read(70)); - spellInfo.DmgClass = (SpellDmgClass)spellsResult.Read(71); - spellInfo.PreventionType = (SpellPreventionType)spellsResult.Read(72); - spellInfo.RequiredAreasID = spellsResult.Read(73); - spellInfo.SchoolMask = (SpellSchoolMask)spellsResult.Read(74); - spellInfo.ChargeCategoryId = spellsResult.Read(75); + spellInfo.ProcFlags = new ProcFlagsInit(spellsResult.Read(44), spellsResult.Read(45)); + spellInfo.ProcChance = spellsResult.Read(46); + spellInfo.ProcCharges = spellsResult.Read(47); + spellInfo.ProcCooldown = spellsResult.Read(48); + spellInfo.ProcBasePPM = spellsResult.Read(49); + spellInfo.MaxLevel = spellsResult.Read(50); + spellInfo.BaseLevel = spellsResult.Read(51); + spellInfo.SpellLevel = spellsResult.Read(52); + spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(spellsResult.Read(53)); + spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(spellsResult.Read(54)); + spellInfo.Speed = spellsResult.Read(55); + spellInfo.LaunchDelay = spellsResult.Read(56); + spellInfo.StackAmount = spellsResult.Read(57); + spellInfo.EquippedItemClass = (ItemClass)spellsResult.Read(58); + spellInfo.EquippedItemSubClassMask = spellsResult.Read(59); + spellInfo.EquippedItemInventoryTypeMask = spellsResult.Read(60); + spellInfo.ContentTuningId = spellsResult.Read(61); + spellInfo.ConeAngle = spellsResult.Read(63); + spellInfo.Width = spellsResult.Read(64); + spellInfo.MaxTargetLevel = spellsResult.Read(65); + spellInfo.MaxAffectedTargets = spellsResult.Read(66); + spellInfo.SpellFamilyName = (SpellFamilyNames)spellsResult.Read(67); + spellInfo.SpellFamilyFlags = new FlagArray128(spellsResult.Read(68), spellsResult.Read(69), spellsResult.Read(70), spellsResult.Read(71)); + spellInfo.DmgClass = (SpellDmgClass)spellsResult.Read(72); + spellInfo.PreventionType = (SpellPreventionType)spellsResult.Read(73); + spellInfo.RequiredAreasID = spellsResult.Read(74); + spellInfo.SchoolMask = (SpellSchoolMask)spellsResult.Read(75); + spellInfo.ChargeCategoryId = spellsResult.Read(76); mSpellInfoMap.Add(spellId, spellInfo); @@ -4373,7 +4373,7 @@ namespace Game.Entities // disable proc for magnet auras, they're handled differently if (spellInfo.HasAura(AuraType.SpellMagnet)) - spellInfo.ProcFlags = 0; + spellInfo.ProcFlags = new ProcFlagsInit(); // due to the way spell system works, unit would change orientation in Spell::_cast if (spellInfo.HasAura(AuraType.ControlVehicle)) @@ -4826,7 +4826,7 @@ namespace Game.Entities public SpellSchoolMask SchoolMask { get; set; } // if nonzero - bitmask for matching proc condition based on spell's school public SpellFamilyNames SpellFamilyName { get; set; } // if nonzero - for matching proc condition based on candidate spell's SpellFamilyName public FlagArray128 SpellFamilyMask { get; set; } = new FlagArray128(); // if nonzero - bitmask for matching proc condition based on candidate spell's SpellFamilyFlags - public ProcFlags ProcFlags { get; set; } // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags + public ProcFlagsInit ProcFlags { get; set; } // if nonzero - owerwrite procFlags field for given Spell.dbc entry, bitmask for matching proc condition, see enum ProcFlags public ProcFlagsSpellType SpellTypeMask { get; set; } // if nonzero - bitmask for matching proc condition based on candidate spell's damage/heal effects, see enum ProcFlagsSpellType public ProcFlagsSpellPhase SpellPhaseMask { get; set; } // if nonzero - bitmask for matching phase of a spellcast on which proc occurs, see enum ProcFlagsSpellPhase public ProcFlagsHit HitMask { get; set; } // if nonzero - bitmask for matching proc condition based on hit result, see enum ProcFlagsHit diff --git a/Source/Scripts/Spells/Items.cs b/Source/Scripts/Spells/Items.cs index 8d550228e..b1b10e9dd 100644 --- a/Source/Scripts/Spells/Items.cs +++ b/Source/Scripts/Spells/Items.cs @@ -1498,7 +1498,7 @@ namespace Scripts.Spells.Items void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { - if (eventInfo.GetTypeMask().HasAnyFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass)) + if (eventInfo.GetTypeMask().HasFlag(ProcFlags.DoneRangedAutoAttack | ProcFlags.DoneSpellRangedDmgClass)) { // in that case, do not cast heal spell PreventDefaultAction();