Skip to main content

wowlab_engine_content/hooks/shadow_priest/
config.rs

1use wowlab_engine_combat::{BuffEffect, ImpactProc, LocalThresholdIdx, ThresholdTracker};
2use wowlab_engine_domain::dbc::ResolvedGameDataEffectExt as _;
3use wowlab_types::{constants::HUNDRED};
4
5use crate::{
6    generated::specs::shadow_priest::{AURA_INSIDIOUS_IRE, EFFECT, SPELL, TALENT},
7    hooks::gated,
8};
9
10use super::hooks::{shadowy_insight_fire, swp_filter, tormented_spirits_fire};
11
12const TORMENTED_SPIRITS_CHANCE: f64 = 0.13;
13// No DBC rate exists (375888 e1 is a dummy); the 0.08-per-SWP-tick accumulator is SimC-only.
14const SHADOWY_INSIGHT_INCREMENT_MAX: f64 = 0.08;
15
16#[rustfmt::skip]
17static INSIDIOUS_IRE_SPELLS: [u32; 4] = [
18    SPELL::MIND_BLAST,
19    EFFECT::VOID_BLAST_DAMAGE.0,
20    SPELL::MIND_FLAY,
21    SPELL::VOID_TORRENT,
22];
23
24crate::hooks::define_spec_config! {
25    /// Talent-gated Shadow hook parameters.
26    pub(super) struct ShadowConfig {
27        void_apparition_chance: f64 { provenance: "Void Apparitions 1264104 e2 chance multiplied by selected ranks.", gate: params.talent_ranks(TALENT::VOID_APPARITIONS_2) > 0, source: data.effect_base_points(EFFECT::VOID_APPARITIONS_CHANCE) * f64::from(params.talent_ranks(TALENT::VOID_APPARITIONS_2)), transform: |value| value / HUNDRED },
28        auspicious_insanity: f64 { provenance: "Auspicious Spirits 155271 e2 insanity per apparition.", gate: params.talent_picked(TALENT::AUSPICIOUS_SPIRITS), source: data.effect_base_points(EFFECT::AUSPICIOUS_SPIRITS_INSANITY), transform: |value| value / HUNDRED },
29        mind_flay_tick_insanity: f64 { provenance: "Mind Flay 15407 e3 insanity, scaled by Surge of Insanity 391399 e2.", gate: true, source: data.effect_base_points(EFFECT::MIND_FLAY_TICK_INSANITY) / HUNDRED, transform: |value| value * if params.talent_picked(TALENT::SURGE_OF_INSANITY) { 1.0 + data.effect_base_points(EFFECT::SURGE_OF_INSANITY_GEN) / HUNDRED } else { 1.0 } },
30        collapsing_void_pct: f64 { provenance: "Collapsing Void 448403 e3 damage bonus per Madness stack.", gate: params.talent_picked(TALENT::COLLAPSING_VOID), source: data.effect_base_points(EFFECT::COLLAPSING_VOID_PCT), transform: |value| value / HUNDRED },
31        shadowy_apparitions: bool { provenance: "Shadowy Apparitions enables apparition volleys.", gate: params.talent_picked(TALENT::SHADOWY_APPARITIONS), source: true, transform: |value| value },
32        void_blast: bool { provenance: "Void Blast enables Mind Blast replacement during Entropic Rift.", gate: params.talent_picked(TALENT::VOID_BLAST), source: true, transform: |value| value },
33        voidheart: bool { provenance: "Voidheart enables its Entropic Rift window aura.", gate: params.talent_picked(TALENT::VOIDHEART), source: true, transform: |value| value },
34        darkening_horizon: bool { provenance: "Darkening Horizon enables Void Blast rift extensions.", gate: params.talent_picked(TALENT::DARKENING_HORIZON), source: true, transform: |value| value },
35        insidious_ire: bool { provenance: "Insidious Ire enables the three-DoT damage window.", gate: params.talent_picked(TALENT::INSIDIOUS_IRE), source: true, transform: |value| value },
36        shattered_psyche: bool { provenance: "Shattered Psyche 391090 e2 stacks buff 391092 on Mind Flay ticks and Mind Blast expires it (`sc_priest_shadow.cpp:77`, `sc_priest.cpp:148`).", gate: params.talent_picked(TALENT::SHATTERED_PSYCHE), source: true, transform: |value| value },
37        shadowy_insight_threshold: Option<LocalThresholdIdx> { provenance: "Shadowy Insight 375888 accumulated-threshold tracker slot (`SimC` `threshold_rng`, `sc_priest_shadow.cpp:2180`).", gate: true, source: shadowy_insight_threshold, transform: |value| value },
38    }
39    accessor pub(super) fn shadow_config(ctx);
40    register pub(super) fn register_shadow(built, params) -> ();
41    prepare {
42        let data = &params.game_data;
43        let shadowy_insight_threshold = gated(params.talent_picked(TALENT::SHADOWY_INSIGHT), || {
44            let idx = built
45                .register_threshold_tracker(ThresholdTracker {
46                    increment_max: SHADOWY_INSIGHT_INCREMENT_MAX,
47                    accumulated: f64::NAN,
48                    roll_over: true,
49                })
50                .expect("Shadow threshold tracker count fits the local-index contract");
51            Some(idx)
52        });
53    }
54    auras {
55        { provenance: "Insidious Ire three-DoT damage window.", gate: params.talent_picked(TALENT::INSIDIOUS_IRE), aura: AURA_INSIDIOUS_IRE, effect: BuffEffect::DamageMultSpells(1.0 + data.effect_base_points(EFFECT::INSIDIOUS_IRE_BONUS) / HUNDRED, &INSIDIOUS_IRE_SPELLS) },
56    }
57    wiring {
58        { provenance: "Tormented Spirits apparition proc.", gate: params.talent_picked(TALENT::TORMENTED_SPIRITS) && params.talent_picked(TALENT::SHADOWY_APPARITIONS), apply: {
59            built.register_impact_proc(ImpactProc::new(tormented_spirits_fire).with_chance(TORMENTED_SPIRITS_CHANCE).with_spell_filter(swp_filter).periodic_only());
60        } },
61        { provenance: "Shadowy Insight threshold proc off Shadow Word: Pain ticks (sc_priest_shadow.cpp:640).", gate: params.talent_picked(TALENT::SHADOWY_INSIGHT), apply: {
62            built.register_impact_proc(ImpactProc::new(shadowy_insight_fire).with_spell_filter(swp_filter).periodic_only());
63        } },
64    }
65    finish |cfg| {
66        built.state.set_spec_config(cfg);
67    }
68}