wowlab_engine_domain/dbc/semantics/
mod.rs1use wowlab_types::data::SpellEffect;
4
5use self::{
6 modifier_property_is as raw_modifier_property_is,
7 modifier_property_is_any as raw_modifier_property_is_any,
8};
9
10mod aura_interrupt_flags;
11mod aura_states;
12mod aura_subtypes;
13mod control;
14mod coverage;
15mod defense_types;
16mod difficulty;
17mod enchantments;
18mod implicit_targets;
19mod items;
20mod loot;
21mod mechanics;
22mod modifier_properties;
23mod power_types;
24mod proc_attributes;
25mod proc_types;
26mod ratings;
27mod resolved_game_data;
28mod schools;
29mod spell_attributes;
30mod spell_cast_target_flags;
31mod spell_effect_attributes;
32mod spell_effect_targets;
33mod spell_effects;
34mod spell_interrupt_flags;
35mod spell_targets;
36mod stances;
37mod stat_masks;
38mod traits;
39
40pub use aura_interrupt_flags::SpellAuraInterruptFlags;
41pub use aura_states::AuraState;
42pub use control::{
43 CrowdControlKind, CrowdControlSemantic, DiminishingGroup, crowd_control_semantic,
44};
45pub use coverage::{EffectSemanticCoverage, effect_semantic_coverage};
46pub use defense_types::DefenseType;
47pub use difficulty::DifficultyId;
48pub use implicit_targets::{
49 IMPLICIT_TARGET_SEMANTICS, ImplicitTargetCheck, ImplicitTargetDirection, ImplicitTargetObject,
50 ImplicitTargetReference, ImplicitTargetSelection, ImplicitTargetSelector,
51 ImplicitTargetSemantic, implicit_target_semantic,
52};
53pub use items::{
54 ArmorSubclass, ConsumableSubclass, GemSubclass, InventoryType, ItemClass, ItemEffectTrigger,
55 WeaponSubclass, item_matches_consumable_query, resolve_item_budget,
56};
57pub use loot::{
58 DungeonDifficultyFlags, ItemBonusListGroupEntryFlags, ItemBonusType, ItemContext,
59 RaidDifficultyFlags,
60};
61pub use mechanics::{DispelType, Mechanic, MechanicMask};
62pub use power_types::PowerType;
63pub use proc_attributes::{
64 CONSUMED_PROC_ATTRIBUTES, PROC_ATTRIBUTE_SEMANTICS, ProcAttributeKind, ProcAttributeSemantic,
65 ProcAttributes, proc_attribute_semantic,
66};
67pub use proc_types::ProcTypeMask;
68pub use schools::SpellSchoolMask;
69pub use spell_cast_target_flags::{
70 SPELL_CAST_TARGET_FLAG_SEMANTICS, SpellCastTargetFlagSemantic, SpellCastTargetFlags,
71 spell_cast_target_flag_semantic,
72};
73pub use spell_effect_attributes::SpellEffectAttributes;
74pub use spell_effect_targets::{
75 SpellEffectImplicitTarget, SpellEffectTargetSemantic, spell_effect_target_semantic,
76};
77pub use spell_interrupt_flags::SpellInterruptFlags;
78pub use spell_targets::{SpellTargetMasks, spell_target_masks};
79pub use stat_masks::{AttributeMask, RatingMultiplierMask};
80
81#[derive(Clone, Copy, Debug, Eq, PartialEq)]
83#[non_exhaustive]
84pub enum SemanticSupport {
85 Generic,
87 Partial,
89 ContentRequired,
91 Ignored,
93 Unsupported,
95}
96
97pub use spell_attributes::{
98 SPELL_ATTRIBUTE_SEMANTICS, SpellAttributeKind, SpellAttributeSemantic, spell_attribute_is,
99 spell_attribute_is_any, spell_attribute_semantic,
100};
101pub use spell_effects::{
102 SPELL_EFFECT_SEMANTICS, SpellEffectKind, SpellEffectSemantic, spell_effect_semantic,
103};
104#[derive(Clone, Copy, Debug, Eq, PartialEq)]
106#[non_exhaustive]
107pub enum ModifierOperation {
108 Flat,
109 Percent,
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
114#[non_exhaustive]
115pub enum ModifierFilter {
116 ClassFamilyMask,
117 Label,
118}
119
120pub use aura_subtypes::{
121 AURA_SUBTYPE_SEMANTICS, AuraSubtypeKind, AuraSubtypeSemantic, PetStatKind, StatModifierKind,
122 is_primary_stat_misc,
123};
124pub use enchantments::{
125 EnchantEffectKind, EnchantTriggerSemantic, enchant_effect_is, enchant_effect_kind,
126 enchant_trigger_semantic, rppm_crit_scaled, rppm_haste_scaled,
127};
128pub use modifier_properties::{
129 MODIFIER_PROPERTY_SEMANTICS, ModifierOperations, ModifierPropertyKind,
130 ModifierPropertySemantic, modifier_property_for_effect,
131};
132pub use ratings::{CombatRating, CombatRatingMask};
133pub use resolved_game_data::ResolvedGameDataSemanticExt;
134pub use stances::{ShapeshiftForm, SpellShapeshiftFormFlags, stance_mask_allows};
135pub use traits::{
136 TraitConditionType, TraitCurrencyFlags, TraitEffectOperation, TraitNodeType, TraitTreeIndex,
137};
138macro_rules! semantic_registry {
139 (
140 kind = $kind_fn:ident,
141 is = $is_fn:ident,
142 is_any = $is_any_fn:ident,
143 raw = $raw_fn:ident,
144 semantic = $semantic_fn:ident,
145 registry = $registry:ident,
146 type = $kind_ty:ty
147 ) => {
148 #[must_use]
149 pub fn $kind_fn(raw: i32) -> Option<$kind_ty> {
150 $semantic_fn(raw).map(|semantic| semantic.kind)
151 }
152
153 #[must_use]
154 pub fn $is_fn(raw: i32, expected: $kind_ty) -> bool {
155 raw == expected as i32
156 }
157
158 #[must_use]
159 pub fn $is_any_fn(raw: i32, expected: &[$kind_ty]) -> bool {
160 expected.iter().any(|kind| raw == *kind as i32)
161 }
162
163 #[must_use]
164 pub fn $raw_fn(kind: $kind_ty) -> i32 {
165 kind as i32
166 }
167 };
168}
169
170semantic_registry! {
171 kind = spell_effect_kind,
172 is = spell_effect_is,
173 is_any = spell_effect_is_any,
174 raw = spell_effect_raw,
175 semantic = spell_effect_semantic,
176 registry = SPELL_EFFECT_SEMANTICS,
177 type = SpellEffectKind
178}
179
180#[must_use]
182pub fn aura_subtype_semantic(raw: i32) -> Option<&'static AuraSubtypeSemantic> {
183 AURA_SUBTYPE_SEMANTICS
184 .binary_search_by_key(&raw, |entry| entry.kind as i32)
185 .ok()
186 .and_then(|index| AURA_SUBTYPE_SEMANTICS.get(index))
187}
188
189#[must_use]
191pub fn aura_subtype_modifier(raw: i32) -> Option<(ModifierOperation, ModifierFilter)> {
192 aura_subtype_semantic(raw).and_then(|semantic| semantic.modifier)
193}
194
195semantic_registry! {
196 kind = aura_subtype_kind,
197 is = aura_subtype_is,
198 is_any = aura_subtype_is_any,
199 raw = aura_subtype_raw,
200 semantic = aura_subtype_semantic,
201 registry = AURA_SUBTYPE_SEMANTICS,
202 type = AuraSubtypeKind
203}
204
205#[must_use]
207pub const fn pet_stat_kind(raw: i32) -> Option<PetStatKind> {
208 match raw {
209 2 => Some(PetStatKind::AttackPowerInheritance),
210 3 => Some(PetStatKind::SpellPowerInheritance),
211 _ => None,
212 }
213}
214
215#[must_use]
217pub fn modifier_property_semantic(raw: i32) -> Option<&'static ModifierPropertySemantic> {
218 MODIFIER_PROPERTY_SEMANTICS
219 .iter()
220 .find(|entry| entry.kind as i32 == raw)
221}
222
223semantic_registry! {
224 kind = modifier_property_kind,
225 is = modifier_property_is,
226 is_any = modifier_property_is_any,
227 raw = modifier_property_raw,
228 semantic = modifier_property_semantic,
229 registry = MODIFIER_PROPERTY_SEMANTICS,
230 type = ModifierPropertyKind
231}
232
233pub trait SpellEffectSemanticExt {
235 fn effect_is(&self, expected: SpellEffectKind) -> bool;
236 fn effect_is_any(&self, expected: &[SpellEffectKind]) -> bool;
237 fn aura_is(&self, expected: AuraSubtypeKind) -> bool;
238 fn aura_is_any(&self, expected: &[AuraSubtypeKind]) -> bool;
239 fn modifier_property_is(&self, expected: ModifierPropertyKind) -> bool;
240 fn modifier_property_is_any(&self, expected: &[ModifierPropertyKind]) -> bool;
241}
242
243impl SpellEffectSemanticExt for SpellEffect {
244 fn effect_is(&self, expected: SpellEffectKind) -> bool {
245 spell_effect_is(self.effect, expected)
246 }
247
248 fn effect_is_any(&self, expected: &[SpellEffectKind]) -> bool {
249 spell_effect_is_any(self.effect, expected)
250 }
251
252 fn aura_is(&self, expected: AuraSubtypeKind) -> bool {
253 aura_subtype_is(self.aura, expected)
254 }
255
256 fn aura_is_any(&self, expected: &[AuraSubtypeKind]) -> bool {
257 aura_subtype_is_any(self.aura, expected)
258 }
259
260 fn modifier_property_is(&self, expected: ModifierPropertyKind) -> bool {
261 raw_modifier_property_is(self.misc_value_0, expected)
262 }
263
264 fn modifier_property_is_any(&self, expected: &[ModifierPropertyKind]) -> bool {
265 raw_modifier_property_is_any(self.misc_value_0, expected)
266 }
267}
268
269#[must_use]
271pub fn modifier_combination_supported(
272 aura: &AuraSubtypeSemantic,
273 property: &ModifierPropertySemantic,
274) -> bool {
275 aura.modifier.is_some_and(|(operation, _)| {
276 let required = match operation {
277 ModifierOperation::Flat => ModifierOperations::FLAT,
278 ModifierOperation::Percent => ModifierOperations::PERCENT,
279 };
280
281 property.operations.contains(required)
282 })
283}
284
285#[cfg(test)]
286mod tests;