codegen/
gen_aura_behavior.rs1use 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}