Skip to main content

wowlab_engine_domain/dbc/passives/
resource.rs

1use std::{collections::HashSet, hash::BuildHasher};
2
3use super::{
4    AuraSubtypeKind, ModifierFold, ModifierOperation, ModifierPropertyKind, PassiveQuery,
5    SpellDataFlat, aura_kind, aura_subtype_semantic, effect_targets_spell, fold_flat_pct_modifiers,
6    modified_effect_base_points, modifier_property_kind, pct_to_mult, power_cost_is_available,
7};
8
9/// Resource cost after passive modifiers; raw DBC flat values descale through `modifiers`.
10#[must_use]
11pub fn passive_resource_cost<S>(
12    query: PassiveQuery<'_>,
13    resource_type: i32,
14    base_cost: f64,
15    active_aura_spell_ids: &HashSet<i32, S>,
16    modifiers: &crate::dbc::PowerModifiers,
17) -> f64
18where
19    S: BuildHasher,
20{
21    let PassiveQuery { passives, spell } = query;
22    let Some(cost_index) = spell.power_costs.iter().position(|cost| {
23        cost.power_type == resource_type && power_cost_is_available(cost, active_aura_spell_ids)
24    }) else {
25        return base_cost;
26    };
27    let property = match cost_index {
28        0 => ModifierPropertyKind::ResourceCost1,
29        1 => ModifierPropertyKind::ResourceCost2,
30        2 => ModifierPropertyKind::ResourceCost3,
31        _ => return base_cost,
32    };
33
34    fold_flat_pct_modifiers(
35        passives,
36        base_cost,
37        ModifierFold::FlatAndPercent,
38        |source, ranks, modifier| {
39            if modifier_property_kind(modifier) != Some(property)
40                || !effect_targets_spell(modifier, source, spell)
41            {
42                return None;
43            }
44
45            let amount = modified_effect_base_points(
46                PassiveQuery {
47                    passives,
48                    spell: source,
49                },
50                modifier.index,
51                modifier.base_points,
52            ) * ranks;
53            let is_flat = aura_subtype_semantic(modifier.aura)
54                .and_then(|semantic| semantic.modifier)
55                .is_some_and(|(operation, _)| operation == ModifierOperation::Flat);
56
57            Some(if is_flat {
58                crate::dbc::decode::scale_power_amount(amount, resource_type, modifiers)
59            } else {
60                amount
61            })
62        },
63    )
64    .max(0.0)
65}
66
67/// A passive spell and its rank multiplier.
68pub type RankedPassive = (SpellDataFlat, f64);
69
70/// Multiplicative mana-regeneration modifier from passive auras.
71#[must_use]
72pub fn passive_mana_regen_multiplier(passives: &[RankedPassive]) -> f64 {
73    passives.iter().fold(1.0, |multiplier, (spell, ranks)| {
74        spell
75            .effects
76            .iter()
77            .filter(|effect| aura_kind(effect) == Some(AuraSubtypeKind::ModManaRegenPercent))
78            .fold(multiplier, |value, effect| {
79                value * pct_to_mult(effect.base_points * ranks)
80            })
81    })
82}