Skip to main content

wowlab_engine_content/hooks/demonology_warlock/
handler.rs

1use wowlab_engine_combat::AuraOps as _;
2use wowlab_engine_combat::GuardianOps as _;
3use wowlab_engine_combat::{CombatHandler, GuardianAbility, GuardianSpec};
4use wowlab_engine_ports::{HandlerParams, SimContext};
5
6use wowlab_types::constants::MS_PER_SECOND;
7
8use crate::generated::specs::demonology_warlock::{
9    AURA, AURA_INNER_DEMONS, REPORTED_SPELL, TALENT,
10};
11
12use super::{
13    config::{apply_demonic_calling, register_demonology_config, DemonologyRuntime},
14    hooks::{
15        felguard_controller_action, inner_demons_action, FELGUARD_CONTROLLER_TICK_MS,
16        INNER_DEMONS_PERIOD_MS,
17    },
18};
19
20#[derive(Debug)]
21pub(crate) struct DemonologyHandler {
22    inner: CombatHandler,
23    inner_demons: bool,
24    fight_duration_ms: u32,
25}
26
27impl DemonologyHandler {
28    /// Finishes the specialization handler from the shared-content composition stage.
29    pub(crate) fn new(
30        parts: crate::composition::ContentHandlerParts,
31        params: &HandlerParams<'_>,
32    ) -> Result<Self, wowlab_engine_ports::EngineError> {
33        let mut parts = parts;
34        let built = parts.draft_mut();
35        let inner_demons = params.talent_ranks(TALENT::INNER_DEMONS) > 0;
36
37        apply_demonic_calling(built, params.talent_ranks(TALENT::DEMONIC_CALLING));
38        register_demonology_config(built, params);
39        built.set_spec_runtime(DemonologyRuntime::default());
40
41        let built = parts.finalize()?;
42
43        Ok(Self {
44            inner: CombatHandler::from_built(built),
45            inner_demons,
46            fight_duration_ms: wowlab_types::numeric::f64_to_u32_saturating_trunc(
47                params.fight_duration_secs * MS_PER_SECOND,
48            ),
49        })
50    }
51}
52
53crate::hooks::define_spec_handler! {
54impl DemonologyHandler(self, inner) {
55    fn on_sim_start(&mut self, ctx: &mut SimContext) {
56        self.inner.on_sim_start(ctx);
57        let duration_ms = self.fight_duration_ms.saturating_add(1);
58        self.inner
59            .with_hook_ctx(&mut *ctx.telemetry, wowlab_engine_combat::HookCtxRequest::targetless(wowlab_types::sim::SimTime::ZERO), |precombat| {
60            let _ = precombat.summon_guardian(
61                GuardianSpec::new_inheriting_owner(
62                    REPORTED_SPELL::LEGION_STRIKE,
63                    duration_ms,
64                )
65                .ability(
66                    GuardianAbility::new(
67                        FELGUARD_CONTROLLER_TICK_MS,
68                        felguard_controller_action,
69                    )
70                    .first_action_delay(FELGUARD_CONTROLLER_TICK_MS),
71                ),
72            );
73            });
74        if !self.inner_demons {
75            return;
76        }
77
78        self.inner
79            .with_hook_ctx(&mut *ctx.telemetry, wowlab_engine_combat::HookCtxRequest::targetless(wowlab_types::sim::SimTime::ZERO), |precombat| {
80                let first_spawn_ms = wowlab_types::numeric::f64_to_u32_saturating_trunc(
81                    (precombat.rng())() * f64::from(INNER_DEMONS_PERIOD_MS),
82                );
83                precombat.apply_aura(AURA_INNER_DEMONS);
84                let _ = precombat.summon_guardian(
85                    GuardianSpec::new_inheriting_owner(AURA::INNER_DEMONS, duration_ms).ability(
86                        GuardianAbility::new(INNER_DEMONS_PERIOD_MS, inner_demons_action)
87                            .first_action_delay(first_spawn_ms),
88                    ),
89                );
90            });
91    }
92
93}
94}