Skip to main content

wowlab_engine_domain/dbc/semantics/
coverage.rs

1use wowlab_types::data::SpellEffect;
2
3use super::{
4    AuraSubtypeSemantic, ModifierPropertySemantic, SemanticSupport, SpellEffectKind,
5    SpellEffectSemantic, aura_subtype_semantic, modifier_combination_supported,
6    modifier_property_semantic, spell_effect_semantic,
7};
8
9/// Conformance result for one DBC spell effect.
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11#[non_exhaustive]
12pub enum EffectSemanticCoverage {
13    Supported {
14        effect: &'static SpellEffectSemantic,
15        aura: Option<&'static AuraSubtypeSemantic>,
16        property: Option<&'static ModifierPropertySemantic>,
17    },
18    Partial {
19        effect: &'static SpellEffectSemantic,
20        aura: Option<&'static AuraSubtypeSemantic>,
21        property: Option<&'static ModifierPropertySemantic>,
22    },
23    ContentRequired {
24        effect: &'static SpellEffectSemantic,
25        aura: Option<&'static AuraSubtypeSemantic>,
26        property: Option<&'static ModifierPropertySemantic>,
27    },
28    Ignored {
29        effect: &'static SpellEffectSemantic,
30        aura: Option<&'static AuraSubtypeSemantic>,
31        property: Option<&'static ModifierPropertySemantic>,
32    },
33    UnsupportedRegistered {
34        effect: &'static SpellEffectSemantic,
35        aura: Option<&'static AuraSubtypeSemantic>,
36        property: Option<&'static ModifierPropertySemantic>,
37    },
38    UnsupportedEffectType(i32),
39    UnsupportedAuraSubtype(i32),
40    UnsupportedModifierProperty(i32),
41    UnsupportedModifierCombination {
42        aura: &'static AuraSubtypeSemantic,
43        property: &'static ModifierPropertySemantic,
44    },
45}
46
47/// Classify one DBC effect against the engine's canonical semantic registry.
48#[must_use]
49pub fn effect_semantic_coverage(effect: &SpellEffect) -> EffectSemanticCoverage {
50    let Some(effect_semantic) = spell_effect_semantic(effect.effect) else {
51        return EffectSemanticCoverage::UnsupportedEffectType(effect.effect);
52    };
53
54    if !matches!(
55        effect_semantic.kind,
56        SpellEffectKind::ApplyAura | SpellEffectKind::ApplyPartyAura
57    ) {
58        return coverage_for_support(effect_semantic, None, None, effect_semantic.support);
59    }
60
61    let Some(aura) = aura_subtype_semantic(effect.aura) else {
62        return EffectSemanticCoverage::UnsupportedAuraSubtype(effect.aura);
63    };
64    let property = if aura.modifier.is_some() {
65        let Some(property) = modifier_property_semantic(effect.misc_value_0) else {
66            return EffectSemanticCoverage::UnsupportedModifierProperty(effect.misc_value_0);
67        };
68
69        if !modifier_combination_supported(aura, property) {
70            return EffectSemanticCoverage::UnsupportedModifierCombination { aura, property };
71        }
72
73        Some(property)
74    } else {
75        None
76    };
77    let support = property.map_or(aura.support, |property| {
78        combine_semantic_support(aura.support, property.support)
79    });
80
81    coverage_for_support(effect_semantic, Some(aura), property, support)
82}
83
84const fn coverage_for_support(
85    effect: &'static SpellEffectSemantic,
86    aura: Option<&'static AuraSubtypeSemantic>,
87    property: Option<&'static ModifierPropertySemantic>,
88    support: SemanticSupport,
89) -> EffectSemanticCoverage {
90    match support {
91        SemanticSupport::Generic => EffectSemanticCoverage::Supported {
92            effect,
93            aura,
94            property,
95        },
96        SemanticSupport::Partial => EffectSemanticCoverage::Partial {
97            effect,
98            aura,
99            property,
100        },
101        SemanticSupport::ContentRequired => EffectSemanticCoverage::ContentRequired {
102            effect,
103            aura,
104            property,
105        },
106        SemanticSupport::Ignored => EffectSemanticCoverage::Ignored {
107            effect,
108            aura,
109            property,
110        },
111        SemanticSupport::Unsupported => EffectSemanticCoverage::UnsupportedRegistered {
112            effect,
113            aura,
114            property,
115        },
116    }
117}
118
119const fn combine_semantic_support(
120    left: SemanticSupport,
121    right: SemanticSupport,
122) -> SemanticSupport {
123    use SemanticSupport::{ContentRequired, Generic, Ignored, Partial, Unsupported};
124
125    match (left, right) {
126        (Unsupported, _) | (_, Unsupported) => Unsupported,
127        (ContentRequired, _) | (_, ContentRequired) => ContentRequired,
128        (Ignored, _) | (_, Ignored) => Ignored,
129        (Partial, _) | (_, Partial) => Partial,
130        (Generic, Generic) => Generic,
131    }
132}