wowlab_engine_content/hooks/affliction_warlock/
handler.rs1use wowlab_engine_combat::{
2 CombatHandler, DriverSpellModifier, DriverSpellModifierResult, ResourceGainProc,
3};
4use wowlab_engine_ports::{EngineError, HandlerParams};
5
6use crate::generated::specs::affliction_warlock::{AURA_HAUNT, SET_BONUS, SPELL, TALENT};
7
8static MID2_CORRUPTION_SPELLS: [u32; 3] = [SPELL::CORRUPTION, 146_739, 445_474];
9static MID2_AGONY_SPELLS: [u32; 1] = [SPELL::AGONY];
10static IMPETUOUS_WRATH_SPELLS: [u32; 3] =
11 [SPELL::SHADOW_BOLT, SPELL::DRAIN_SOUL, SPELL::MALEFIC_GRASP];
12static IMPETUOUS_WRATH_DARK_HARVEST: [u32; 1] = [SPELL::DARK_HARVEST];
13
14use super::{
15 config::{affliction_config, AfflictionRuntime},
16 hooks::succulent_soul_proc,
17};
18
19const SUCCULENT_SOUL_RATE: f64 = 0.225;
20#[derive(Debug)]
22pub(crate) struct AfflictionHandler {
23 inner: CombatHandler,
24}
25
26impl AfflictionHandler {
27 pub(crate) fn try_new(
29 parts: crate::composition::ContentHandlerParts,
30 params: &HandlerParams<'_>,
31 ) -> Result<Self, EngineError> {
32 let mut parts = parts;
33 let built = parts.draft_mut();
34 let config = affliction_config(params);
35
36 if config.mid2_2pc {
37 built.register_driver_spell_modifier(DriverSpellModifier::new(
38 SET_BONUS::MID2_AFFLICTION_2PC,
39 &MID2_CORRUPTION_SPELLS,
40 mid2_corruption_modifier,
41 ));
42 built.register_driver_spell_modifier(DriverSpellModifier::new(
43 SET_BONUS::MID2_AFFLICTION_2PC,
44 &MID2_AGONY_SPELLS,
45 mid2_agony_modifier,
46 ));
47 }
48
49 if params.talent_picked(TALENT::IMPETUOUS_WRATH) {
50 built.register_driver_spell_modifier(DriverSpellModifier::new(
51 TALENT::IMPETUOUS_WRATH,
52 &IMPETUOUS_WRATH_SPELLS,
53 impetuous_wrath_modifier,
54 ));
55 built.register_driver_spell_modifier(DriverSpellModifier::new(
56 TALENT::IMPETUOUS_WRATH,
57 &IMPETUOUS_WRATH_DARK_HARVEST,
58 impetuous_wrath_dark_harvest_modifier,
59 ));
60 }
61
62 if params.talent_picked(TALENT::DEMONIC_SOUL) {
63 built.register_resource_gain_proc(
64 ResourceGainProc::prd(SUCCULENT_SOUL_RATE, succulent_soul_proc).per_whole_unit(),
65 );
66 }
67
68 if params.talent_picked(TALENT::SHADOW_OF_NATHREZA_3) {
69 built.bind_system_rppm(
70 wowlab_engine_combat::generated_identities::system_rppm::SHADOW_OF_NATHREZA,
71 TALENT::SHADOW_OF_NATHREZA_3,
72 )?;
73 }
74
75 if let Some(local) = built.spell_local(SPELL::CORRUPTION) {
76 built.patch_spell(local, |spell| {
77 spell.requirements.exclude_caster_aura_spell = 0;
79 });
80 }
81
82 built.set_spec_config(config);
83 built.set_spec_runtime(AfflictionRuntime::default());
84
85 let built = parts.finalize()?;
86
87 Ok(Self {
88 inner: CombatHandler::from_built(built),
89 })
90 }
91}
92
93fn mid2_corruption_modifier(view: wowlab_engine_combat::HookView<'_>) -> DriverSpellModifierResult {
94 DriverSpellModifierResult::damage_mult(
95 view.program()
96 .spec_config::<super::config::AfflictionConfig>()
97 .map_or(1.0, |cfg| cfg.mid2_corruption_mult),
98 )
99}
100
101fn mid2_agony_modifier(view: wowlab_engine_combat::HookView<'_>) -> DriverSpellModifierResult {
102 DriverSpellModifierResult::damage_mult(
103 view.program()
104 .spec_config::<super::config::AfflictionConfig>()
105 .map_or(1.0, |cfg| cfg.mid2_agony_mult),
106 )
107}
108
109fn impetuous_wrath_modifier(view: wowlab_engine_combat::HookView<'_>) -> DriverSpellModifierResult {
110 let Some(cfg) = view
111 .program()
112 .spec_config::<super::config::AfflictionConfig>()
113 else {
114 return DriverSpellModifierResult::default();
115 };
116 let haunted = wowlab_engine_combat::is_aura_active(
117 &view.combat(),
118 AURA_HAUNT,
119 wowlab_types::sim::ActorId::Player,
120 view.target,
121 );
122
123 DriverSpellModifierResult::damage_mult(if haunted {
124 cfg.impetuous_haunt_mult
125 } else {
126 cfg.impetuous_normal_mult
127 })
128}
129
130fn impetuous_wrath_dark_harvest_modifier(
131 view: wowlab_engine_combat::HookView<'_>,
132) -> DriverSpellModifierResult {
133 let Some(cfg) = view
134 .program()
135 .spec_config::<super::config::AfflictionConfig>()
136 else {
137 return DriverSpellModifierResult::default();
138 };
139 let haunted = wowlab_engine_combat::is_aura_active(
140 &view.combat(),
141 AURA_HAUNT,
142 wowlab_types::sim::ActorId::Player,
143 view.target,
144 );
145
146 DriverSpellModifierResult::damage_mult(if haunted {
147 cfg.impetuous_dark_harvest_haunt_mult
148 } else {
149 cfg.impetuous_dark_harvest_mult
150 })
151}
152
153crate::hooks::define_spec_handler! {
154impl AfflictionHandler(self, inner) {
155 fn on_sim_start(&mut self, ctx: &mut wowlab_engine_ports::SimContext) {
156 self.inner.on_sim_start(ctx);
157 }
158}
159}