Skip to main content

codegen/
gen_spell_properties.rs

1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3use wowlab_manifest_schema::ManifestSpellDef;
4
5use crate::{
6    gen_emit::{
7        scalar_ref_call, spell_idx, validated_charges_call, validated_milliseconds_call,
8        validated_nonnegative_call,
9    },
10    rust_source::{lit_int, rust_ident, rust_path},
11};
12
13pub(crate) fn apply_core_spell_properties(
14    mut expression: TokenStream,
15    id: u32,
16    def: &ManifestSpellDef,
17    hook_module: &str,
18) -> anyhow::Result<TokenStream> {
19    if let Some(cooldown) = &def.cooldown {
20        let cooldown = validated_nonnegative_call(cooldown, id, "spell.cooldown")?;
21
22        expression = quote!(#expression.cooldown(#cooldown));
23    }
24
25    if let Some(charges) = &def.charges {
26        let charge_cooldown = def
27            .charge_cd
28            .as_ref()
29            .or(def.cooldown.as_ref())
30            .map(|value| validated_nonnegative_call(value, id, "spell.charge_cd"))
31            .transpose()?
32            .unwrap_or_else(|| {
33                let spell_id = spell_idx(id);
34
35                quote!(data.require_charge_cd_s(#spell_id)?)
36            });
37        let charges = validated_charges_call(charges, id, "spell.charges")?;
38
39        expression = quote!(#expression.charges(#charges, #charge_cooldown));
40    }
41
42    if let Some(hasted) = def.cooldown_hasted {
43        expression = if hasted {
44            quote!(#expression.hasted_cooldown())
45        } else {
46            quote!(#expression.unhasted_cooldown())
47        };
48    }
49
50    if def.cast_time_ms.is_some() && def.empower.is_some() {
51        anyhow::bail!("spell {id} cannot declare both cast_time_ms and empower");
52    }
53
54    if let Some(empower) = &def.empower {
55        if let Some(aura) = &empower.max_when_aura {
56            let aura = rust_ident(aura)?;
57
58            expression = quote!(#expression.max_empower_when_aura(AURA::#aura));
59        }
60
61        if let Some(driver) = &empower.driver {
62            let hook_module = rust_path(hook_module)?;
63            let driver = format_ident!("{driver}_empower_release");
64
65            expression =
66                quote!(#expression.on_empower_release(crate::hooks::#hook_module::#driver));
67        }
68    } else if let Some(cast_time) = &def.cast_time_ms {
69        let cast_time = validated_milliseconds_call(cast_time, id, "spell.cast_time_ms")?;
70
71        expression = quote!(#expression.cast_time(#cast_time));
72    }
73
74    if let Some(travel_time) = &def.travel_time_ms {
75        let travel_time = validated_milliseconds_call(travel_time, id, "spell.travel_time_ms")?;
76
77        expression = quote!(#expression.travel_time(#travel_time));
78    }
79
80    if let Some(cost) = &def.cost {
81        let cost = validated_nonnegative_call(cost, id, "spell.cost")?;
82
83        expression = quote!(#expression.cost(#cost));
84    }
85
86    if let Some(gcd) = &def.gcd_ms {
87        let gcd = validated_milliseconds_call(gcd, id, "spell.gcd_ms")?;
88
89        expression = quote!(#expression.gcd(#gcd));
90    }
91
92    if let Some(gain) = &def.gain {
93        let gain = scalar_ref_call(gain)?;
94
95        expression = quote!(#expression.gain(#gain));
96    }
97
98    Ok(expression)
99}
100
101pub(crate) fn apply_override(
102    mut expression: TokenStream,
103    id: u32,
104    def: &ManifestSpellDef,
105) -> anyhow::Result<TokenStream> {
106    match (&def.override_when_aura, &def.override_with_spell) {
107        (Some(aura), Some(spell)) => {
108            let aura = rust_ident(aura)?;
109            let spell = rust_ident(spell)?;
110
111            expression = quote!(#expression.overridden_by(SPELL::#spell, AURA::#aura));
112        }
113        (None, None) => {}
114        _ => anyhow::bail!(
115            "spell {id}: override_when_aura and override_with_spell must be specified together"
116        ),
117    }
118
119    if let Some(min_stacks) = def.override_aura_min_stacks {
120        let min_stacks = lit_int(min_stacks);
121
122        expression = quote!(#expression.override_at_min_stacks(#min_stacks));
123    }
124
125    if def.override_shares_base_cooldown {
126        expression = quote!(#expression.override_shares_base_cooldown());
127    }
128
129    if def.override_preserves_aura {
130        expression = quote!(#expression.override_preserves_aura());
131    }
132
133    Ok(expression)
134}