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: 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}