Skip to main content

wowlab_engine_domain/dbc/semantics/
spell_attributes.rs

1use super::SemanticSupport;
2
3const COMBAT_LOG_METADATA_HANDLER: &str = "combat-log metadata has no simulation impact";
4const SPELLBOOK_METADATA_HANDLER: &str = "spellbook display metadata has no combat impact";
5
6/// Spell-level DBC attribute identities consumed by shared engine resolution.
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8#[repr(u16)]
9#[non_exhaustive]
10pub enum SpellAttributeKind {
11    RangedAbility = 1,
12    Ability = 4,
13    Passive = 6,
14    Hidden = 7,
15    DoNotLog = 8,
16    NotShapeshifted = 16,
17    RequiresStealth = 17,
18    DoNotSheath = 18,
19    CancelsAutoAttack = 20,
20    NoActiveDefense = 21,
21    NoCombat = 22,
22    AllowWhileMounted = 24,
23    AllowWhileSitting = 27,
24    NoImmunities = 29,
25    NoAuraCancel = 31,
26    Channeled = 34,
27    NoRedirection = 35,
28    AllowWhileStealthed = 37,
29    SelfChanneled = 38,
30    NoReflection = 39,
31    InitiatesAutoAttack = 41,
32    NoThreat = 42,
33    ImmunityPurgesEffect = 47,
34    NoAutoCastAi = 49,
35    DiscountPowerOnMiss = 59,
36    NoAuraIcon = 60,
37    IgnoreLineOfSight = 66,
38    IncludeAdvancedCombatLog = 72,
39    ChainFromCaster = 76,
40    AllowWhileNotShapeshifted = 83,
41    NotAnAction = 92,
42    CannotCrit = 93,
43    FoodAura = 95,
44    DotStackingRule = 103,
45    NotAProc = 105,
46    RequiresMainHand = 106,
47    SuppressCasterProcs = 112,
48    SuppressTargetProcs = 113,
49    AlwaysHit = 114,
50    InstantTargetProcs = 115,
51    AllowAuraWhileDead = 116,
52    RequiresOffHand = 120,
53    TreatAsPeriodic = 121,
54    CanProcFromProcs = 122,
55    DoNotDisplayRange = 126,
56    NoCastLog = 128,
57    CannotBeStolen = 134,
58    AllowCastWhileCasting = 135,
59    DisableTargetMultiplier = 136,
60    NotInSpellbook = 143,
61    AllowProcWhileSitting = 147,
62    AuraNeverBounces = 148,
63    AllowEnteringArena = 149,
64    SuppressWeaponProcs = 151,
65    AllowWhileStunned = 163,
66    TickOnApplication = 169,
67    SpellHasteAffectsPeriodic = 173,
68    TreatAsAreaEffect = 175,
69    AllowWhileFleeing = 177,
70    AllowWhileConfused = 178,
71    RequiresLineOfSight = 186,
72    IgnoreTimeRate = 196,
73    NoAuraLog = 202,
74    AllowWhileRidingVehicle = 204,
75    TapsImmediately = 215,
76    VehicleImmunityCategory = 218,
77    IgnoreHealingModifiers = 219,
78    DoNotAutoSelectTarget = 220,
79    DisablePlayerMultiplier = 221,
80    AllowSpellReflection = 224,
81    DisableAuraWhileDead = 226,
82    CannotDodge = 247,
83    CannotParry = 248,
84    CannotMiss = 249,
85    CanProcFromSuppressedTarget = 254,
86    CannotBlock = 256,
87    PeriodicCanCrit = 265,
88    AuraPointsOnClient = 268,
89    NotInSpellbookUntilLearned = 269,
90    HasteAffectsDuration = 273,
91    RequiresEquippedArmorType = 276,
92    MeleeHasteAffectsPeriodic = 278,
93    MasteryAffectsPoints = 285,
94    DisplayLargeAuraIcon = 286,
95    FixedTravelTime = 292,
96    AllowCastWhileChanneling = 308,
97    SpellcastOverrideInSpellbook = 310,
98    DisablePlayerHealingMultiplier = 312,
99    DisableTargetPositiveMultiplier = 321,
100    TargetSpecificCooldown = 330,
101    ResetCooldownOnEncounterEnd = 333,
102    RollingPeriodic = 334,
103    UpdatePassivesOnApplyRemove = 344,
104    EnforceFacingPrimaryTargetOnly = 351,
105    ScalesWithCastingItemLevel = 354,
106    DoNotLogOnLearn = 355,
107    EnableProcsFromSuppressed = 384,
108    CanProcFromSuppressed = 385,
109    IgnoreCastingDisabled = 393,
110    OnlyProcFromClassAbilities = 415,
111    AllowClassAbilityProcs = 416,
112    NameplatePersonalAura = 423,
113    NameplateEnemyDebuff = 426,
114    DoNotConsumeAuraStackOnProc = 428,
115    PeriodicRefreshExtendsDuration = 436,
116    DoNotDisplayCastTime = 441,
117    AlwaysAllowNegativeHealingModifiers = 442,
118    PreventJumpingDuringPrecast = 448,
119    HidePassiveFromTooltip = 451,
120    AsynchronousStackingBuff = 490,
121    ImportantSpell = 491,
122    ExternalDefensive = 499,
123    BigDefensive = 512,
124}
125
126impl SpellAttributeKind {
127    #[must_use]
128    pub const fn block(self) -> usize {
129        self as usize / i32::BITS as usize
130    }
131
132    #[must_use]
133    pub const fn mask(self) -> i32 {
134        1_i32.wrapping_shl(self as u32 % i32::BITS)
135    }
136}
137
138/// One registered spell-level DBC attribute.
139#[derive(Clone, Copy, Debug, Eq, PartialEq)]
140pub struct SpellAttributeSemantic {
141    pub kind: SpellAttributeKind,
142    pub name: &'static str,
143    pub support: SemanticSupport,
144    pub handler: &'static str,
145}
146
147const fn spell_attribute(
148    kind: SpellAttributeKind,
149    name: &'static str,
150    support: SemanticSupport,
151    handler: &'static str,
152) -> SpellAttributeSemantic {
153    SpellAttributeSemantic {
154        kind,
155        name,
156        support,
157        handler,
158    }
159}
160
161/// Canonical registry of spell attributes interpreted by the engine.
162#[rustfmt::skip]
163pub const SPELL_ATTRIBUTE_SEMANTICS: &[SpellAttributeSemantic] = &[
164    spell_attribute(SpellAttributeKind::RangedAbility, "Uses Ranged Slot", SemanticSupport::Generic, "base GCD haste classification combined with passive auras 320 and 417"),
165    spell_attribute(SpellAttributeKind::Ability, "Is Ability", SemanticSupport::Generic, "base GCD haste classification combined with passive auras 320 and 417"),
166    spell_attribute(SpellAttributeKind::Passive, "Passive", SemanticSupport::Generic, "passive spell classification"),
167    spell_attribute(SpellAttributeKind::Hidden, "Do Not Display", SemanticSupport::Ignored, "display metadata has no combat impact"),
168    spell_attribute(SpellAttributeKind::DoNotLog, "Do Not Log", SemanticSupport::Ignored, COMBAT_LOG_METADATA_HANDLER),
169    spell_attribute(SpellAttributeKind::NotShapeshifted, "Not Shapeshifted", SemanticSupport::Generic, "shared player form cast gating"),
170    spell_attribute(SpellAttributeKind::RequiresStealth, "Requires Stealth", SemanticSupport::Generic, "shared cast gating against player stealth state"),
171    spell_attribute(SpellAttributeKind::DoNotSheath, "Do Not Sheath", SemanticSupport::Ignored, "animation metadata has no combat impact"),
172    spell_attribute(SpellAttributeKind::CancelsAutoAttack, "Cancels Auto Attack", SemanticSupport::Generic, "action-driven auto-attack cancellation"),
173    spell_attribute(SpellAttributeKind::NoActiveDefense, "No Active Defense", SemanticSupport::Unsupported, "active defense and attack avoidance are not modelled"),
174    spell_attribute(SpellAttributeKind::NoCombat, "Does Not Enter Combat", SemanticSupport::Unsupported, "per-action combat-state transitions are not modelled"),
175    spell_attribute(SpellAttributeKind::AllowWhileMounted, "Allow While Mounted", SemanticSupport::Unsupported, "mounted actor state and cast gating are not modelled"),
176    spell_attribute(SpellAttributeKind::AllowWhileSitting, "Allow While Sitting", SemanticSupport::Unsupported, "sitting actor state and cast gating are not modelled"),
177    spell_attribute(SpellAttributeKind::NoImmunities, "No Immunities", SemanticSupport::Unsupported, "spell-level bypass of active school and mechanic immunities is not modelled"),
178    spell_attribute(SpellAttributeKind::NoAuraCancel, "No Aura Cancel", SemanticSupport::Unsupported, "aura cancellation eligibility is not modelled"),
179    spell_attribute(SpellAttributeKind::Channeled, "Is Channelled", SemanticSupport::Generic, "channel cast-time resolution"),
180    spell_attribute(SpellAttributeKind::NoRedirection, "No Redirection", SemanticSupport::Unsupported, "spell-level bypass of active split and share damage is not modelled"),
181    spell_attribute(SpellAttributeKind::AllowWhileStealthed, "Allow While Stealthed", SemanticSupport::Generic, "stealth-break resolution"),
182    spell_attribute(SpellAttributeKind::SelfChanneled, "Is Self Channelled", SemanticSupport::Generic, "channel cast-time resolution"),
183    spell_attribute(SpellAttributeKind::NoReflection, "No Reflection", SemanticSupport::Generic, "bypasses shared target reflection and deflection resolution"),
184    spell_attribute(SpellAttributeKind::InitiatesAutoAttack, "Initiates Auto Attack", SemanticSupport::Generic, "action-driven auto-attack start scheduling"),
185    spell_attribute(SpellAttributeKind::NoThreat, "No Threat", SemanticSupport::Unsupported, "per-action threat generation is not modelled"),
186    spell_attribute(SpellAttributeKind::ImmunityPurgesEffect, "Immunity Purges Effect", SemanticSupport::Unsupported, "immunity-driven aura purging is not modelled"),
187    spell_attribute(SpellAttributeKind::NoAutoCastAi, "No AutoCast (AI)", SemanticSupport::Unsupported, "pet and creature autocast eligibility is not modelled"),
188    spell_attribute(SpellAttributeKind::DiscountPowerOnMiss, "Discount Power On Miss", SemanticSupport::Unsupported, "miss outcomes and cost refunds are not modelled"),
189    spell_attribute(SpellAttributeKind::NoAuraIcon, "No Aura Icon", SemanticSupport::Ignored, "display metadata has no combat impact"),
190    spell_attribute(SpellAttributeKind::IgnoreLineOfSight, "Ignore Line of Sight", SemanticSupport::Generic, "shared hostile range and line-of-sight cast gating"),
191    spell_attribute(SpellAttributeKind::IncludeAdvancedCombatLog, "Include In Advanced Combat Log", SemanticSupport::Ignored, COMBAT_LOG_METADATA_HANDLER),
192    spell_attribute(SpellAttributeKind::ChainFromCaster, "Chain From Caster", SemanticSupport::Generic, "shared chain targeting keeps every additional target anchored on the caster"),
193    spell_attribute(SpellAttributeKind::AllowWhileNotShapeshifted, "Allow While Not Shapeshifted", SemanticSupport::Generic, "caster-form exception to shared stance-mask gating"),
194    spell_attribute(SpellAttributeKind::NotAnAction, "Not an Action", SemanticSupport::Unsupported, "action classification is not consumed by cast or proc resolution"),
195    spell_attribute(SpellAttributeKind::CannotCrit, "Can't Crit", SemanticSupport::Generic, "direct and triggered damage critical-hit resolution"),
196    spell_attribute(SpellAttributeKind::FoodAura, "Food Aura", SemanticSupport::Unsupported, "item-cast retention semantics are not modelled"),
197    spell_attribute(SpellAttributeKind::DotStackingRule, "DoT Stacking Rule", SemanticSupport::Ignored, "legacy flag is not consumed by current SimC"),
198    spell_attribute(SpellAttributeKind::NotAProc, "Not a Proc", SemanticSupport::Partial, "proc-source provenance"),
199    spell_attribute(SpellAttributeKind::RequiresMainHand, "Requires Main-Hand Weapon", SemanticSupport::Generic, "shared equipped-weapon cast gating"),
200    spell_attribute(SpellAttributeKind::SuppressCasterProcs, "Suppress Caster Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
201    spell_attribute(SpellAttributeKind::SuppressTargetProcs, "Suppress Target Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
202    spell_attribute(SpellAttributeKind::AlwaysHit, "Always Hit", SemanticSupport::Generic, "attack-table miss override"),
203    spell_attribute(SpellAttributeKind::InstantTargetProcs, "Instant Target Procs", SemanticSupport::Unsupported, "target-proc timing is not modelled"),
204    spell_attribute(SpellAttributeKind::AllowAuraWhileDead, "Allow Aura While Dead", SemanticSupport::Unsupported, "dead actor state and aura eligibility are not modelled"),
205    spell_attribute(SpellAttributeKind::RequiresOffHand, "Requires Off-Hand Weapon", SemanticSupport::Generic, "shared equipped-weapon cast gating and off-hand AP source"),
206    spell_attribute(SpellAttributeKind::TreatAsPeriodic, "Treat As Periodic", SemanticSupport::Generic, "shared damage flags route the impact through periodic modifiers"),
207    spell_attribute(SpellAttributeKind::CanProcFromProcs, "Can Proc From Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
208    spell_attribute(SpellAttributeKind::DoNotDisplayRange, "Do Not Display Range", SemanticSupport::Ignored, "display metadata has no combat impact"),
209    spell_attribute(SpellAttributeKind::NoCastLog, "No Cast Log", SemanticSupport::Ignored, COMBAT_LOG_METADATA_HANDLER),
210    spell_attribute(SpellAttributeKind::CannotBeStolen, "Cannot Be Stolen", SemanticSupport::Unsupported, "spellsteal does not yet exclude auras carrying this attribute"),
211    spell_attribute(SpellAttributeKind::AllowCastWhileCasting, "Allow Cast While Casting", SemanticSupport::Generic, "cast concurrency gating"),
212    spell_attribute(SpellAttributeKind::DisableTargetMultiplier, "Disable Target Multipliers", SemanticSupport::Generic, "damage multiplier routing"),
213    spell_attribute(SpellAttributeKind::NotInSpellbook, "Not In Spellbook", SemanticSupport::Ignored, SPELLBOOK_METADATA_HANDLER),
214    spell_attribute(SpellAttributeKind::AllowProcWhileSitting, "Allow Proc While Sitting", SemanticSupport::Unsupported, "sitting actor state and proc eligibility are not modelled"),
215    spell_attribute(SpellAttributeKind::AuraNeverBounces, "Aura Never Bounces", SemanticSupport::Unsupported, "multi-target aura bouncing is not modelled"),
216    spell_attribute(SpellAttributeKind::AllowEnteringArena, "Allow Entering Arena", SemanticSupport::Unsupported, "arena state and aura persistence are not modelled"),
217    spell_attribute(SpellAttributeKind::SuppressWeaponProcs, "Suppress Weapon Procs", SemanticSupport::Partial, "proc-source provenance"),
218    spell_attribute(SpellAttributeKind::AllowWhileStunned, "Allow While Stunned", SemanticSupport::Unsupported, "this cast exception is not applied to the player stun gate"),
219    spell_attribute(SpellAttributeKind::TickOnApplication, "Extra Initial Period", SemanticSupport::Generic, "periodic scheduling"),
220    spell_attribute(SpellAttributeKind::SpellHasteAffectsPeriodic, "Spell Haste Affects Periodic", SemanticSupport::Generic, "periodic cadence resolution"),
221    spell_attribute(SpellAttributeKind::TreatAsAreaEffect, "Treat as Area Effect", SemanticSupport::Generic, "shared AoE target-count and damage dispatch"),
222    spell_attribute(SpellAttributeKind::AllowWhileFleeing, "Allow While Fleeing", SemanticSupport::Unsupported, "this cast exception is not applied to the player fear gate"),
223    spell_attribute(SpellAttributeKind::AllowWhileConfused, "Allow While Confused", SemanticSupport::Unsupported, "this cast exception is not applied to a confusion gate"),
224    spell_attribute(SpellAttributeKind::RequiresLineOfSight, "Requires Line of Sight", SemanticSupport::Generic, "default hostile line-of-sight target gating"),
225    spell_attribute(SpellAttributeKind::IgnoreTimeRate, "Ignore Time Rate", SemanticSupport::Unsupported, "per-aura opt-out from active time-rate modifiers is not modelled"),
226    spell_attribute(SpellAttributeKind::NoAuraLog, "No Aura Log", SemanticSupport::Ignored, COMBAT_LOG_METADATA_HANDLER),
227    spell_attribute(SpellAttributeKind::AllowWhileRidingVehicle, "Allow While Riding Vehicle", SemanticSupport::Unsupported, "vehicle actor state and cast gating are not modelled"),
228    spell_attribute(SpellAttributeKind::TapsImmediately, "Taps Immediately", SemanticSupport::Unsupported, "target tapping and ownership are not modelled"),
229    spell_attribute(SpellAttributeKind::VehicleImmunityCategory, "Vehicle Immunity Category", SemanticSupport::Unsupported, "vehicle immunity categories are not modelled"),
230    spell_attribute(SpellAttributeKind::IgnoreHealingModifiers, "Ignore Healing Modifiers", SemanticSupport::Unsupported, "spell-level bypass of the shared healing modifiers is not modelled"),
231    spell_attribute(SpellAttributeKind::DoNotAutoSelectTarget, "Do Not Auto Select Target with Initiates Combat", SemanticSupport::Unsupported, "automatic target selection across actors is not modelled"),
232    spell_attribute(SpellAttributeKind::DisablePlayerMultiplier, "Disable Player Multipliers", SemanticSupport::Generic, "damage multiplier routing"),
233    spell_attribute(SpellAttributeKind::AllowSpellReflection, "Allow Spell Reflection", SemanticSupport::Generic, "explicitly permits reflection independent of magic ability classification"),
234    spell_attribute(SpellAttributeKind::DisableAuraWhileDead, "Disable Aura While Dead", SemanticSupport::Unsupported, "dead actor state and aura disabling are not modelled"),
235    spell_attribute(SpellAttributeKind::CannotDodge, "Cannot Be Dodged", SemanticSupport::Generic, "attack-table dodge override"),
236    spell_attribute(SpellAttributeKind::CannotParry, "Cannot Be Parried", SemanticSupport::Generic, "attack-table parry override"),
237    spell_attribute(SpellAttributeKind::CannotMiss, "Cannot Miss", SemanticSupport::Generic, "attack-table miss override"),
238    spell_attribute(SpellAttributeKind::CanProcFromSuppressedTarget, "Can Proc From Suppressed Target Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
239    spell_attribute(SpellAttributeKind::CannotBlock, "Cannot Be Blocked", SemanticSupport::Generic, "attack-table block override"),
240    spell_attribute(SpellAttributeKind::PeriodicCanCrit, "Periodic Can Crit", SemanticSupport::Generic, "periodic critical-hit resolution"),
241    spell_attribute(SpellAttributeKind::AuraPointsOnClient, "Aura Points On Client", SemanticSupport::Ignored, "client aura-display metadata has no combat impact"),
242    spell_attribute(SpellAttributeKind::NotInSpellbookUntilLearned, "Not In Spellbook Until Learned", SemanticSupport::Ignored, SPELLBOOK_METADATA_HANDLER),
243    spell_attribute(SpellAttributeKind::HasteAffectsDuration, "Haste Affects Duration", SemanticSupport::Generic, "aura duration resolution"),
244    spell_attribute(SpellAttributeKind::RequiresEquippedArmorType, "Requires Equipped Armor Type", SemanticSupport::Unsupported, "equipment cast gating"),
245    spell_attribute(SpellAttributeKind::MeleeHasteAffectsPeriodic, "Melee Haste Affects Periodic", SemanticSupport::Generic, "periodic cadence resolution"),
246    spell_attribute(SpellAttributeKind::MasteryAffectsPoints, "Mastery Affects Points", SemanticSupport::Generic, "live mastery effect-point resolution"),
247    spell_attribute(SpellAttributeKind::DisplayLargeAuraIcon, "Display Large Aura Icon On Unit Frames", SemanticSupport::Ignored, "display metadata has no combat impact"),
248    spell_attribute(SpellAttributeKind::FixedTravelTime, "Missile Speed is Delay", SemanticSupport::Generic, "shared spatial travel-time resolution"),
249    spell_attribute(SpellAttributeKind::AllowCastWhileChanneling, "Allow Cast While Channeling", SemanticSupport::Generic, "cast concurrency gating"),
250    spell_attribute(SpellAttributeKind::SpellcastOverrideInSpellbook, "Spellcast Override In Spellbook", SemanticSupport::Ignored, SPELLBOOK_METADATA_HANDLER),
251    spell_attribute(SpellAttributeKind::DisablePlayerHealingMultiplier, "Disable Player Healing Multipliers", SemanticSupport::Unsupported, "spell-level suppression of source healing multipliers is not modelled"),
252    spell_attribute(SpellAttributeKind::DisableTargetPositiveMultiplier, "Disable Target Positive Multipliers", SemanticSupport::Generic, "damage multiplier routing"),
253    spell_attribute(SpellAttributeKind::TargetSpecificCooldown, "Target-Specific Cooldown", SemanticSupport::Unsupported, "per-target cooldown state is not modelled"),
254    spell_attribute(SpellAttributeKind::ResetCooldownOnEncounterEnd, "Reset Cooldown Upon Ending Encounter", SemanticSupport::Ignored, "single-encounter iteration reset clears every cooldown"),
255    spell_attribute(SpellAttributeKind::RollingPeriodic, "Rolling Periodic", SemanticSupport::Generic, "rolling periodic damage pool"),
256    spell_attribute(SpellAttributeKind::UpdatePassivesOnApplyRemove, "Update Passives On Apply/Remove", SemanticSupport::Generic, "attribute-marked passives remain active auras and recompute through apply/remove"),
257    spell_attribute(SpellAttributeKind::EnforceFacingPrimaryTargetOnly, "Enforce Facing on Primary Target Only", SemanticSupport::Generic, "caster cone and line geometry faces the explicit primary target"),
258    spell_attribute(SpellAttributeKind::ScalesWithCastingItemLevel, "Scales with Casting Item's Level", SemanticSupport::Generic, "consumable item-level scaling"),
259    spell_attribute(SpellAttributeKind::DoNotLogOnLearn, "Do Not Log On Learn", SemanticSupport::Ignored, COMBAT_LOG_METADATA_HANDLER),
260    spell_attribute(SpellAttributeKind::EnableProcsFromSuppressed, "Enable Procs from Suppressed Caster Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
261    spell_attribute(SpellAttributeKind::CanProcFromSuppressed, "Can Proc from Suppressed Caster Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
262    spell_attribute(SpellAttributeKind::IgnoreCastingDisabled, "Ignore Casting Disabled", SemanticSupport::Generic, "aura 263 casting exception"),
263    spell_attribute(SpellAttributeKind::OnlyProcFromClassAbilities, "Only Proc From Class Abilities", SemanticSupport::Generic, "central paired proc provenance policy"),
264    spell_attribute(SpellAttributeKind::AllowClassAbilityProcs, "Allow Class Ability Procs", SemanticSupport::Generic, "central paired proc provenance policy"),
265    spell_attribute(SpellAttributeKind::NameplatePersonalAura, "Nameplate Personal Buffs/Debuffs", SemanticSupport::Ignored, "nameplate display metadata has no combat impact"),
266    spell_attribute(SpellAttributeKind::NameplateEnemyDebuff, "Nameplate Enemy Debuffs", SemanticSupport::Ignored, "nameplate display metadata has no combat impact"),
267    spell_attribute(SpellAttributeKind::DoNotConsumeAuraStackOnProc, "Do Not Consume Aura Stack On Proc", SemanticSupport::Unsupported, "attribute-level exception to stacks-as-proc-charges consumption is not modelled"),
268    spell_attribute(SpellAttributeKind::PeriodicRefreshExtendsDuration, "Periodic Refresh Extends Duration", SemanticSupport::Generic, "pandemic refresh carryover"),
269    spell_attribute(SpellAttributeKind::DoNotDisplayCastTime, "Do Not Display Cast Time", SemanticSupport::Ignored, "cast-bar display metadata has no combat impact"),
270    spell_attribute(SpellAttributeKind::AlwaysAllowNegativeHealingModifiers, "Always Allow Negative Healing Percent Modifiers", SemanticSupport::Unsupported, "negative healing modifier rules are not modelled"),
271    spell_attribute(SpellAttributeKind::PreventJumpingDuringPrecast, "Prevent Jumping During Precast", SemanticSupport::Unsupported, "jump state and precast movement locks are not modelled"),
272    spell_attribute(SpellAttributeKind::HidePassiveFromTooltip, "Hide Passive From Tooltip", SemanticSupport::Ignored, "tooltip display metadata has no combat impact"),
273    spell_attribute(SpellAttributeKind::AsynchronousStackingBuff, "Asynchronous Stacking Buff", SemanticSupport::Generic, "independent aura-stack expiration"),
274    spell_attribute(SpellAttributeKind::ImportantSpell, "Important Spell", SemanticSupport::Ignored, "reporting metadata has no combat impact"),
275    spell_attribute(SpellAttributeKind::ExternalDefensive, "External Defensive", SemanticSupport::Unsupported, "defensive action classification is not modelled"),
276    spell_attribute(SpellAttributeKind::BigDefensive, "Big Defensive", SemanticSupport::Unsupported, "defensive action classification is not modelled"),
277];
278
279/// Registry lookup for a raw spell-attribute id.
280#[must_use]
281pub fn spell_attribute_semantic(raw: i32) -> Option<&'static SpellAttributeSemantic> {
282    SPELL_ATTRIBUTE_SEMANTICS
283        .iter()
284        .find(|entry| entry.kind as i32 == raw)
285}
286
287/// Whether an attribute-block slice contains `expected`.
288#[must_use]
289pub fn spell_attribute_is(attributes: &[i32], expected: SpellAttributeKind) -> bool {
290    attributes
291        .get(expected.block())
292        .is_some_and(|value| value & expected.mask() != 0)
293}
294
295/// Whether an attribute-block slice contains any requested identity.
296#[must_use]
297pub fn spell_attribute_is_any(attributes: &[i32], expected: &[SpellAttributeKind]) -> bool {
298    expected
299        .iter()
300        .any(|kind| spell_attribute_is(attributes, *kind))
301}