Skip to main content

codegen/
gen_aura_behavior.rs

1use anyhow::bail;
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote};
4use wowlab_manifest_schema::{EventEffectDef, ManifestAuraDef, ManifestAuraTickBehavior};
5
6use crate::{
7    gen_aura::AuraEmitOptions, gen_emit::validated_milliseconds_call, rust_source::lit_int,
8};
9
10pub(crate) fn apply_refresh_behavior(
11    mut expression: TokenStream,
12    def: &ManifestAuraDef,
13) -> anyhow::Result<TokenStream> {
14    if def.no_pandemic && def.refresh_behavior.is_some() {
15        bail!(
16            "aura {} cannot combine no_pandemic with an explicit refresh_behavior",
17            def.id
18        );
19    }
20
21    if def.no_pandemic {
22        expression = quote!(#expression.no_pandemic());
23    }
24
25    if let Some(refresh_behavior) = def.refresh_behavior {
26        expression = match refresh_behavior {
27            wowlab_types::data::RefreshBehavior::Pandemic => {
28                quote!(#expression.pandemic_on_refresh())
29            }
30            wowlab_types::data::RefreshBehavior::Extend => {
31                quote!(#expression.extend_on_refresh())
32            }
33            wowlab_types::data::RefreshBehavior::Tick => {
34                quote!(#expression.carry_tick_on_refresh())
35            }
36            wowlab_types::data::RefreshBehavior::Clip => {
37                quote!(#expression.clip_on_refresh())
38            }
39            wowlab_types::data::RefreshBehavior::None => quote!(#expression.never_refresh()),
40            wowlab_types::data::RefreshBehavior::Duration => quote!(#expression.no_pandemic()),
41        };
42    }
43
44    Ok(expression)
45}
46
47pub(crate) fn apply_tick_behavior(
48    mut expression: TokenStream,
49    def: &ManifestAuraDef,
50) -> anyhow::Result<TokenStream> {
51    let id = def.id;
52
53    if def.tick_stack_change.is_some() && def.tick_behavior.is_none() {
54        bail!("aura {id} has tick_stack_change without tick_behavior");
55    }
56
57    if def.stack_tick_ms.is_some() && def.tick_behavior.is_none() {
58        bail!("aura {id} has stack_tick_ms without tick_behavior");
59    }
60
61    if def.stack_tick_ms.is_some()
62        && (def.periodic_remove_stack.is_some()
63            || def.periodic_damage.is_some()
64            || def.periodic_residual_damage.is_some()
65            || def.periodic_resource.is_some()
66            || def.periodic_resource_drain.is_some()
67            || def.periodic_apply_aura.is_some()
68            || def.periodic_hook.is_some())
69    {
70        bail!("aura {id} cannot combine stack_tick_ms with another periodic source");
71    }
72
73    if let Some(tick_ms) = &def.stack_tick_ms {
74        let tick_ms = validated_milliseconds_call(tick_ms, id, "aura.stack_tick_ms")?;
75
76        expression = quote!(#expression.periodic_stack_tick(#tick_ms));
77    }
78
79    if let Some(tick_behavior) = def.tick_behavior {
80        let amount = lit_int(def.tick_stack_change.unwrap_or(1));
81        let method = match tick_behavior {
82            ManifestAuraTickBehavior::Clip => format_ident!("clip_tick_behavior"),
83            ManifestAuraTickBehavior::Refresh => format_ident!("refresh_tick_behavior"),
84            _ => bail!("aura {id} uses an unsupported tick_behavior"),
85        };
86
87        expression = quote!(#expression.#method(#amount));
88    }
89
90    Ok(expression)
91}
92
93pub(crate) fn apply_aura_consume_effects(
94    mut expression: TokenStream,
95    def: &ManifestAuraDef,
96    options: &AuraEmitOptions<'_>,
97) -> anyhow::Result<TokenStream> {
98    for effect in &def.on_consume {
99        expression = match effect {
100            EventEffectDef::ExtendAura { aura, amount_ms } => {
101                let index = options
102                    .aura_idx_map
103                    .get(aura.as_str())
104                    .copied()
105                    .ok_or_else(|| anyhow::anyhow!("on_consume aura {aura:?} not found"))?;
106                let index = lit_int(index);
107                let amount_ms = validated_milliseconds_call(
108                    amount_ms,
109                    def.id,
110                    "aura.on_consume.extend_aura.amount_ms",
111                )?;
112
113                quote! {
114                    #expression.on_consume_extend(LocalAuraIdx::new(#index), #amount_ms)
115                }
116            }
117            _ => bail!("unsupported aura consume effect"),
118        };
119    }
120
121    Ok(expression)
122}