Skip to main content

codegen/
gen_spell_channel.rs

1use 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}