Skip to main content

wowlab_engine_combat/builder/aura_builder/
from_data.rs

1use wowlab_engine_domain::dbc::{
2    AuraSubtypeKind, EffectLookup, LiveDamageModifierKind, ModifierPropertyKind, aura_subtype_is,
3    aura_subtype_is_any, live_damage_modifier, modifier_property_is,
4};
5
6use super::{
7    AuraDefinitionDraft, apply_active_stat_effect, apply_actor_scope_from_data,
8    apply_automatic_periodic_effect, apply_critical_modifier_effect, apply_effect_points_modifier,
9    apply_non_passive_effect, apply_spell_modifier_effect, apply_timing_modifier_effect,
10};
11use crate::{
12    BuilderError,
13    state::{BuffEffect, DamageSource},
14};
15
16// #t(fn: rust_cyclomatic_complexity) one DBC effect is lowered through independent modifier and trigger families in deterministic order.
17fn apply_foldable_effects(
18    mut aura: AuraDefinitionDraft,
19    lookup: EffectLookup<'_>,
20    folded_passive: bool,
21) -> Result<AuraDefinitionDraft, BuilderError> {
22    if folded_passive {
23        return Ok(aura);
24    }
25
26    aura = apply_effect_points_modifier(aura, lookup)?;
27    aura = apply_spell_modifier_effect(aura, lookup)?;
28    aura = apply_timing_modifier_effect(aura, lookup)?;
29    aura = apply_critical_modifier_effect(aura, lookup)?;
30    aura = apply_active_stat_effect(aura, lookup)?;
31    let spell_id = lookup.effect.spell.as_u32();
32    let effect_index = lookup.effect.effect_index;
33    let subtype = lookup.effect_aura();
34
35    if aura_subtype_is_any(
36        subtype,
37        &[
38            AuraSubtypeKind::AddPercentModifier,
39            AuraSubtypeKind::AddPercentLabelModifier,
40        ],
41    ) && modifier_property_is(lookup.effect_misc_value_0(), ModifierPropertyKind::Cooldown)
42    {
43        aura = aura.push_effect(BuffEffect::CooldownDurationPercent {
44            percent: lookup.base_points(),
45            source_spell_id: spell_id,
46            effect_index,
47        })?;
48    }
49
50    let subtype = lookup.effect_aura();
51
52    if aura_subtype_is(subtype, AuraSubtypeKind::SpellReflection) {
53        aura = aura.push_effect(BuffEffect::SpellReflection(
54            wowlab_engine_domain::dbc::SpellSchoolMask::CHAOS,
55        ))?;
56    } else if aura_subtype_is(subtype, AuraSubtypeKind::SpellReflectionSchool) {
57        aura = aura.push_effect(BuffEffect::SpellReflection(
58            wowlab_engine_domain::dbc::SpellSchoolMask::from_dbc(lookup.effect_misc_value_0()),
59        ))?;
60    } else if aura_subtype_is(subtype, AuraSubtypeKind::DeflectSpells) {
61        aura = aura.push_effect(BuffEffect::SpellDeflectChance(lookup.base_points()))?;
62    }
63
64    Ok(aura)
65}
66
67fn apply_damage_taken_effects(
68    mut aura: AuraDefinitionDraft,
69    lookup: EffectLookup<'_>,
70) -> Result<AuraDefinitionDraft, BuilderError> {
71    let spell_id = lookup.effect.spell.as_u32();
72    let effect_index = lookup.effect.effect_index;
73    let subtype = lookup.effect_aura();
74    let source = if aura_subtype_is(subtype, AuraSubtypeKind::ModDamageTakenFromCaster) {
75        Some(DamageSource::Player)
76    } else if aura_subtype_is(subtype, AuraSubtypeKind::ModDamageTakenFromCasterGuardian) {
77        Some(DamageSource::Guardian)
78    } else if aura_subtype_is(subtype, AuraSubtypeKind::ModDamageTakenFromCasterPet) {
79        Some(DamageSource::Pet)
80    } else {
81        None
82    };
83
84    if let Some(source) = source {
85        aura = aura.push_effect(BuffEffect::DamageTakenFromSource(
86            lookup.base_points(),
87            source,
88        ))?;
89    }
90
91    if live_damage_modifier(subtype, lookup.effect_misc_value_0())
92        == Some(LiveDamageModifierKind::DamageTakenFromCasterSpells)
93    {
94        aura = aura.push_effect(BuffEffect::DamageTakenFromSourceSpells {
95            percent: lookup.base_points(),
96            source_spell_id: spell_id,
97            effect_index,
98            source: DamageSource::Player,
99        })?;
100    }
101
102    Ok(aura)
103}
104
105pub(super) fn apply_base_effect(
106    aura: AuraDefinitionDraft,
107    lookup: EffectLookup<'_>,
108    folded_passive: bool,
109) -> Result<AuraDefinitionDraft, BuilderError> {
110    let spell_id = lookup.effect.spell.as_u32();
111    let effect_index = lookup.effect.effect_index;
112    let mut aura = apply_actor_scope_from_data(aura, lookup);
113
114    if aura.crowd_control.is_none()
115        && let Some(subtype) = wowlab_engine_domain::dbc::aura_subtype_kind(lookup.effect_aura())
116    {
117        aura.crowd_control = wowlab_engine_domain::dbc::crowd_control_semantic(subtype);
118    }
119
120    if aura_subtype_is(lookup.effect_aura(), AuraSubtypeKind::Shapeshift) {
121        aura.shapeshift_form = lookup.effect_misc_value_0();
122        aura.shapeshift_form_flags = lookup
123            .data
124            .shapeshift_form_flags(lookup.effect.spell, effect_index);
125        aura.shapeshift_combat_round_time_ms = u32::try_from(
126            lookup
127                .data
128                .shapeshift_combat_round_time_ms(lookup.effect.spell, effect_index),
129        )
130        .unwrap_or(0);
131    }
132
133    if aura_subtype_is(lookup.effect_aura(), AuraSubtypeKind::TriggerSpellOnExpire)
134        && let Some(trigger) = lookup.trigger_spell()
135    {
136        aura = aura.trigger_spell_on_expire(trigger.as_u32(), lookup.effect_misc_value_0() > 0);
137    }
138
139    if aura_subtype_is_any(
140        lookup.effect_aura(),
141        &[
142            AuraSubtypeKind::ModTimeRate,
143            AuraSubtypeKind::ModTimeRateLabel,
144        ],
145    ) {
146        aura = aura.push_effect(BuffEffect::AuraTimeRateFromEffect {
147            percent: lookup.base_points(),
148            source_spell_id: spell_id,
149            effect_index,
150        })?;
151    }
152
153    let aura = apply_automatic_periodic_effect(aura, lookup)?;
154    let aura = apply_non_passive_effect(aura, lookup)?;
155    let aura = apply_foldable_effects(aura, lookup, folded_passive)?;
156
157    apply_damage_taken_effects(aura, lookup)
158}