wowlab_engine_combat/context/hook/
spells.rs1use wowlab_engine_domain::pool::SpellGate;
2
3use super::CooldownOps;
4use crate::{context::HookCtx, state::LocalSpellIdx, systems};
5
6impl CooldownOps for HookCtx<'_> {
7 fn spend_spell_charge(&mut self, spell: u8) -> bool {
8 let local = LocalSpellIdx::new(spell);
9 let Some(definition) = self.state.defs.spells.get(local.as_usize()) else {
10 return false;
11 };
12 let Some(cooldown) = self.buf.cooldown(definition.idx()) else {
13 return false;
14 };
15
16 if !definition.is_charged() || cooldown.current_charges <= 0 {
17 return false;
18 }
19
20 systems::start_cooldown(self.state, self.buf, local, self.now);
21
22 true
23 }
24
25 fn reduce_cooldown(&mut self, spell: u8, amount_ms: u32) {
26 systems::reduce_cooldown(
27 self.state,
28 self.buf,
29 LocalSpellIdx::new(spell),
30 amount_ms,
31 self.now,
32 );
33 }
34
35 fn reset_cooldown(&mut self, spell: u8) {
36 systems::reset_cooldown(self.state, self.buf, LocalSpellIdx::new(spell));
37 }
38
39 fn start_cooldown(&mut self, spell: u8) {
40 systems::start_cooldown(self.state, self.buf, LocalSpellIdx::new(spell), self.now);
41 }
42
43 fn set_spell_gate(&mut self, spell: u8, gate: SpellGate, available: bool) {
44 systems::set_spell_gate(
45 self.state,
46 self.buf,
47 LocalSpellIdx::new(spell),
48 gate,
49 available,
50 );
51 }
52
53 fn grant_charges(&mut self, spell: u8, amount: u8) {
54 systems::grant_charges(self.state, self.buf, LocalSpellIdx::new(spell), amount);
55 }
56
57 fn spell_cooldown_ms(&self, spell: u8) -> u32 {
58 self.state
59 .defs
60 .spells
61 .get(usize::from(spell))
62 .map_or(0, |definition| {
63 if definition.cooldown.recharge_ms > 0 {
64 definition.cooldown.recharge_ms
65 } else {
66 definition.cooldown.cooldown_duration_ms
67 }
68 })
69 }
70
71 fn spell_cooldown_remaining_ms(&self, spell: u8) -> u32 {
72 let remaining_seconds = self
73 .state
74 .defs
75 .spells
76 .get(usize::from(spell))
77 .and_then(|definition| self.buf.cooldown(definition.idx()))
78 .map_or(0.0, |cooldown| cooldown.ready_at - self.now.as_secs_f64())
79 .max(0.0);
80
81 wowlab_types::numeric::f64_to_u32_saturating_trunc(
82 remaining_seconds.mul_add(wowlab_types::constants::MS_PER_SECOND, 0.0),
83 )
84 }
85
86 fn spell_ready(&self, spell: u8) -> bool {
87 self.state
88 .defs
89 .spells
90 .get(usize::from(spell))
91 .and_then(|definition| self.buf.cooldown(definition.idx()))
92 .is_none_or(|cooldown| cooldown.is_ready(self.now.as_secs_f64()))
93 }
94
95 fn spell_current_charges(&self, spell: u8) -> i32 {
96 self.state
97 .defs
98 .spells
99 .get(usize::from(spell))
100 .and_then(|definition| self.buf.cooldown(definition.idx()))
101 .map_or(0, |cooldown| cooldown.current_charges)
102 }
103}