Skip to main content

wowlab_engine_combat/builder/spell_builder/
channel.rs

1use super::{
2    BuilderDamageDef, BuilderSpellEffect, CastHookFn, DamageFlags, LocalAuraIdx, ResourcePool,
3    SpellDefinitionDraft, attribute_damage_flags,
4};
5
6impl SpellDefinitionDraft {
7    /// Register a hook fired after each channel tick's damage is applied.
8    pub fn on_channel_tick(mut self, hook: CastHookFn) -> Self {
9        self.tick_hook = Some(hook);
10
11        self
12    }
13
14    /// Mark this spell as a channel of `tick_count` ticks over `cast_time_ms`.
15    pub fn channel(mut self, tick_count: u8) -> Self {
16        self.is_channel = true;
17        self.channel_tick_count = tick_count;
18
19        self
20    }
21
22    pub fn channel_tick_timing(mut self, interval_ms: u32, tick_zero: bool) -> Self {
23        self.channel_tick_interval_ms = interval_ms;
24        self.channel_tick_zero = tick_zero;
25
26        self
27    }
28
29    /// Classify child tick hits as direct damage while retaining channel cadence.
30    pub fn channel_tick_direct_damage(mut self) -> Self {
31        self.channel_tick_is_periodic = false;
32
33        self
34    }
35
36    pub fn channel_tick_damage_ap(mut self, coef: f64, flags: DamageFlags) -> Self {
37        self.channel_tick_damage = BuilderDamageDef::ApCoefficient {
38            coef,
39            is_physical: flags.contains(DamageFlags::PHYSICAL),
40            ap_type: crate::state::WeaponApType::MainHand,
41        };
42        self.channel_tick_may_crit = !flags.contains(DamageFlags::NO_CRIT);
43        self.damage_attribute_flags = attribute_damage_flags(flags);
44
45        self
46    }
47
48    pub fn channel_tick_damage_sp(mut self, coef: f64, flags: DamageFlags) -> Self {
49        self.channel_tick_damage = BuilderDamageDef::SpCoefficient {
50            coef,
51            is_physical: flags.contains(DamageFlags::PHYSICAL),
52        };
53        self.channel_tick_may_crit = !flags.contains(DamageFlags::NO_CRIT);
54        self.damage_attribute_flags = attribute_damage_flags(flags);
55
56        self
57    }
58
59    /// Use an alternate AP payload while `aura_id` is active.
60    pub fn channel_tick_damage_alt_ap(
61        mut self,
62        coef: f64,
63        flags: DamageFlags,
64        spell_id: u32,
65        aura_id: u32,
66    ) -> Self {
67        self.channel_tick_damage_alt = BuilderDamageDef::ApCoefficient {
68            coef,
69            is_physical: flags.contains(DamageFlags::PHYSICAL),
70            ap_type: crate::state::WeaponApType::MainHand,
71        };
72        self.channel_tick_damage_alt_may_crit = !flags.contains(DamageFlags::NO_CRIT);
73        self.channel_tick_damage_alt_spell_id = spell_id;
74        self.channel_tick_damage_aura = aura_id;
75
76        self
77    }
78
79    /// Use an alternate SP payload while `aura_id` is active.
80    pub fn channel_tick_damage_alt_sp(
81        mut self,
82        coef: f64,
83        flags: DamageFlags,
84        spell_id: u32,
85        aura_id: u32,
86    ) -> Self {
87        self.channel_tick_damage_alt = BuilderDamageDef::SpCoefficient {
88            coef,
89            is_physical: flags.contains(DamageFlags::PHYSICAL),
90        };
91        self.channel_tick_damage_alt_may_crit = !flags.contains(DamageFlags::NO_CRIT);
92        self.channel_tick_damage_alt_spell_id = spell_id;
93        self.channel_tick_damage_aura = aura_id;
94
95        self
96    }
97
98    /// Per-tick primary-resource cost for a channel; an unaffordable tick ends it early.
99    pub fn channel_tick_cost(mut self, amount: f64) -> Self {
100        self.channel_tick_cost = amount;
101
102        self
103    }
104
105    /// Aura-conditional per-tick cost: spend `amount` instead while `aura_id` is active.
106    pub fn channel_tick_cost_alt(mut self, amount: f64, aura_id: u32) -> Self {
107        self.channel_tick_cost_alt = amount;
108        self.channel_tick_cost_aura = aura_id;
109
110        self
111    }
112
113    pub fn channel_tick_gain(mut self, amount: f64) -> Self {
114        self.channel_tick_effects
115            .push(BuilderSpellEffect::Energize {
116                effect: None,
117                pool: ResourcePool::Primary,
118                amount,
119            });
120
121        self
122    }
123
124    pub fn channel_tick_secondary_gain(mut self, amount: f64) -> Self {
125        self.channel_tick_effects
126            .push(BuilderSpellEffect::Energize {
127                effect: None,
128                pool: ResourcePool::Secondary,
129                amount,
130            });
131
132        self
133    }
134
135    /// Extend an aura once after the channel's final scheduled tick.
136    pub fn channel_complete_extend_aura(mut self, aura: LocalAuraIdx, amount_ms: u32) -> Self {
137        self.channel_complete_effects
138            .push(BuilderSpellEffect::ExtendAura {
139                aura_local: aura,
140                amount_ms,
141            });
142
143        self
144    }
145
146    /// Override whether the GCD triggers at channel start. Defaults to `true`.
147    pub fn channel_gcd_on_start(mut self, on_start: bool) -> Self {
148        self.channel_gcd_on_start = on_start;
149
150        self
151    }
152
153    pub(crate) fn channel_tick_source(mut self, spell_id: u32) -> Self {
154        self.channel_tick_spell_id = Some(spell_id);
155
156        self
157    }
158}