Skip to main content

wowlab_engine_combat/context/hook/
spells.rs

1use 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: LocalSpellIdx) -> bool {
8        let local = self.spell_identity(spell);
9        let Some(definition) = self.program.spells.get(local.as_usize()) else {
10            return false;
11        };
12        let Some(cooldown) = self.program.buffer_cooldown(self.instance, local) 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.program, self.instance, local, self.now);
21
22        true
23    }
24
25    fn reduce_cooldown(&mut self, spell: LocalSpellIdx, amount_ms: u32) {
26        let spell = self.spell_identity(spell);
27
28        systems::reduce_cooldown(self.program, self.instance, spell, amount_ms, self.now);
29    }
30
31    fn reset_cooldown(&mut self, spell: LocalSpellIdx) {
32        let spell = self.spell_identity(spell);
33
34        systems::reset_cooldown(self.program, self.instance, spell, self.now);
35    }
36
37    fn start_cooldown(&mut self, spell: LocalSpellIdx) {
38        let spell = self.spell_identity(spell);
39
40        systems::start_cooldown(self.program, self.instance, spell, self.now);
41    }
42
43    fn set_spell_gate(&mut self, spell: LocalSpellIdx, gate: SpellGate, available: bool) {
44        let spell = self.spell_identity(spell);
45
46        systems::set_spell_gate(
47            self.program,
48            self.instance,
49            spell,
50            gate,
51            available,
52            self.now,
53        );
54    }
55
56    fn grant_charges(&mut self, spell: LocalSpellIdx, amount: u8) {
57        let spell = self.spell_identity(spell);
58
59        systems::grant_charges(self.program, self.instance, spell, amount, self.now);
60    }
61
62    fn spell_cooldown_ms(&self, spell: LocalSpellIdx) -> u32 {
63        let spell = self.spell_identity(spell);
64
65        self.program
66            .spells
67            .get(spell.as_usize())
68            .map_or(0, |definition| {
69                if definition.cooldown.recharge_ms > 0 {
70                    definition.cooldown.recharge_ms
71                } else {
72                    definition.cooldown.cooldown_duration_ms
73                }
74            })
75    }
76
77    fn spell_cooldown_remaining_ms(&self, spell: LocalSpellIdx) -> u32 {
78        let spell = self.spell_identity(spell);
79        let remaining_seconds = self
80            .program
81            .spells
82            .get(spell.as_usize())
83            .and_then(|_| self.program.buffer_cooldown(self.instance, spell))
84            .map_or(0.0, |cooldown| cooldown.ready_at - self.now.as_secs_f64())
85            .max(0.0);
86
87        wowlab_types::numeric::f64_to_u32_saturating_trunc(
88            remaining_seconds.mul_add(wowlab_types::constants::MS_PER_SECOND, 0.0),
89        )
90    }
91
92    fn spell_ready(&self, spell: LocalSpellIdx) -> bool {
93        let spell = self.spell_identity(spell);
94
95        self.program
96            .spells
97            .get(spell.as_usize())
98            .and_then(|_| self.program.buffer_cooldown(self.instance, spell))
99            .is_none_or(|cooldown| cooldown.is_ready(self.now.as_secs_f64()))
100    }
101
102    fn spell_current_charges(&self, spell: LocalSpellIdx) -> i32 {
103        let spell = self.spell_identity(spell);
104
105        self.program
106            .spells
107            .get(spell.as_usize())
108            .and_then(|_| self.program.buffer_cooldown(self.instance, spell))
109            .map_or(0, |cooldown| cooldown.current_charges)
110    }
111}