wowlab_engine_content/hooks/marksmanship_hunter/
dark_minion.rs1use wowlab_engine_combat::DamageOps as _;
4use wowlab_engine_combat::GuardianOps as _;
5use wowlab_engine_combat::{DamageFlags, GuardianAbility, GuardianEvent, GuardianSpec, HookCtx};
6use wowlab_engine_rng::roll_range;
7use wowlab_types::constants::MS_PER_SECOND;
8
9use crate::generated::specs::marksmanship_hunter::{EFFECT, HERO};
10
11use super::config::{MarksmanshipConfig, marksmanship_config};
12
13const SPAWN_SHOOT_DELAY_MIN_MS: f64 = MS_PER_SECOND;
15const SPAWN_SHOOT_DELAY_MAX_MS: f64 = MS_PER_SECOND * 1.5;
16const SHOOT_IDLE_MIN_MS: f64 = 350.0;
18const SHOOT_IDLE_MAX_MS: f64 = 650.0;
19
20const BLIGHTED_ARROW_ABILITY: usize = 1;
22
23fn shoot(ctx: &mut HookCtx<'_>, _event: GuardianEvent) {
24 ctx.deal_effect_damage_ap(
25 EFFECT::DARK_MINION_SHOOT_DAMAGE,
26 1.0,
27 DamageFlags::PHYSICAL,
28 );
29}
30
31fn blighted_arrow(ctx: &mut HookCtx<'_>, _event: GuardianEvent) {
32 ctx.deal_effect_damage_ap(
33 EFFECT::DARK_MINION_BLIGHTED_ARROW_DAMAGE,
34 1.0,
35 DamageFlags::empty(),
36 );
37}
38
39fn delay_ms(rng: &mut dyn FnMut() -> f64, cast_ms: u32, low: f64, high: f64) -> u32 {
40 cast_ms.saturating_add(wowlab_types::numeric::f64_to_u32_saturating_round(roll_range(
41 rng, low, high,
42 )))
43}
44
45pub(super) fn summon_dark_minion(ctx: &mut HookCtx<'_>) {
47 let cfg = marksmanship_config(ctx);
48
49 if cfg.dark_minion_duration_ms == 0 {
50 return;
51 }
52
53 let cast_ms = cfg.dark_minion_shoot_cast_ms;
54 let first_shoot_ms = delay_ms(ctx.rng(), cast_ms, SPAWN_SHOOT_DELAY_MIN_MS, SPAWN_SHOOT_DELAY_MAX_MS);
55 let shoot_interval_ms = delay_ms(ctx.rng(), cast_ms, SHOOT_IDLE_MIN_MS, SHOOT_IDLE_MAX_MS);
56
57 let _ = ctx.summon_guardian(
58 GuardianSpec::new_inheriting_owner(
59 HERO::DARK_RANGER::SPELL::DARK_MINION_SUMMON,
60 cfg.dark_minion_duration_ms,
61 )
62 .ability(GuardianAbility::new(shoot_interval_ms, shoot).first_action_delay(first_shoot_ms))
63 .ability(GuardianAbility::on_demand(blighted_arrow)),
64 );
65}
66
67pub(super) fn trueshot_summon(
69 ctx: &mut HookCtx<'_>,
70 cfg: &MarksmanshipConfig,
71) {
72 if !cfg.wailing_dead {
73 return;
74 }
75
76 summon_dark_minion(ctx);
77}
78
79pub(super) fn pact_of_the_hollow(
81 ctx: &mut HookCtx<'_>,
82 cfg: &MarksmanshipConfig,
83) {
84 if !cfg.pact_of_the_hollow {
85 return;
86 }
87
88 let _ = ctx.command_guardians(
89 HERO::DARK_RANGER::SPELL::DARK_MINION_SUMMON,
90 BLIGHTED_ARROW_ABILITY,
91 );
92}