Skip to main content

wowlab_engine_content/hooks/devourer_demon_hunter/
config.rs

1use wowlab_engine_combat::AuraOps as _;
2use wowlab_engine_combat::{HookCtx, ImpactEvent, ImpactProc};
3use wowlab_engine_domain::dbc::ResolvedGameDataEffectExt as _;
4use wowlab_engine_rng::prd_constant;
5use wowlab_types::constants::HUNDRED;
6
7use crate::{
8    generated::specs::devourer_demon_hunter::{AURA_CATASTROPHE, EFFECT, HERO, TALENT},
9    hooks::{shared::demon_hunter::annihilator_meteor_impact, try_gated},
10};
11
12use super::hooks::{shattered_souls_fire, shattered_souls_spell_filter};
13
14fn catastrophe_impact(ctx: &mut HookCtx<'_>, impact: ImpactEvent) {
15    let fraction = devourer_config(ctx).catastrophe_pct;
16
17    ctx.add_residual_damage(AURA_CATASTROPHE.raw(), impact.amount * fraction);
18}
19
20crate::hooks::define_spec_config! {
21    /// Talent-gated Devourer hook parameters.
22    pub(super) struct DevourerConfig {
23        soul_splitter_chance: f64 {
24            provenance: "Soul Splitter 1266330 e1, converted from percent points.",
25            gate: true,
26            source: params.game_data.effect_base_points(EFFECT::SOUL_SPLITTER_CHANCE),
27            transform: |value: f64| (value / HUNDRED).max(0.0),
28        },
29        shattered_souls_chance: f64 {
30            provenance: "Shattered Souls proc chance converted from percent points.",
31            gate: true,
32            source: params.game_data.effect_base_points(EFFECT::SHATTERED_SOULS_CHANCE),
33            transform: |value: f64| (value / HUNDRED).max(0.0),
34        },
35        reap_soul_limit: i32 {
36            provenance: "Shattered Souls 1227619 e2 base Reap collection limit.",
37            gate: true,
38            source: params.game_data.effect_base_points(EFFECT::REAP_SOUL_LIMIT),
39            transform: |value: f64| wowlab_types::numeric::f64_to_i32_saturating_trunc(value.max(0.0)),
40        },
41        moment_of_craving_extra_souls: i32 {
42            provenance: "Moment of Craving 1238495 e1 additional Reap collection limit.",
43            gate: true,
44            source: params.game_data.effect_base_points(EFFECT::MOMENT_OF_CRAVING_EXTRA_SOULS),
45            transform: |value: f64| wowlab_types::numeric::f64_to_i32_saturating_trunc(value.max(0.0)),
46        },
47        soulshaper_per_fragment: f64 {
48            provenance: "Soulshaper 1238739 e1 Reap damage per collected fragment.",
49            gate: params.talent_picked(TALENT::SOULSHAPER),
50            source: params.game_data.effect_base_points(EFFECT::SOULSHAPER_PER_FRAGMENT),
51            transform: |value: f64| (value / HUNDRED).max(0.0),
52        },
53        feast_of_souls_enabled: bool {
54            provenance: "Feast of Souls 1237270 talent selection gates its consumed-fragment buff.",
55            gate: params.talent_picked(TALENT::FEAST_OF_SOULS),
56            source: 1.0,
57            transform: |value: f64| value > 0.0,
58        },
59        voidfall: bool {
60            provenance: "Voidfall hero talent enables the shared building/spending state machine.",
61            gate: voidfall,
62            source: true,
63            transform: |value| value,
64        },
65        voidfall_chance: f64 {
66            provenance: "Voidfall 1253304 e3 accumulated proc chance.",
67            gate: voidfall,
68            source: params.game_data.require_effect_base_points(EFFECT::VOIDFALL_CHANCE)?,
69            transform: |value: f64| prd_constant(value / HUNDRED),
70        },
71        voidfall_stacks: i32 {
72            provenance: "Voidfall 1253304 e1 building stacks per proc.",
73            gate: voidfall,
74            source: params.game_data.require_effect_base_points(EFFECT::VOIDFALL_STACKS)?,
75            transform: wowlab_types::numeric::f64_to_i32_saturating_trunc,
76        },
77        voidfall_max_stacks: i32 {
78            provenance: "Voidfall building aura 1256301 stack cap.",
79            gate: voidfall,
80            source: params.game_data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(HERO::ANNIHILATOR::AURA::VOIDFALL_BUILDING))?,
81            transform: i32::from,
82        },
83        meteoric_fall: bool {
84            provenance: "Meteoric Fall releases the complete spending state together.",
85            gate: meteoric_fall,
86            source: true,
87            transform: |value| value,
88        },
89        world_killer: bool {
90            provenance: "World Killer replaces the final Voidfall meteor.",
91            gate: world_killer,
92            source: true,
93            transform: |value| value,
94        },
95        meteor_coef: f64 {
96            provenance: "Devourer Voidfall Meteor 1256305 e1 SP coefficient with selected damage talents.",
97            gate: voidfall,
98            source: params.game_data.effect_sp_coefficient(EFFECT::VOIDFALL_METEOR_COEF),
99            transform: |value: f64| value * voidfall_mult,
100        },
101        world_killer_coef: f64 {
102            provenance: "Devourer World Killer 1256619 e1 SP coefficient with selected damage talents.",
103            gate: world_killer,
104            source: params.game_data.effect_sp_coefficient(EFFECT::WORLD_KILLER_COEF),
105            transform: |value: f64| value * voidfall_mult,
106        },
107        world_killer_souls: i32 {
108            provenance: "World Killer 1256353 e4 Lesser Soul Fragments for Devourer.",
109            gate: world_killer,
110            source: params.game_data.require_effect_base_points(EFFECT::WORLD_KILLER_SOULS)?,
111            transform: wowlab_types::numeric::f64_to_i32_saturating_trunc,
112        },
113        catastrophe_pct: f64 {
114            provenance: "Catastrophe 1253769 e1 residual fraction of post-mitigation meteor damage.",
115            gate: catastrophe,
116            source: params.game_data.require_effect_base_points(EFFECT::CATASTROPHE_PCT)?,
117            transform: |value: f64| value / HUNDRED,
118        },
119        mass_acceleration_stacks: i32 {
120            provenance: "Mass Acceleration 1256295 e1 Voidfall stacks on Metamorphosis.",
121            gate: mass_acceleration,
122            source: params.game_data.require_effect_base_points(EFFECT::MASS_ACCELERATION_STACKS)?,
123            transform: wowlab_types::numeric::f64_to_i32_saturating_trunc,
124        },
125        meteoric_rise_stacks: i32 {
126            provenance: "Meteoric Rise grants one Voidfall building stack when Void Ray completes.",
127            gate: meteoric_rise,
128            source: 1,
129            transform: |value| value,
130        },
131    }
132    accessor pub(super) fn devourer_config(ctx);
133    register pub(super) fn register_devourer(built, params) -> Result<(), wowlab_engine_ports::EngineError>;
134    prepare {
135        let voidfall = params.talent_picked(HERO::ANNIHILATOR::SPELL::VOIDFALL);
136        let meteoric_fall = voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::METEORIC_FALL);
137        let world_killer = voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::WORLD_KILLER);
138        let catastrophe = voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::CATASTROPHE);
139        let mass_acceleration = voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::MASS_ACCELERATION);
140        let meteoric_rise = voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::METEORIC_RISE);
141        let harness = try_gated(
142            voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::HARNESS_THE_COSMOS),
143            || Ok::<_, wowlab_engine_ports::EngineError>(params.game_data.require_effect_base_points(EFFECT::HARNESS_THE_COSMOS_PCT)? / HUNDRED),
144        )?;
145        let otherworldly = try_gated(
146            voidfall && params.talent_picked(HERO::ANNIHILATOR::SPELL::OTHERWORLDLY_FOCUS),
147            || Ok::<_, wowlab_engine_ports::EngineError>(params.game_data.require_effect_base_points(EFFECT::OTHERWORLDLY_FOCUS_PCT)? / HUNDRED),
148        )?;
149        let voidfall_mult = (1.0 + harness) * (1.0 + otherworldly);
150    }
151    auras {}
152    wiring {
153        { provenance: "Shattered Souls impact proc registration.", gate: cfg.shattered_souls_chance > 0.0, apply: {
154            built.register_impact_proc(
155                ImpactProc::new(shattered_souls_fire)
156                    .with_chance(cfg.shattered_souls_chance)
157                    .with_spell_filter(shattered_souls_spell_filter),
158            );
159        } },
160        { provenance: "Catastrophe receives post-mitigation Annihilator meteor impacts.", gate: catastrophe, apply: {
161            built.register_impact_proc(
162                ImpactProc::new(catastrophe_impact)
163                    .with_spell_filter(annihilator_meteor_impact)
164                    .skip_periodic(),
165            );
166        } },
167    }
168    finish |cfg| {
169        built.state.set_spec_config(cfg);
170        Ok(())
171    }
172}