wowlab_engine_content/hooks/shared/
hunter.rs1use wowlab_engine_combat::{AuraOps as _, HookCtx, LocalAuraIdx, ProcOps as _};
2
3pub(crate) type HowlEffect = fn(&mut HookCtx<'_>);
4
5const HOWL_STAGE_COUNT: usize = 3;
6const FINAL_HOWL_STAGE: usize = HOWL_STAGE_COUNT - 1;
7
8#[derive(Clone, Copy, Debug)]
9pub(crate) struct PackLeaderHowl {
10 pub wyvern_ready: LocalAuraIdx,
11 pub boar_ready: LocalAuraIdx,
12 pub bear_ready: LocalAuraIdx,
13 pub on_wyvern: HowlEffect,
14 pub on_boar: HowlEffect,
15 pub on_bear: HowlEffect,
16 pub on_consumed: HowlEffect,
17 pub consume_all: bool,
18}
19
20pub(crate) fn apply_next_howl_ready(
21 ctx: &mut HookCtx<'_>,
22 driver_spell_id: u32,
23 ready_auras: [LocalAuraIdx; HOWL_STAGE_COUNT],
24) {
25 let stage_count = u32::try_from(HOWL_STAGE_COUNT).expect("howl stage count fits in u32");
26 let stage = usize::try_from(ctx.proc_counter(driver_spell_id) % stage_count)
27 .expect("howl stage index fits in usize");
28 let Some(ready_aura) = ready_auras.get(stage).copied() else {
29 return;
30 };
31
32 ctx.apply_aura(ready_aura.raw());
33
34 if stage == FINAL_HOWL_STAGE {
35 ctx.reset_proc_counter(driver_spell_id);
36 } else {
37 ctx.add_proc_counter(driver_spell_id, 1);
38 }
39}
40
41pub(crate) fn consume_howl(ctx: &mut HookCtx<'_>, howl: PackLeaderHowl) {
42 let mut consumed = false;
43
44 for (ready, effect) in [
45 (howl.wyvern_ready, howl.on_wyvern),
46 (howl.boar_ready, howl.on_boar),
47 (howl.bear_ready, howl.on_bear),
48 ] {
49 if ctx.consume_aura(ready.raw()) {
50 effect(ctx);
51 consumed = true;
52
53 if !howl.consume_all {
54 break;
55 }
56 }
57 }
58
59 if consumed {
60 (howl.on_consumed)(ctx);
61 }
62}