codegen/
gen_spell_channel.rs1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3use wowlab_manifest_schema::{ChannelDamageType, ChannelDef, EventEffectDef};
4
5use crate::{
6 gen_damage::{apply_channel_tick_damage, apply_channel_tick_damage_alt},
7 gen_emit::{
8 require_get, scalar_ref_call, spell_idx, validated_channel_tick_count_call,
9 validated_milliseconds_call,
10 },
11 rust_source::{rust_ident, rust_path},
12};
13
14pub(crate) fn apply_channel(
15 mut expression: TokenStream,
16 id: u32,
17 channel: &ChannelDef,
18 module_name: &str,
19) -> anyhow::Result<TokenStream> {
20 let spell_id = spell_idx(id);
21 let tick_count = match &channel.tick_count {
22 Some(count) => validated_channel_tick_count_call(count, id, "channel.tick_count")?,
23 None => require_get("channel_tick_count", &spell_id),
24 };
25
26 expression = quote!(#expression.channel(#tick_count));
27
28 if channel.damage_type == ChannelDamageType::Direct {
29 expression = quote!(#expression.channel_tick_direct_damage());
30 }
31
32 if let Some(interval) = &channel.tick_interval_ms {
33 let interval = validated_milliseconds_call(interval, id, "channel.tick_interval_ms")?;
34 let tick_zero = channel.tick_zero;
35
36 expression = quote!(#expression.channel_tick_timing(#interval, #tick_zero));
37 } else if channel.tick_zero {
38 expression = quote!(#expression.channel_tick_timing(0, true));
39 }
40
41 if let Some(damage) = &channel.tick_damage {
42 expression = apply_channel_tick_damage(&expression, damage)?;
43 }
44
45 if let Some(alternate) = &channel.tick_damage_alt {
46 expression =
47 apply_channel_tick_damage_alt(&expression, &alternate.damage, &alternate.aura)?;
48 }
49
50 if let Some(cost) = &channel.tick_cost {
51 let spell_id = spell_idx(cost.spell_id);
52 let cost = require_get("cost", &spell_id);
53
54 expression = quote!(#expression.channel_tick_cost(#cost));
55 }
56
57 if let Some(alternate) = &channel.tick_cost_alt {
58 let spell_id = spell_idx(alternate.spell_id);
59 let cost = require_get("cost", &spell_id);
60 let aura = rust_ident(&alternate.aura)?;
61
62 expression = quote!(#expression.channel_tick_cost_alt(#cost, AURA::#aura));
63 }
64
65 for effect in &channel.tick_effects {
66 expression = match effect {
67 EventEffectDef::Energize { amount, secondary } => {
68 let amount = scalar_ref_call(amount)?;
69
70 if *secondary {
71 quote!(#expression.channel_tick_secondary_gain(#amount))
72 } else {
73 quote!(#expression.channel_tick_gain(#amount))
74 }
75 }
76 _ => anyhow::bail!("unsupported channel tick effect"),
77 };
78 }
79
80 for effect in &channel.complete_effects {
81 expression = match effect {
82 EventEffectDef::ExtendAura { aura, amount_ms } => {
83 let aura = format_ident!("AURA_{aura}");
84 let amount_ms = validated_milliseconds_call(
85 amount_ms,
86 id,
87 "channel.complete_effects.extend_aura.amount_ms",
88 )?;
89
90 quote!(#expression.channel_complete_extend_aura(#aura, #amount_ms))
91 }
92 _ => anyhow::bail!("unsupported channel completion effect"),
93 };
94 }
95
96 if let Some(gcd_on_start) = channel.gcd_on_start {
97 expression = quote!(#expression.channel_gcd_on_start(#gcd_on_start));
98 }
99
100 if let Some(tick_hook) = &channel.tick_hook {
101 let module = rust_path(module_name)?;
102 let hook = format_ident!("{tick_hook}_tick_hook");
103
104 expression = quote!(#expression.on_channel_tick(crate::hooks::#module::#hook));
105 }
106
107 Ok(expression)
108}