1#![allow(non_snake_case, dead_code)]
4use wowlab_types::{combat::ResourceType, game::SpecId};
5use wowlab_engine_combat::{
6 BuiltCombatSystem, AuraDefinitionDraft, LocalAuraIdx, LocalSpellIdx,
7 SpellDefinitionDraft,
8};
9use wowlab_engine_ports::{
10 DeclaredSpecMetadata, SpecDescriptor, SpecHandler, HeroTalentTreeDesc,
11};
12use wowlab_engine_gamedata::ResolvedGameData;
13pub(crate) mod SPELL {
14 pub(crate) const SHADOW_BOLT: u32 = 686;
16 pub(crate) const DEMONBOLT: u32 = 264_178;
18 pub(crate) const HAND_OF_GULDAN: u32 = 105_174;
20 pub(crate) const POWER_SIPHON: u32 = 264_130;
22 pub(crate) const DRAIN_LIFE: u32 = 234_153;
24 pub(crate) const SUMMON_FELGUARD: u32 = 30146;
26 pub(crate) const SUMMON_FELHUNTER: u32 = 691;
28 pub(crate) const SUMMON_IMP: u32 = 688;
30 pub(crate) const CALL_DREADSTALKERS: u32 = 104_316;
32 pub(crate) const SUMMON_DEMONIC_TYRANT: u32 = 265_187;
34 pub(crate) const SUMMON_VILEFIEND: u32 = 264_119;
36 pub(crate) const IMPLOSION: u32 = 196_277;
38 pub(crate) const GRIMOIRE_IMP_LORD: u32 = 1_276_452;
40 pub(crate) const GRIMOIRE_FEL_RAVAGER: u32 = 1_276_467;
42 pub(crate) const SUMMON_DOOMGUARD: u32 = 1_276_672;
44 pub(crate) const INFERNAL_BOLT: u32 = 434_506;
46 pub(crate) const RUINATION: u32 = 434_635;
48}
49pub(crate) mod AURA {
50 pub(crate) const DEMONIC_CORE: u32 = 264_173;
52 pub(crate) const CARNIVOROUS_STALKERS_TALENT: u32 = 386_194;
54 pub(crate) const POWER_SIPHON: u32 = 334_581;
56 pub(crate) const DOOM: u32 = 460_553;
58 pub(crate) const TYRANTS_OBLATION: u32 = 1_276_767;
60 pub(crate) const HELLBENT_COMMANDER: u32 = 1_281_559;
62 pub(crate) const INNER_DEMONS: u32 = 267_216;
64 pub(crate) const DOMINION_OF_ARGUS: u32 = 1_276_166;
66 pub(crate) const SUCCULENT_SOUL: u32 = 449_793;
68 pub(crate) const MANIFESTED_DEMONIC_SOUL: u32 = 1_269_042;
70 pub(crate) const GRIMOIRE_OF_SACRIFICE: u32 = 196_099;
72 pub(crate) const WILD_IMPS: u32 = 104_317;
74 pub(crate) const DREADSTALKERS: u32 = 193_332;
76 pub(crate) const TRACK_PETS: u32 = 462_599;
78 pub(crate) const FLAMETOUCHED_TALENT: u32 = 453_699;
80 pub(crate) const INFERNAL_BOLT: u32 = 433_891;
82 pub(crate) const RUINATION: u32 = 433_885;
84 pub(crate) const DIABOLIC_RITUAL_TALENT: u32 = 428_514;
86 pub(crate) const DIABOLIC_RITUAL_OVERLORD: u32 = 431_944;
88 pub(crate) const DIABOLIC_RITUAL_MOTHER: u32 = 432_815;
90 pub(crate) const DIABOLIC_RITUAL_PIT_LORD: u32 = 432_816;
92 pub(crate) const DEMONIC_ART_OVERLORD: u32 = 428_524;
94 pub(crate) const DEMONIC_ART_MOTHER: u32 = 432_794;
96 pub(crate) const DEMONIC_ART_PIT_LORD: u32 = 432_795;
98 pub(crate) const DEMONIC_OCULI: u32 = 1_269_643;
100 pub(crate) const DIABOLIC_OCULI_TALENT: u32 = 1_268_709;
102 pub(crate) const LOOKS_THAT_KILL_TALENT: u32 = 1_268_713;
104 pub(crate) const MINDS_EYES_TALENT: u32 = 1_268_716;
106 pub(crate) const MINDS_EYES: u32 = 1_269_879;
108 pub(crate) const ABYSSAL_DOMINION: u32 = 456_323;
110 pub(crate) const ABYSSAL_DOMINION_TALENT: u32 = 429_581;
112 pub(crate) const CLOVEN_SOUL: u32 = 434_424;
114}
115pub(crate) mod TALENT {
116 pub(crate) const ABYSSAL_DOMINION_TALENT: u32 = 429_581;
118 pub(crate) const ANTORAN_ARMAMENTS: u32 = 1_250_921;
120 pub(crate) const BLIGHTED_MAW: u32 = 1_276_956;
122 pub(crate) const CALL_DREADSTALKERS: u32 = 104_316;
124 pub(crate) const CARNIVOROUS_STALKERS: u32 = 386_194;
126 pub(crate) const DEMONIAC: u32 = 426_115;
128 pub(crate) const DEMONIC_BRUTALITY: u32 = 453_908;
130 pub(crate) const DEMONIC_CALLING: u32 = 1_276_947;
132 pub(crate) const DEMONIC_KNOWLEDGE: u32 = 386_185;
134 pub(crate) const DIABOLIC_OCULI: u32 = 1_268_709;
136 pub(crate) const DIABOLIC_RITUAL: u32 = 428_514;
138 pub(crate) const DOMINION_OF_ARGUS: u32 = 1_276_163;
140 pub(crate) const DOMINION_OF_ARGUS_2: u32 = 1_276_190;
142 pub(crate) const DOMINION_OF_ARGUS_3: u32 = 1_276_222;
144 pub(crate) const DOOM: u32 = 460_551;
146 pub(crate) const DREADLASH: u32 = 264_078;
148 pub(crate) const FLAMETOUCHED: u32 = 453_699;
150 pub(crate) const GLOOM_OF_NATHREZA: u32 = 429_899;
152 pub(crate) const GRIMOIRE_FEL_RAVAGER: u32 = 1_276_467;
154 pub(crate) const GRIMOIRE_IMP_LORD: u32 = 1_276_452;
156 pub(crate) const HAND_OF_GULDAN: u32 = 1_250_273;
158 pub(crate) const HELLBENT_COMMANDER: u32 = 1_250_897;
160 pub(crate) const IMPLOSION: u32 = 196_277;
162 pub(crate) const IMP_GANG_BOSS: u32 = 1_250_768;
164 pub(crate) const INFERNAL_RAPIDITY: u32 = 1_263_941;
166 pub(crate) const INNER_DEMONS: u32 = 267_216;
168 pub(crate) const LOOKS_THAT_KILL: u32 = 1_268_713;
170 pub(crate) const MARK_OF_SHATUG: u32 = 455_449;
172 pub(crate) const MINDS_EYES: u32 = 1_268_716;
174 pub(crate) const POWER_SIPHON: u32 = 264_130;
176 pub(crate) const REIGN_OF_TYRANNY: u32 = 1_276_748;
178 pub(crate) const SACRIFICED_SOULS: u32 = 267_214;
180 pub(crate) const SPITEFUL_RECONSTITUTION: u32 = 428_394;
182 pub(crate) const SUMMON_DEMONIC_TYRANT: u32 = 265_187;
184 pub(crate) const SUMMON_DOOMGUARD: u32 = 1_276_672;
186 pub(crate) const SUMMON_VILEFIEND: u32 = 1_251_778;
188 pub(crate) const SUMMON_VILEFIEND_CASTABLE: u32 = 264_119;
190 pub(crate) const TO_HELL_AND_BACK: u32 = 1_281_511;
192 pub(crate) const TYRANTS_OBLATION: u32 = 1_276_746;
194}
195pub(crate) mod SET_BONUS {
196 pub(crate) const MID1_DEMONOLOGY_4PC: u32 = 1_264_872;
198}
199pub(crate) mod REPORTED_SPELL {
200 pub(crate) const ANTORAN_INQUISITOR: u32 = 1_276_283;
202 pub(crate) const ANTORAN_JAILER: u32 = 1_276_182;
204 pub(crate) const BILE_SPIT: u32 = 267_997;
206 pub(crate) const BLAZE_MISSILE: u32 = 1_282_534;
208 pub(crate) const BLIGHTED_MAW: u32 = 1_276_960;
210 pub(crate) const BURNING_CLEAVE: u32 = 1_264_093;
212 pub(crate) const CHAOS_SALVO: u32 = 432_596;
214 pub(crate) const DIABOLIC_GAZE_1: u32 = 1_269_892;
216 pub(crate) const DIABOLIC_GAZE_2: u32 = 1_269_886;
218 pub(crate) const DIABOLIC_GAZE_3: u32 = 1_269_885;
220 pub(crate) const DREADBITE: u32 = 271_971;
222 pub(crate) const DREADSTALKER_MELEE: u32 = 193_332;
224 pub(crate) const EYE_EXPLOSION: u32 = 1_269_800;
226 pub(crate) const FELSEEKER: u32 = 434_404;
228 pub(crate) const FELSTORM: u32 = 89753;
230 pub(crate) const FEL_FIREBOLT: u32 = 104_318;
232 pub(crate) const GLOOM_SLASH: u32 = 455_491;
234 pub(crate) const GRAND_WARLOCK_ALYTHESS: u32 = 1_282_502;
236 pub(crate) const HAND_OF_GULDAN_IMPACT: u32 = 86040;
238 pub(crate) const HEADBUTT: u32 = 267_999;
240 pub(crate) const LADY_SACROLASH: u32 = 1_282_501;
242 pub(crate) const LEGION_STRIKE: u32 = 30213;
244 pub(crate) const MIND_SEAR_CHANNEL: u32 = 1_280_460;
246 pub(crate) const SHADOW_NOVA: u32 = 1_282_507;
248 pub(crate) const SOUL_BARRAGE_CAST: u32 = 1_292_391;
250 pub(crate) const UNSTABLE_GANG_BOSS: u32 = 1_281_512;
252 pub(crate) const VILEFIEND: u32 = 1_251_781;
254 pub(crate) const WICKED_CLEAVE: u32 = 432_120;
256}
257pub(crate) mod HERO {
258 pub(crate) mod SOUL_HARVESTER {
259 pub(crate) mod SPELL {
260 pub(crate) const DEMONIC_SOUL_DAMAGE: u32 = 449_801;
262 pub(crate) const SHADOW_OF_DEATH_ENERGIZE: u32 = 449_858;
264 pub(crate) const SHARED_FATE: u32 = 450_591;
266 pub(crate) const SOUL_ANATHEMA: u32 = 450_538;
268 pub(crate) const WICKED_REAPING: u32 = 449_826;
270 }
271 pub(crate) mod AURA {
272 pub(crate) const MANIFESTED_DEMONIC_SOUL: u32 = 1_269_042;
274 pub(crate) const SUCCULENT_SOUL: u32 = 449_793;
276 }
277 }
278 pub(crate) mod DIABOLIST {
279 pub(crate) mod SPELL {
280 pub(crate) const INFERNAL_BOLT: u32 = 434_506;
282 pub(crate) const RUINATION: u32 = 434_635;
284 pub(crate) const RUINATION_IMPACT: u32 = 434_636;
286 }
287 pub(crate) mod AURA {
288 pub(crate) const ABYSSAL_DOMINION: u32 = 456_323;
290 pub(crate) const CLOVEN_SOUL: u32 = 434_424;
292 pub(crate) const DEMONIC_ART_MOTHER: u32 = 432_794;
294 pub(crate) const DEMONIC_ART_OVERLORD: u32 = 428_524;
296 pub(crate) const DEMONIC_ART_PIT_LORD: u32 = 432_795;
298 pub(crate) const DEMONIC_OCULI: u32 = 1_269_643;
300 pub(crate) const DIABOLIC_RITUAL_MOTHER: u32 = 432_815;
302 pub(crate) const DIABOLIC_RITUAL_OVERLORD: u32 = 431_944;
304 pub(crate) const DIABOLIC_RITUAL_PIT_LORD: u32 = 432_816;
306 pub(crate) const INFERNAL_BOLT_BUFF: u32 = 433_891;
308 pub(crate) const MINDS_EYES: u32 = 1_269_879;
310 pub(crate) const RUINATION_BUFF: u32 = 433_885;
312 }
313 }
314}
315static HERO_TREE_SOUL_HARVESTER_SPELLS: &[(&str, u32)] = &[
316 ("DEMONIC_SOUL_DAMAGE", 449_801),
317 ("SHADOW_OF_DEATH_ENERGIZE", 449_858),
318 ("SHARED_FATE", 450_591),
319 ("SOUL_ANATHEMA", 450_538),
320 ("WICKED_REAPING", 449_826),
321];
322static HERO_TREE_SOUL_HARVESTER_AURAS: &[(&str, u32)] = &[
323 ("MANIFESTED_DEMONIC_SOUL", 1_269_042),
324 ("SUCCULENT_SOUL", 449_793),
325];
326static HERO_TREE_DIABOLIST_SPELLS: &[(&str, u32)] = &[
327 ("INFERNAL_BOLT", 434_506),
328 ("RUINATION", 434_635),
329 ("RUINATION_IMPACT", 434_636),
330];
331static HERO_TREE_DIABOLIST_AURAS: &[(&str, u32)] = &[
332 ("ABYSSAL_DOMINION", 456_323),
333 ("CLOVEN_SOUL", 434_424),
334 ("DEMONIC_ART_MOTHER", 432_794),
335 ("DEMONIC_ART_OVERLORD", 428_524),
336 ("DEMONIC_ART_PIT_LORD", 432_795),
337 ("DEMONIC_OCULI", 1_269_643),
338 ("DIABOLIC_RITUAL_MOTHER", 432_815),
339 ("DIABOLIC_RITUAL_OVERLORD", 431_944),
340 ("DIABOLIC_RITUAL_PIT_LORD", 432_816),
341 ("INFERNAL_BOLT_BUFF", 433_891),
342 ("MINDS_EYES", 1_269_879),
343 ("RUINATION_BUFF", 433_885),
344];
345pub(crate) const AURA_DEMONIC_CORE: LocalAuraIdx = LocalAuraIdx::new(0);
346pub(crate) const AURA_CARNIVOROUS_STALKERS_TALENT: LocalAuraIdx = LocalAuraIdx::new(1);
347pub(crate) const AURA_POWER_SIPHON: LocalAuraIdx = LocalAuraIdx::new(2);
348pub(crate) const AURA_DOOM: LocalAuraIdx = LocalAuraIdx::new(3);
349pub(crate) const AURA_TYRANTS_OBLATION: LocalAuraIdx = LocalAuraIdx::new(4);
350pub(crate) const AURA_HELLBENT_COMMANDER: LocalAuraIdx = LocalAuraIdx::new(5);
351pub(crate) const AURA_INNER_DEMONS: LocalAuraIdx = LocalAuraIdx::new(6);
352pub(crate) const AURA_DOMINION_OF_ARGUS: LocalAuraIdx = LocalAuraIdx::new(7);
353pub(crate) const AURA_SUCCULENT_SOUL: LocalAuraIdx = LocalAuraIdx::new(8);
354pub(crate) const AURA_MANIFESTED_DEMONIC_SOUL: LocalAuraIdx = LocalAuraIdx::new(9);
355pub(crate) const AURA_GRIMOIRE_OF_SACRIFICE: LocalAuraIdx = LocalAuraIdx::new(10);
356pub(crate) const AURA_WILD_IMPS: LocalAuraIdx = LocalAuraIdx::new(11);
357pub(crate) const AURA_DREADSTALKERS: LocalAuraIdx = LocalAuraIdx::new(12);
358pub(crate) const AURA_TRACK_PETS: LocalAuraIdx = LocalAuraIdx::new(13);
359pub(crate) const AURA_FLAMETOUCHED_TALENT: LocalAuraIdx = LocalAuraIdx::new(14);
360pub(crate) const AURA_INFERNAL_BOLT: LocalAuraIdx = LocalAuraIdx::new(15);
361pub(crate) const AURA_RUINATION: LocalAuraIdx = LocalAuraIdx::new(16);
362pub(crate) const AURA_DIABOLIC_RITUAL_TALENT: LocalAuraIdx = LocalAuraIdx::new(17);
363pub(crate) const AURA_DIABOLIC_RITUAL_OVERLORD: LocalAuraIdx = LocalAuraIdx::new(18);
364pub(crate) const AURA_DIABOLIC_RITUAL_MOTHER: LocalAuraIdx = LocalAuraIdx::new(19);
365pub(crate) const AURA_DIABOLIC_RITUAL_PIT_LORD: LocalAuraIdx = LocalAuraIdx::new(20);
366pub(crate) const AURA_DEMONIC_ART_OVERLORD: LocalAuraIdx = LocalAuraIdx::new(21);
367pub(crate) const AURA_DEMONIC_ART_MOTHER: LocalAuraIdx = LocalAuraIdx::new(22);
368pub(crate) const AURA_DEMONIC_ART_PIT_LORD: LocalAuraIdx = LocalAuraIdx::new(23);
369pub(crate) const AURA_DEMONIC_OCULI: LocalAuraIdx = LocalAuraIdx::new(24);
370pub(crate) const AURA_DIABOLIC_OCULI_TALENT: LocalAuraIdx = LocalAuraIdx::new(25);
371pub(crate) const AURA_LOOKS_THAT_KILL_TALENT: LocalAuraIdx = LocalAuraIdx::new(26);
372pub(crate) const AURA_MINDS_EYES_TALENT: LocalAuraIdx = LocalAuraIdx::new(27);
373pub(crate) const AURA_MINDS_EYES: LocalAuraIdx = LocalAuraIdx::new(28);
374pub(crate) const AURA_ABYSSAL_DOMINION: LocalAuraIdx = LocalAuraIdx::new(29);
375pub(crate) const AURA_ABYSSAL_DOMINION_TALENT: LocalAuraIdx = LocalAuraIdx::new(30);
376pub(crate) const AURA_CLOVEN_SOUL: LocalAuraIdx = LocalAuraIdx::new(31);
377pub(crate) const AURA_COUNT: usize = 32;
378const _: () = assert!(
379 AURA_COUNT == 32, "AURA index ABI: count changed -- update positional hook consumers"
380);
381pub(crate) const SPELL_SHADOW_BOLT: LocalSpellIdx = LocalSpellIdx::new(0);
382pub(crate) const SPELL_DEMONBOLT: LocalSpellIdx = LocalSpellIdx::new(1);
383pub(crate) const SPELL_HAND_OF_GULDAN: LocalSpellIdx = LocalSpellIdx::new(2);
384pub(crate) const SPELL_POWER_SIPHON: LocalSpellIdx = LocalSpellIdx::new(3);
385pub(crate) const SPELL_DRAIN_LIFE: LocalSpellIdx = LocalSpellIdx::new(4);
386pub(crate) const SPELL_SUMMON_FELGUARD: LocalSpellIdx = LocalSpellIdx::new(5);
387pub(crate) const SPELL_SUMMON_FELHUNTER: LocalSpellIdx = LocalSpellIdx::new(6);
388pub(crate) const SPELL_SUMMON_IMP: LocalSpellIdx = LocalSpellIdx::new(7);
389pub(crate) const SPELL_CALL_DREADSTALKERS: LocalSpellIdx = LocalSpellIdx::new(8);
390pub(crate) const SPELL_SUMMON_DEMONIC_TYRANT: LocalSpellIdx = LocalSpellIdx::new(9);
391pub(crate) const SPELL_SUMMON_VILEFIEND: LocalSpellIdx = LocalSpellIdx::new(10);
392pub(crate) const SPELL_IMPLOSION: LocalSpellIdx = LocalSpellIdx::new(11);
393pub(crate) const SPELL_GRIMOIRE_IMP_LORD: LocalSpellIdx = LocalSpellIdx::new(12);
394pub(crate) const SPELL_GRIMOIRE_FEL_RAVAGER: LocalSpellIdx = LocalSpellIdx::new(13);
395pub(crate) const SPELL_SUMMON_DOOMGUARD: LocalSpellIdx = LocalSpellIdx::new(14);
396pub(crate) const SPELL_INFERNAL_BOLT: LocalSpellIdx = LocalSpellIdx::new(15);
397pub(crate) const SPELL_RUINATION: LocalSpellIdx = LocalSpellIdx::new(16);
398pub(crate) const SPELL_COUNT: usize = 17;
399const _: () = assert!(
400 SPELL_COUNT == 17,
401 "SPELL index ABI: count changed -- update positional hook consumers"
402);
403pub(crate) mod EFFECT {
404 pub(crate) const BURNING_CLEAVE: (u32, u8) = (1_264_093, 1);
406 pub(crate) const FEL_FIREBOLT_DAMAGE: (u32, u8) = (104_318, 1);
408 pub(crate) const SHADOW_NOVA_DAMAGE: (u32, u8) = (1_282_507, 1);
410 pub(crate) const BLAZE_MISSILE_DAMAGE: (u32, u8) = (1_282_534, 1);
412 pub(crate) const MIND_SEAR_DAMAGE: (u32, u8) = (1_280_460, 2);
414 pub(crate) const SOUL_BARRAGE_DAMAGE: (u32, u8) = (1_292_391, 1);
416 pub(crate) const HAND_OF_GULDAN_IMPACT_DAMAGE: (u32, u8) = (86040, 1);
418 pub(crate) const BILE_SPIT_DIRECT_DAMAGE: (u32, u8) = (267_997, 1);
420 pub(crate) const BILE_SPIT_TICK_DAMAGE: (u32, u8) = (267_997, 2);
422 pub(crate) const HEADBUTT_DAMAGE: (u32, u8) = (267_999, 1);
424 pub(crate) const GLOOM_SLASH_DAMAGE: (u32, u8) = (455_491, 1);
426 pub(crate) const LEGION_STRIKE_DAMAGE: (u32, u8) = (30213, 1);
428 pub(crate) const FELSTORM_DAMAGE: (u32, u8) = (89753, 1);
430 pub(crate) const DREADBITE_DAMAGE: (u32, u8) = (271_971, 1);
432 pub(crate) const DEMONIC_CORE_IMP_CHANCE: (u32, u8) = (267_102, 1);
434 pub(crate) const WICKED_CLEAVE_DAMAGE: (u32, u8) = (432_120, 1);
436 pub(crate) const CHAOS_SALVO_DAMAGE: (u32, u8) = (432_596, 1);
438 pub(crate) const FELSEEKER_DAMAGE: (u32, u8) = (434_404, 1);
440 pub(crate) const EYE_EXPLOSION_DAMAGE: (u32, u8) = (1_269_800, 1);
442 pub(crate) const DIABOLIC_GAZE_1_DAMAGE: (u32, u8) = (1_269_892, 1);
444 pub(crate) const DIABOLIC_GAZE_2_DAMAGE: (u32, u8) = (1_269_886, 1);
446 pub(crate) const DIABOLIC_GAZE_3_DAMAGE: (u32, u8) = (1_269_885, 1);
448}
449static REPORTED_SPELLS: &[(&str, u32)] = &[
450 ("antoran_inquisitor", 1_276_283),
451 ("antoran_jailer", 1_276_182),
452 ("bile_spit", 267_997),
453 ("blaze_missile", 1_282_534),
454 ("blighted_maw", 1_276_960),
455 ("burning_cleave", 1_264_093),
456 ("chaos_salvo", 432_596),
457 ("diabolic_gaze_1", 1_269_892),
458 ("diabolic_gaze_2", 1_269_886),
459 ("diabolic_gaze_3", 1_269_885),
460 ("dreadbite", 271_971),
461 ("dreadstalker_melee", 193_332),
462 ("eye_explosion", 1_269_800),
463 ("felseeker", 434_404),
464 ("felstorm", 89753),
465 ("fel_firebolt", 104_318),
466 ("gloom_slash", 455_491),
467 ("grand_warlock_alythess", 1_282_502),
468 ("hand_of_guldan_impact", 86040),
469 ("headbutt", 267_999),
470 ("lady_sacrolash", 1_282_501),
471 ("legion_strike", 30213),
472 ("mind_sear_channel", 1_280_460),
473 ("shadow_nova", 1_282_507),
474 ("soul_barrage_cast", 1_292_391),
475 ("unstable_gang_boss", 1_281_512),
476 ("vilefiend", 1_251_781),
477 ("wicked_cleave", 432_120),
478];
479static DECLARED_SPELL_IDS: &[u32] = &[
480 686, 264_178, 105_174, 264_130, 234_153, 30146, 691, 688, 104_316, 265_187, 264_119,
481 196_277, 1_276_452, 1_276_467, 1_276_672, 434_506, 434_635, 264_173, 386_194,
482 334_581, 460_553, 1_276_767, 1_281_559, 267_216, 1_276_166, 449_793, 1_269_042,
483 196_099, 104_317, 193_332, 462_599, 453_699, 433_891, 433_885, 428_514, 431_944,
484 432_815, 432_816, 428_524, 432_794, 432_795, 1_269_643, 1_268_709, 1_268_713,
485 1_268_716, 1_269_879, 456_323, 429_581, 434_424, 1, 30213, 77219, 86040, 89753,
486 104_318, 193_332, 267_102, 267_997, 267_999, 271_971, 432_120, 432_596, 434_404,
487 434_506, 455_491, 456_323, 1_251_781, 1_264_093, 1_269_800, 1_269_879, 1_269_885,
488 1_269_886, 1_269_892, 1_276_182, 1_276_283, 1_276_960, 1_280_460, 1_281_512,
489 1_282_501, 1_282_502, 1_282_507, 1_282_534, 1_292_391, 1_276_283, 1_276_182, 267_997,
490 1_282_534, 1_276_960, 1_264_093, 432_596, 1_269_892, 1_269_886, 1_269_885, 271_971,
491 193_332, 1_269_800, 434_404, 89753, 104_318, 455_491, 1_282_502, 86040, 267_999,
492 1_282_501, 30213, 1_280_460, 1_282_507, 1_292_391, 1_281_512, 1_251_781, 432_120,
493 449_801, 449_858, 450_591, 450_538, 449_826, 1_269_042, 449_793, 434_506, 434_635,
494 434_636, 456_323, 434_424, 432_794, 428_524, 432_795, 1_269_643, 432_815, 431_944,
495 432_816, 433_891, 1_269_879, 433_885,
496];
497static DECLARED_AURA_IDS: &[u32] = &[
498 264_173, 386_194, 334_581, 460_553, 1_276_767, 1_281_559, 267_216, 1_276_166,
499 449_793, 1_269_042, 196_099, 104_317, 193_332, 462_599, 453_699, 433_891, 433_885,
500 428_514, 431_944, 432_815, 432_816, 428_524, 432_794, 432_795, 1_269_643, 1_268_709,
501 1_268_713, 1_268_716, 1_269_879, 456_323, 429_581, 434_424, 1_269_042, 449_793,
502 456_323, 434_424, 432_794, 428_524, 432_795, 1_269_643, 432_815, 431_944, 432_816,
503 433_891, 1_269_879, 433_885,
504];
505static TALENTS: &[(&str, u32)] = &[
506 ("ABYSSAL_DOMINION_TALENT", TALENT::ABYSSAL_DOMINION_TALENT),
507 ("ANTORAN_ARMAMENTS", TALENT::ANTORAN_ARMAMENTS),
508 ("BLIGHTED_MAW", TALENT::BLIGHTED_MAW),
509 ("CALL_DREADSTALKERS", TALENT::CALL_DREADSTALKERS),
510 ("CARNIVOROUS_STALKERS", TALENT::CARNIVOROUS_STALKERS),
511 ("DEMONIAC", TALENT::DEMONIAC),
512 ("DEMONIC_BRUTALITY", TALENT::DEMONIC_BRUTALITY),
513 ("DEMONIC_CALLING", TALENT::DEMONIC_CALLING),
514 ("DEMONIC_KNOWLEDGE", TALENT::DEMONIC_KNOWLEDGE),
515 ("DIABOLIC_OCULI", TALENT::DIABOLIC_OCULI),
516 ("DIABOLIC_RITUAL", TALENT::DIABOLIC_RITUAL),
517 ("DOMINION_OF_ARGUS", TALENT::DOMINION_OF_ARGUS),
518 ("DOMINION_OF_ARGUS_2", TALENT::DOMINION_OF_ARGUS_2),
519 ("DOMINION_OF_ARGUS_3", TALENT::DOMINION_OF_ARGUS_3),
520 ("DOOM", TALENT::DOOM),
521 ("DREADLASH", TALENT::DREADLASH),
522 ("FLAMETOUCHED", TALENT::FLAMETOUCHED),
523 ("GLOOM_OF_NATHREZA", TALENT::GLOOM_OF_NATHREZA),
524 ("GRIMOIRE_FEL_RAVAGER", TALENT::GRIMOIRE_FEL_RAVAGER),
525 ("GRIMOIRE_IMP_LORD", TALENT::GRIMOIRE_IMP_LORD),
526 ("HAND_OF_GULDAN", TALENT::HAND_OF_GULDAN),
527 ("HELLBENT_COMMANDER", TALENT::HELLBENT_COMMANDER),
528 ("IMPLOSION", TALENT::IMPLOSION),
529 ("IMP_GANG_BOSS", TALENT::IMP_GANG_BOSS),
530 ("INFERNAL_RAPIDITY", TALENT::INFERNAL_RAPIDITY),
531 ("INNER_DEMONS", TALENT::INNER_DEMONS),
532 ("LOOKS_THAT_KILL", TALENT::LOOKS_THAT_KILL),
533 ("MARK_OF_SHATUG", TALENT::MARK_OF_SHATUG),
534 ("MINDS_EYES", TALENT::MINDS_EYES),
535 ("POWER_SIPHON", TALENT::POWER_SIPHON),
536 ("REIGN_OF_TYRANNY", TALENT::REIGN_OF_TYRANNY),
537 ("SACRIFICED_SOULS", TALENT::SACRIFICED_SOULS),
538 ("SPITEFUL_RECONSTITUTION", TALENT::SPITEFUL_RECONSTITUTION),
539 ("SUMMON_DEMONIC_TYRANT", TALENT::SUMMON_DEMONIC_TYRANT),
540 ("SUMMON_DOOMGUARD", TALENT::SUMMON_DOOMGUARD),
541 ("SUMMON_VILEFIEND", TALENT::SUMMON_VILEFIEND),
542 ("SUMMON_VILEFIEND_CASTABLE", TALENT::SUMMON_VILEFIEND_CASTABLE),
543 ("TO_HELL_AND_BACK", TALENT::TO_HELL_AND_BACK),
544 ("TYRANTS_OBLATION", TALENT::TYRANTS_OBLATION),
545];
546pub(crate) mod DEMONOLOGY_WARLOCK {
547 pub(crate) const SHADOW_BOLT_CASTS: u32 = 0;
548 pub(crate) const DEMONBOLT_CASTS: u32 = 1;
549 pub(crate) const HAND_OF_GULDAN_CASTS: u32 = 2;
550 pub(crate) const CALL_DREADSTALKERS_CASTS: u32 = 3;
551 pub(crate) const SUMMON_DEMONIC_TYRANT_CASTS: u32 = 4;
552 pub(crate) const POWER_SIPHON_CASTS: u32 = 5;
553 pub(crate) const DEMONIC_CORE_UPTIME_MS: u32 = 6;
554 pub(crate) const TYRANT_UPTIME_MS: u32 = 7;
555}
556fn aura_demonic_core(
557 a: AuraDefinitionDraft,
558 data: &ResolvedGameData,
559) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
560 Ok(
561 a
562 .on_player()
563 .apply_base_from_data(data, 264_173)?
564 .max_stacks(
565 data
566 .require_aura_max_stacks(
567 wowlab_types::sim::SpellIdx::from_raw(264_173),
568 )?,
569 ),
570 )
571}
572fn aura_carnivorous_stalkers_talent(
573 a: AuraDefinitionDraft,
574 data: &ResolvedGameData,
575) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
576 Ok(
577 a
578 .on_player()
579 .apply_base_from_data(data, 386_194)?
580 .max_stacks(
581 data
582 .require_aura_max_stacks(
583 wowlab_types::sim::SpellIdx::from_raw(386_194),
584 )?,
585 ),
586 )
587}
588fn aura_power_siphon(
589 a: AuraDefinitionDraft,
590 data: &ResolvedGameData,
591) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
592 a.on_player()
593 .apply_base_from_data(data, 334_581)?
594 .max_stacks(
595 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(334_581))?,
596 )
597 .damage_percent_spells_linear(30.0, &[264_178])
598}
599fn aura_doom(
600 a: AuraDefinitionDraft,
601 data: &ResolvedGameData,
602) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
603 Ok(
604 a
605 .on_target()
606 .apply_base_from_data(data, 460_553)?
607 .max_stacks(
608 data
609 .require_aura_max_stacks(
610 wowlab_types::sim::SpellIdx::from_raw(460_553),
611 )?,
612 ),
613 )
614}
615fn aura_tyrants_oblation(
616 a: AuraDefinitionDraft,
617 data: &ResolvedGameData,
618) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
619 Ok(
620 a
621 .on_player()
622 .apply_base_from_data(data, 1_276_767)?
623 .max_stacks(
624 data
625 .require_aura_max_stacks(
626 wowlab_types::sim::SpellIdx::from_raw(1_276_767),
627 )?,
628 ),
629 )
630}
631fn aura_hellbent_commander(
632 a: AuraDefinitionDraft,
633 data: &ResolvedGameData,
634) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
635 Ok(
636 a
637 .on_player()
638 .apply_base_from_data(data, 1_281_559)?
639 .max_stacks(
640 data
641 .require_aura_max_stacks(
642 wowlab_types::sim::SpellIdx::from_raw(1_281_559),
643 )?,
644 ),
645 )
646}
647fn aura_inner_demons(
648 a: AuraDefinitionDraft,
649 data: &ResolvedGameData,
650) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
651 Ok(
652 a
653 .on_player()
654 .apply_base_from_data(data, 267_216)?
655 .max_stacks(
656 data
657 .require_aura_max_stacks(
658 wowlab_types::sim::SpellIdx::from_raw(267_216),
659 )?,
660 ),
661 )
662}
663fn aura_dominion_of_argus(
664 a: AuraDefinitionDraft,
665 data: &ResolvedGameData,
666) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
667 Ok(
668 a
669 .on_player()
670 .apply_base_from_data(data, 1_276_166)?
671 .max_stacks(
672 data
673 .require_aura_max_stacks(
674 wowlab_types::sim::SpellIdx::from_raw(1_276_166),
675 )?,
676 ),
677 )
678}
679fn aura_succulent_soul(
680 a: AuraDefinitionDraft,
681 data: &ResolvedGameData,
682) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
683 Ok(
684 a
685 .on_player()
686 .apply_base_from_data(data, 449_793)?
687 .max_stacks(
688 data
689 .require_aura_max_stacks(
690 wowlab_types::sim::SpellIdx::from_raw(449_793),
691 )?,
692 ),
693 )
694}
695fn aura_manifested_demonic_soul(
696 a: AuraDefinitionDraft,
697 data: &ResolvedGameData,
698) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
699 Ok(
700 a
701 .on_player()
702 .apply_base_from_data(data, 1_269_042)?
703 .max_stacks(
704 data
705 .require_aura_max_stacks(
706 wowlab_types::sim::SpellIdx::from_raw(1_269_042),
707 )?,
708 ),
709 )
710}
711fn aura_grimoire_of_sacrifice(
712 a: AuraDefinitionDraft,
713 data: &ResolvedGameData,
714) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
715 Ok(
716 a
717 .on_player()
718 .apply_base_from_data(data, 196_099)?
719 .max_stacks(
720 data
721 .require_aura_max_stacks(
722 wowlab_types::sim::SpellIdx::from_raw(196_099),
723 )?,
724 ),
725 )
726}
727fn aura_wild_imps(
728 a: AuraDefinitionDraft,
729 data: &ResolvedGameData,
730) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
731 Ok(
732 a
733 .on_player()
734 .apply_base_from_data(data, 104_317)?
735 .max_stacks(
736 data
737 .require_aura_max_stacks(
738 wowlab_types::sim::SpellIdx::from_raw(104_317),
739 )?,
740 ),
741 )
742}
743fn aura_dreadstalkers(
744 a: AuraDefinitionDraft,
745 data: &ResolvedGameData,
746) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
747 Ok(
748 a
749 .on_player()
750 .apply_base_from_data(data, 193_332)?
751 .max_stacks(
752 data
753 .require_aura_max_stacks(
754 wowlab_types::sim::SpellIdx::from_raw(193_332),
755 )?,
756 ),
757 )
758}
759fn aura_track_pets(
760 a: AuraDefinitionDraft,
761 data: &ResolvedGameData,
762) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
763 Ok(
764 a
765 .on_player()
766 .apply_base_from_data(data, 462_599)?
767 .max_stacks(
768 data
769 .require_aura_max_stacks(
770 wowlab_types::sim::SpellIdx::from_raw(462_599),
771 )?,
772 ),
773 )
774}
775fn aura_flametouched_talent(
776 a: AuraDefinitionDraft,
777 data: &ResolvedGameData,
778) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
779 Ok(
780 a
781 .on_player()
782 .apply_base_from_data(data, 453_699)?
783 .max_stacks(
784 data
785 .require_aura_max_stacks(
786 wowlab_types::sim::SpellIdx::from_raw(453_699),
787 )?,
788 ),
789 )
790}
791fn aura_infernal_bolt(
792 a: AuraDefinitionDraft,
793 data: &ResolvedGameData,
794) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
795 Ok(
796 a
797 .on_player()
798 .apply_base_from_data(data, 433_891)?
799 .max_stacks(
800 data
801 .require_aura_max_stacks(
802 wowlab_types::sim::SpellIdx::from_raw(433_891),
803 )?,
804 ),
805 )
806}
807fn aura_ruination(
808 a: AuraDefinitionDraft,
809 data: &ResolvedGameData,
810) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
811 Ok(
812 a
813 .on_player()
814 .apply_base_from_data(data, 433_885)?
815 .max_stacks(
816 data
817 .require_aura_max_stacks(
818 wowlab_types::sim::SpellIdx::from_raw(433_885),
819 )?,
820 ),
821 )
822}
823fn aura_diabolic_ritual_talent(
824 a: AuraDefinitionDraft,
825 data: &ResolvedGameData,
826) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
827 Ok(
828 a
829 .on_player()
830 .apply_base_from_data(data, 428_514)?
831 .max_stacks(
832 data
833 .require_aura_max_stacks(
834 wowlab_types::sim::SpellIdx::from_raw(428_514),
835 )?,
836 ),
837 )
838}
839fn aura_diabolic_ritual_overlord(
840 a: AuraDefinitionDraft,
841 data: &ResolvedGameData,
842) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
843 Ok(
844 a
845 .on_player()
846 .apply_base_from_data(data, 431_944)?
847 .max_stacks(
848 data
849 .require_aura_max_stacks(
850 wowlab_types::sim::SpellIdx::from_raw(431_944),
851 )?,
852 )
853 .on_expire(
854 crate::hooks::demonology_warlock::demonology_diabolic_ritual_overlord_expire_hook,
855 ),
856 )
857}
858fn aura_diabolic_ritual_mother(
859 a: AuraDefinitionDraft,
860 data: &ResolvedGameData,
861) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
862 Ok(
863 a
864 .on_player()
865 .apply_base_from_data(data, 432_815)?
866 .max_stacks(
867 data
868 .require_aura_max_stacks(
869 wowlab_types::sim::SpellIdx::from_raw(432_815),
870 )?,
871 )
872 .on_expire(
873 crate::hooks::demonology_warlock::demonology_diabolic_ritual_mother_expire_hook,
874 ),
875 )
876}
877fn aura_diabolic_ritual_pit_lord(
878 a: AuraDefinitionDraft,
879 data: &ResolvedGameData,
880) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
881 Ok(
882 a
883 .on_player()
884 .apply_base_from_data(data, 432_816)?
885 .max_stacks(
886 data
887 .require_aura_max_stacks(
888 wowlab_types::sim::SpellIdx::from_raw(432_816),
889 )?,
890 )
891 .on_expire(
892 crate::hooks::demonology_warlock::demonology_diabolic_ritual_pit_lord_expire_hook,
893 ),
894 )
895}
896fn aura_demonic_art_overlord(
897 a: AuraDefinitionDraft,
898 data: &ResolvedGameData,
899) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
900 Ok(
901 a
902 .on_player()
903 .apply_base_from_data(data, 428_524)?
904 .max_stacks(
905 data
906 .require_aura_max_stacks(
907 wowlab_types::sim::SpellIdx::from_raw(428_524),
908 )?,
909 )
910 .on_expire(
911 crate::hooks::demonology_warlock::demonology_demonic_art_overlord_expire_hook,
912 ),
913 )
914}
915fn aura_demonic_art_mother(
916 a: AuraDefinitionDraft,
917 data: &ResolvedGameData,
918) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
919 Ok(
920 a
921 .on_player()
922 .apply_base_from_data(data, 432_794)?
923 .max_stacks(
924 data
925 .require_aura_max_stacks(
926 wowlab_types::sim::SpellIdx::from_raw(432_794),
927 )?,
928 )
929 .on_expire(
930 crate::hooks::demonology_warlock::demonology_demonic_art_mother_expire_hook,
931 ),
932 )
933}
934fn aura_demonic_art_pit_lord(
935 a: AuraDefinitionDraft,
936 data: &ResolvedGameData,
937) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
938 Ok(
939 a
940 .on_player()
941 .apply_base_from_data(data, 432_795)?
942 .max_stacks(
943 data
944 .require_aura_max_stacks(
945 wowlab_types::sim::SpellIdx::from_raw(432_795),
946 )?,
947 )
948 .on_expire(
949 crate::hooks::demonology_warlock::demonology_demonic_art_pit_lord_expire_hook,
950 ),
951 )
952}
953fn aura_demonic_oculi(
954 a: AuraDefinitionDraft,
955 data: &ResolvedGameData,
956) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
957 Ok(
958 a
959 .on_player()
960 .apply_base_from_data(data, 1_269_643)?
961 .max_stacks(
962 data
963 .require_aura_max_stacks(
964 wowlab_types::sim::SpellIdx::from_raw(1_269_643),
965 )?,
966 ),
967 )
968}
969fn aura_diabolic_oculi_talent(
970 a: AuraDefinitionDraft,
971 data: &ResolvedGameData,
972) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
973 Ok(
974 a
975 .on_player()
976 .apply_base_from_data(data, 1_268_709)?
977 .max_stacks(
978 data
979 .require_aura_max_stacks(
980 wowlab_types::sim::SpellIdx::from_raw(1_268_709),
981 )?,
982 ),
983 )
984}
985fn aura_looks_that_kill_talent(
986 a: AuraDefinitionDraft,
987 data: &ResolvedGameData,
988) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
989 Ok(
990 a
991 .on_player()
992 .apply_base_from_data(data, 1_268_713)?
993 .max_stacks(
994 data
995 .require_aura_max_stacks(
996 wowlab_types::sim::SpellIdx::from_raw(1_268_713),
997 )?,
998 ),
999 )
1000}
1001fn aura_minds_eyes_talent(
1002 a: AuraDefinitionDraft,
1003 data: &ResolvedGameData,
1004) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1005 Ok(
1006 a
1007 .on_player()
1008 .apply_base_from_data(data, 1_268_716)?
1009 .max_stacks(
1010 data
1011 .require_aura_max_stacks(
1012 wowlab_types::sim::SpellIdx::from_raw(1_268_716),
1013 )?,
1014 ),
1015 )
1016}
1017fn aura_minds_eyes(
1018 a: AuraDefinitionDraft,
1019 data: &ResolvedGameData,
1020) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1021 a.on_player()
1022 .apply_base_from_data(data, 1_269_879)?
1023 .max_stacks(
1024 data
1025 .require_aura_max_stacks(
1026 wowlab_types::sim::SpellIdx::from_raw(1_269_879),
1027 )?,
1028 )
1029 .primary_pct_per_stack(
1030 data.base_points(wowlab_types::sim::SpellIdx::from_raw(1_269_879), 1),
1031 )
1032}
1033fn aura_abyssal_dominion(
1034 a: AuraDefinitionDraft,
1035 data: &ResolvedGameData,
1036) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1037 a.on_player()
1038 .apply_base_from_data(data, 456_323)?
1039 .max_stacks(
1040 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(456_323))?,
1041 )
1042 .pet_damage_multiplier(
1043 ((data.base_points(wowlab_types::sim::SpellIdx::from_raw(456_323), 1))
1044 * 0.01) + 1.0,
1045 )
1046}
1047fn aura_abyssal_dominion_talent(
1048 a: AuraDefinitionDraft,
1049 data: &ResolvedGameData,
1050) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1051 Ok(
1052 a
1053 .on_player()
1054 .apply_base_from_data(data, 429_581)?
1055 .max_stacks(
1056 data
1057 .require_aura_max_stacks(
1058 wowlab_types::sim::SpellIdx::from_raw(429_581),
1059 )?,
1060 ),
1061 )
1062}
1063fn aura_cloven_soul(
1064 a: AuraDefinitionDraft,
1065 data: &ResolvedGameData,
1066) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1067 Ok(
1068 a
1069 .on_target()
1070 .apply_base_from_data(data, 434_424)?
1071 .max_stacks(
1072 data
1073 .require_aura_max_stacks(
1074 wowlab_types::sim::SpellIdx::from_raw(434_424),
1075 )?,
1076 ),
1077 )
1078}
1079fn spell_shadow_bolt(
1080 s: SpellDefinitionDraft,
1081 data: &ResolvedGameData,
1082) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1083 Ok(s.apply_base_from_data(data, 686)?.gain(1.0).apply_aoe_from_data(data))
1084}
1085fn spell_demonbolt(
1086 s: SpellDefinitionDraft,
1087 data: &ResolvedGameData,
1088) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1089 Ok(
1090 s
1091 .apply_base_from_data(data, 264_178)?
1092 .gain(2.0)
1093 .apply_aoe_from_data(data)
1094 .on_cast(crate::hooks::demonology_warlock::demonbolt_hook)
1095 .instant_when_aura(AURA::DEMONIC_CORE),
1096 )
1097}
1098fn spell_hand_of_guldan(
1099 s: SpellDefinitionDraft,
1100 data: &ResolvedGameData,
1101) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1102 Ok(
1103 s
1104 .apply_base_from_data(data, 105_174)?
1105 .apply_aoe_from_data(data)
1106 .on_cast(crate::hooks::demonology_warlock::hand_of_guldan_hook),
1107 )
1108}
1109fn spell_power_siphon(
1110 s: SpellDefinitionDraft,
1111 data: &ResolvedGameData,
1112) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1113 Ok(
1114 s
1115 .apply_base_from_data(data, 264_130)?
1116 .applies_inferred_aura(AURA_POWER_SIPHON, 334_581)
1117 .apply_aoe_from_data(data)
1118 .on_cast(crate::hooks::demonology_warlock::power_siphon_hook),
1119 )
1120}
1121fn spell_drain_life(
1122 s: SpellDefinitionDraft,
1123 data: &ResolvedGameData,
1124) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1125 Ok(s.apply_base_from_data(data, 234_153)?.apply_aoe_from_data(data))
1126}
1127fn spell_summon_felguard(
1128 s: SpellDefinitionDraft,
1129 data: &ResolvedGameData,
1130) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1131 Ok(s.apply_base_from_data(data, 30146)?.apply_aoe_from_data(data))
1132}
1133fn spell_summon_felhunter(
1134 s: SpellDefinitionDraft,
1135 data: &ResolvedGameData,
1136) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1137 Ok(s.apply_base_from_data(data, 691)?.apply_aoe_from_data(data))
1138}
1139fn spell_summon_imp(
1140 s: SpellDefinitionDraft,
1141 data: &ResolvedGameData,
1142) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1143 Ok(s.apply_base_from_data(data, 688)?.apply_aoe_from_data(data))
1144}
1145fn spell_call_dreadstalkers(
1146 s: SpellDefinitionDraft,
1147 data: &ResolvedGameData,
1148) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1149 Ok(
1150 s
1151 .apply_base_from_data(data, 104_316)?
1152 .apply_aoe_from_data(data)
1153 .on_cast(crate::hooks::demonology_warlock::call_dreadstalkers_hook),
1154 )
1155}
1156fn spell_summon_demonic_tyrant(
1157 s: SpellDefinitionDraft,
1158 data: &ResolvedGameData,
1159) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1160 Ok(
1161 s
1162 .apply_base_from_data(data, 265_187)?
1163 .apply_aoe_from_data(data)
1164 .on_cast(crate::hooks::demonology_warlock::summon_demonic_tyrant_hook),
1165 )
1166}
1167fn spell_summon_vilefiend(
1168 s: SpellDefinitionDraft,
1169 data: &ResolvedGameData,
1170) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1171 Ok(s.apply_base_from_data(data, 264_119)?.apply_aoe_from_data(data))
1172}
1173fn spell_implosion(
1174 s: SpellDefinitionDraft,
1175 data: &ResolvedGameData,
1176) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1177 Ok(s.apply_base_from_data(data, 196_277)?.apply_aoe_from_data(data))
1178}
1179fn spell_grimoire_imp_lord(
1180 s: SpellDefinitionDraft,
1181 data: &ResolvedGameData,
1182) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1183 Ok(s.apply_base_from_data(data, 1_276_452)?.apply_aoe_from_data(data))
1184}
1185fn spell_grimoire_fel_ravager(
1186 s: SpellDefinitionDraft,
1187 data: &ResolvedGameData,
1188) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1189 Ok(s.apply_base_from_data(data, 1_276_467)?.apply_aoe_from_data(data))
1190}
1191fn spell_summon_doomguard(
1192 s: SpellDefinitionDraft,
1193 data: &ResolvedGameData,
1194) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1195 Ok(s.apply_base_from_data(data, 1_276_672)?.apply_aoe_from_data(data))
1196}
1197fn spell_infernal_bolt(
1198 s: SpellDefinitionDraft,
1199 data: &ResolvedGameData,
1200) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1201 Ok(
1202 s
1203 .apply_base_from_data(data, 434_506)?
1204 .gain(
1205 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(434_506), 2))
1206 * 0.1,
1207 )
1208 .apply_aoe_from_data(data)
1209 .requires_aura_at_min_stacks(433_891, 0)
1210 .consume_aura_on_cast(433_891),
1211 )
1212}
1213fn spell_ruination(
1214 s: SpellDefinitionDraft,
1215 data: &ResolvedGameData,
1216) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1217 Ok(
1218 s
1219 .apply_base_from_data(data, 434_635)?
1220 .travel_time(
1221 wowlab_engine_combat::validated_milliseconds(
1222 1000.0,
1223 434_635,
1224 "spell.travel_time_ms",
1225 )?,
1226 )
1227 .apply_aoe_from_data(data)
1228 .on_cast(crate::hooks::demonology_warlock::ruination_hook)
1229 .requires_aura_at_min_stacks(433_885, 0)
1230 .consume_aura_on_cast(433_885),
1231 )
1232}
1233pub(crate) fn build_combat_system(
1234 params: &wowlab_engine_ports::HandlerParams<'_>,
1235) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1236 let builder = BuiltCombatSystem::builder(params.stats.clone())
1237 .spec_id(SpecId::Demonology)
1238 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1239 .mastery_spell(77219)
1240 .mastery_hook(crate::hooks::demonology_warlock::mastery)
1241 .resource(
1242 "soul_shards",
1243 5.0,
1244 params
1245 .game_data
1246 .power_regen_for_max(7, 5.0)
1247 .ok_or_else(|| {
1248 wowlab_engine_ports::EngineError::spec_construction(
1249 "missing power-type power_regen_for_max for type_id 7",
1250 )
1251 })?,
1252 )
1253 .resource_type_id(7)
1254 .resource_start(3.0)
1255 .mastery_crit_damage_hook(crate::hooks::demonology_warlock::crit_damage)
1256 .has_pet(true)
1257 .aura(
1258 "demonic_core",
1259 AURA::DEMONIC_CORE,
1260 |a| aura_demonic_core(a, ¶ms.game_data),
1261 )
1262 .aura(
1263 "carnivorous_stalkers_talent",
1264 AURA::CARNIVOROUS_STALKERS_TALENT,
1265 |a| aura_carnivorous_stalkers_talent(a, ¶ms.game_data),
1266 )
1267 .aura(
1268 "power_siphon",
1269 AURA::POWER_SIPHON,
1270 |a| aura_power_siphon(a, ¶ms.game_data),
1271 )
1272 .aura("doom", AURA::DOOM, |a| aura_doom(a, ¶ms.game_data))
1273 .aura(
1274 "tyrants_oblation",
1275 AURA::TYRANTS_OBLATION,
1276 |a| aura_tyrants_oblation(a, ¶ms.game_data),
1277 )
1278 .aura(
1279 "hellbent_commander",
1280 AURA::HELLBENT_COMMANDER,
1281 |a| aura_hellbent_commander(a, ¶ms.game_data),
1282 )
1283 .aura(
1284 "inner_demons",
1285 AURA::INNER_DEMONS,
1286 |a| aura_inner_demons(a, ¶ms.game_data),
1287 )
1288 .aura(
1289 "dominion_of_argus",
1290 AURA::DOMINION_OF_ARGUS,
1291 |a| aura_dominion_of_argus(a, ¶ms.game_data),
1292 )
1293 .aura(
1294 "succulent_soul",
1295 AURA::SUCCULENT_SOUL,
1296 |a| aura_succulent_soul(a, ¶ms.game_data),
1297 )
1298 .aura(
1299 "manifested_demonic_soul",
1300 AURA::MANIFESTED_DEMONIC_SOUL,
1301 |a| aura_manifested_demonic_soul(a, ¶ms.game_data),
1302 )
1303 .aura(
1304 "grimoire_of_sacrifice",
1305 AURA::GRIMOIRE_OF_SACRIFICE,
1306 |a| aura_grimoire_of_sacrifice(a, ¶ms.game_data),
1307 )
1308 .aura("wild_imps", AURA::WILD_IMPS, |a| aura_wild_imps(a, ¶ms.game_data))
1309 .aura(
1310 "dreadstalkers",
1311 AURA::DREADSTALKERS,
1312 |a| aura_dreadstalkers(a, ¶ms.game_data),
1313 )
1314 .aura("track_pets", AURA::TRACK_PETS, |a| aura_track_pets(a, ¶ms.game_data))
1315 .aura(
1316 "flametouched_talent",
1317 AURA::FLAMETOUCHED_TALENT,
1318 |a| aura_flametouched_talent(a, ¶ms.game_data),
1319 )
1320 .aura(
1321 "infernal_bolt",
1322 AURA::INFERNAL_BOLT,
1323 |a| aura_infernal_bolt(a, ¶ms.game_data),
1324 )
1325 .aura("ruination", AURA::RUINATION, |a| aura_ruination(a, ¶ms.game_data))
1326 .aura(
1327 "diabolic_ritual_talent",
1328 AURA::DIABOLIC_RITUAL_TALENT,
1329 |a| aura_diabolic_ritual_talent(a, ¶ms.game_data),
1330 )
1331 .aura(
1332 "diabolic_ritual_overlord",
1333 AURA::DIABOLIC_RITUAL_OVERLORD,
1334 |a| aura_diabolic_ritual_overlord(a, ¶ms.game_data),
1335 )
1336 .aura(
1337 "diabolic_ritual_mother",
1338 AURA::DIABOLIC_RITUAL_MOTHER,
1339 |a| aura_diabolic_ritual_mother(a, ¶ms.game_data),
1340 )
1341 .aura(
1342 "diabolic_ritual_pit_lord",
1343 AURA::DIABOLIC_RITUAL_PIT_LORD,
1344 |a| aura_diabolic_ritual_pit_lord(a, ¶ms.game_data),
1345 )
1346 .aura(
1347 "demonic_art_overlord",
1348 AURA::DEMONIC_ART_OVERLORD,
1349 |a| aura_demonic_art_overlord(a, ¶ms.game_data),
1350 )
1351 .aura(
1352 "demonic_art_mother",
1353 AURA::DEMONIC_ART_MOTHER,
1354 |a| aura_demonic_art_mother(a, ¶ms.game_data),
1355 )
1356 .aura(
1357 "demonic_art_pit_lord",
1358 AURA::DEMONIC_ART_PIT_LORD,
1359 |a| aura_demonic_art_pit_lord(a, ¶ms.game_data),
1360 )
1361 .aura(
1362 "demonic_oculi",
1363 AURA::DEMONIC_OCULI,
1364 |a| aura_demonic_oculi(a, ¶ms.game_data),
1365 )
1366 .aura(
1367 "diabolic_oculi_talent",
1368 AURA::DIABOLIC_OCULI_TALENT,
1369 |a| aura_diabolic_oculi_talent(a, ¶ms.game_data),
1370 )
1371 .aura(
1372 "looks_that_kill_talent",
1373 AURA::LOOKS_THAT_KILL_TALENT,
1374 |a| aura_looks_that_kill_talent(a, ¶ms.game_data),
1375 )
1376 .aura(
1377 "minds_eyes_talent",
1378 AURA::MINDS_EYES_TALENT,
1379 |a| aura_minds_eyes_talent(a, ¶ms.game_data),
1380 )
1381 .aura("minds_eyes", AURA::MINDS_EYES, |a| aura_minds_eyes(a, ¶ms.game_data))
1382 .aura(
1383 "abyssal_dominion",
1384 AURA::ABYSSAL_DOMINION,
1385 |a| aura_abyssal_dominion(a, ¶ms.game_data),
1386 )
1387 .aura(
1388 "abyssal_dominion_talent",
1389 AURA::ABYSSAL_DOMINION_TALENT,
1390 |a| aura_abyssal_dominion_talent(a, ¶ms.game_data),
1391 )
1392 .aura(
1393 "cloven_soul",
1394 AURA::CLOVEN_SOUL,
1395 |a| aura_cloven_soul(a, ¶ms.game_data),
1396 )
1397 .spell(
1398 "shadow_bolt",
1399 SPELL::SHADOW_BOLT,
1400 |s| spell_shadow_bolt(s, ¶ms.game_data),
1401 )
1402 .spell("demonbolt", SPELL::DEMONBOLT, |s| spell_demonbolt(s, ¶ms.game_data))
1403 .spell(
1404 "hand_of_guldan",
1405 SPELL::HAND_OF_GULDAN,
1406 |s| spell_hand_of_guldan(s, ¶ms.game_data),
1407 )
1408 .spell(
1409 "power_siphon",
1410 SPELL::POWER_SIPHON,
1411 |s| spell_power_siphon(s, ¶ms.game_data),
1412 )
1413 .spell(
1414 "drain_life",
1415 SPELL::DRAIN_LIFE,
1416 |s| spell_drain_life(s, ¶ms.game_data),
1417 )
1418 .spell(
1419 "summon_felguard",
1420 SPELL::SUMMON_FELGUARD,
1421 |s| spell_summon_felguard(s, ¶ms.game_data),
1422 )
1423 .spell(
1424 "summon_felhunter",
1425 SPELL::SUMMON_FELHUNTER,
1426 |s| spell_summon_felhunter(s, ¶ms.game_data),
1427 )
1428 .spell(
1429 "summon_imp",
1430 SPELL::SUMMON_IMP,
1431 |s| spell_summon_imp(s, ¶ms.game_data),
1432 )
1433 .spell(
1434 "call_dreadstalkers",
1435 SPELL::CALL_DREADSTALKERS,
1436 |s| spell_call_dreadstalkers(s, ¶ms.game_data),
1437 )
1438 .spell(
1439 "summon_demonic_tyrant",
1440 SPELL::SUMMON_DEMONIC_TYRANT,
1441 |s| spell_summon_demonic_tyrant(s, ¶ms.game_data),
1442 )
1443 .spell(
1444 "summon_vilefiend",
1445 SPELL::SUMMON_VILEFIEND,
1446 |s| spell_summon_vilefiend(s, ¶ms.game_data),
1447 )
1448 .spell("implosion", SPELL::IMPLOSION, |s| spell_implosion(s, ¶ms.game_data))
1449 .spell(
1450 "grimoire_imp_lord",
1451 SPELL::GRIMOIRE_IMP_LORD,
1452 |s| spell_grimoire_imp_lord(s, ¶ms.game_data),
1453 )
1454 .spell(
1455 "grimoire_fel_ravager",
1456 SPELL::GRIMOIRE_FEL_RAVAGER,
1457 |s| spell_grimoire_fel_ravager(s, ¶ms.game_data),
1458 )
1459 .spell(
1460 "summon_doomguard",
1461 SPELL::SUMMON_DOOMGUARD,
1462 |s| spell_summon_doomguard(s, ¶ms.game_data),
1463 )
1464 .spell(
1465 "infernal_bolt",
1466 SPELL::INFERNAL_BOLT,
1467 |s| spell_infernal_bolt(s, ¶ms.game_data),
1468 )
1469 .spell("ruination", SPELL::RUINATION, |s| spell_ruination(s, ¶ms.game_data))
1470 .auto_attack(|a| {
1471 a
1472 .spell_id(1)
1473 .swing_ms(2000)
1474 .apply_base_from_data(¶ms.game_data)
1475 .ap_coef(0.7297)
1476 .is_pet()
1477 .uses_spell_power()
1478 })
1479 .game_data(params.game_data.clone())
1480 .talent_spell_ids(TALENTS)
1481 .talent_selections(params.talent_selections)
1482 .talent_companion_aura(
1483 TALENT::ABYSSAL_DOMINION_TALENT,
1484 AURA_ABYSSAL_DOMINION_TALENT,
1485 )
1486 .talent_companion_aura(
1487 TALENT::CARNIVOROUS_STALKERS,
1488 AURA_CARNIVOROUS_STALKERS_TALENT,
1489 )
1490 .talent_companion_aura(TALENT::DIABOLIC_OCULI, AURA_DIABOLIC_OCULI_TALENT)
1491 .talent_companion_aura(TALENT::DIABOLIC_RITUAL, AURA_DIABOLIC_RITUAL_TALENT)
1492 .talent_companion_aura(TALENT::FLAMETOUCHED, AURA_FLAMETOUCHED_TALENT)
1493 .talent_companion_aura(TALENT::LOOKS_THAT_KILL, AURA_LOOKS_THAT_KILL_TALENT)
1494 .talent_companion_aura(TALENT::MINDS_EYES, AURA_MINDS_EYES_TALENT)
1495 .set_bonus_auras(params.set_bonus_auras)
1496 .encounter(params.encounter.clone());
1497 let builder = crate::generated::items::register_equipped(
1498 builder,
1499 ¶ms.game_data,
1500 params.equipped_items,
1501 )?;
1502
1503 builder
1504 .build(params.rotation)
1505 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1506}
1507fn new_handler(
1508 params: wowlab_engine_ports::HandlerParams<'_>,
1509) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1510 let handler = crate::composition::compose_handler(
1511 build_combat_system,
1512 ¶ms,
1513 |parts, params| Ok(
1514 crate::hooks::demonology_warlock::DemonologyHandler::new(parts, params),
1515 ),
1516 )?;
1517
1518 Ok(Box::new(handler))
1519}
1520static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1521 primary_resource: ResourceType::SoulShards,
1522 secondary_resource: None,
1523 spell_ids: DECLARED_SPELL_IDS,
1524 aura_ids: DECLARED_AURA_IDS,
1525 server_proc_entries: &[],
1526 talents: TALENTS,
1527 rotation_field_schema: &[],
1528 metrics_plugin_id: None,
1529 hero_talent_trees: &[
1530 HeroTalentTreeDesc {
1531 name: "Soul Harvester",
1532 spells: HERO_TREE_SOUL_HARVESTER_SPELLS,
1533 auras: HERO_TREE_SOUL_HARVESTER_AURAS,
1534 },
1535 HeroTalentTreeDesc {
1536 name: "Diabolist",
1537 spells: HERO_TREE_DIABOLIST_SPELLS,
1538 auras: HERO_TREE_DIABOLIST_AURAS,
1539 },
1540 ],
1541 reported_spells: REPORTED_SPELLS,
1542 masked_passive_effects: &[],
1543 passive_effect_overrides: &[],
1544};
1545pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1546 spec_id: SpecId::Demonology,
1547 display_name: "Demonology Warlock",
1548 metadata: DECLARED_METADATA,
1549 handler_factory: new_handler,
1550};
1551wowlab_engine_combat::smoke_test!(build_combat_system);