Skip to main content

wowlab_engine_content/generated/specs/
shadow_priest.rs

1//! @generated by codegen-cli from manifests/specs/priest/shadow/manifest.toml -- do not edit by hand.
2// Generated code: naming follows game data conventions
3#![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    ///<https://wowlab.gg/inspect/spell/8092>
15    pub(crate) const MIND_BLAST: u32 = 8092;
16    ///<https://wowlab.gg/inspect/spell/589>
17    pub(crate) const SHADOW_WORD_PAIN: u32 = 589;
18    ///<https://wowlab.gg/inspect/spell/34914>
19    pub(crate) const VAMPIRIC_TOUCH: u32 = 34914;
20    ///<https://wowlab.gg/inspect/spell/335467>
21    pub(crate) const SHADOW_WORD_MADNESS: u32 = 335_467;
22    ///<https://wowlab.gg/inspect/spell/228260>
23    pub(crate) const VOIDFORM: u32 = 228_260;
24    ///<https://wowlab.gg/inspect/spell/263165>
25    pub(crate) const VOID_TORRENT: u32 = 263_165;
26    ///<https://wowlab.gg/inspect/spell/15407>
27    pub(crate) const MIND_FLAY: u32 = 15407;
28    ///<https://wowlab.gg/inspect/spell/32379>
29    pub(crate) const SHADOW_WORD_DEATH: u32 = 32379;
30    ///<https://wowlab.gg/inspect/spell/120644>
31    pub(crate) const HALO: u32 = 120_644;
32    ///<https://wowlab.gg/inspect/spell/10060>
33    pub(crate) const POWER_INFUSION: u32 = 10060;
34    ///<https://wowlab.gg/inspect/spell/232698>
35    pub(crate) const SHADOWFORM: u32 = 232_698;
36    ///<https://wowlab.gg/inspect/spell/21562>
37    pub(crate) const POWER_WORD_FORTITUDE: u32 = 21562;
38    ///<https://wowlab.gg/inspect/spell/413231>
39    pub(crate) const SHADOWY_APPARITION: u32 = 413_231;
40    ///<https://wowlab.gg/inspect/spell/1264176>
41    pub(crate) const VOID_APPARITION: u32 = 1_264_176;
42    ///<https://wowlab.gg/inspect/spell/1264177>
43    pub(crate) const VOID_BOLT: u32 = 1_264_177;
44    ///<https://wowlab.gg/inspect/spell/1227280>
45    pub(crate) const TENTACLE_SLAM: u32 = 1_227_280;
46    ///<https://wowlab.gg/inspect/spell/1227621>
47    pub(crate) const TENTACLE_SLAM_DAMAGE: u32 = 1_227_621;
48}
49pub(crate) mod AURA {
50    ///<https://wowlab.gg/inspect/spell/232698>
51    pub(crate) const SHADOWFORM: u32 = 232_698;
52    ///<https://wowlab.gg/inspect/spell/194249>
53    pub(crate) const VOIDFORM: u32 = 194_249;
54    ///<https://wowlab.gg/inspect/spell/589>
55    pub(crate) const SHADOW_WORD_PAIN: u32 = 589;
56    ///<https://wowlab.gg/inspect/spell/34914>
57    pub(crate) const VAMPIRIC_TOUCH: u32 = 34914;
58    ///<https://wowlab.gg/inspect/spell/335467>
59    pub(crate) const SHADOW_WORD_MADNESS: u32 = 335_467;
60    ///<https://wowlab.gg/inspect/spell/375981>
61    pub(crate) const SHADOWY_INSIGHT: u32 = 375_981;
62    ///<https://wowlab.gg/inspect/spell/373204>
63    pub(crate) const MIND_DEVOURER: u32 = 373_204;
64    ///<https://wowlab.gg/inspect/spell/391401>
65    pub(crate) const MIND_FLAY_INSANITY: u32 = 391_401;
66    ///<https://wowlab.gg/inspect/spell/393919>
67    pub(crate) const SCREAMS_OF_THE_VOID: u32 = 393_919;
68    ///<https://wowlab.gg/inspect/spell/392507>
69    pub(crate) const DEATHSPEAKER: u32 = 392_507;
70    ///<https://wowlab.gg/inspect/spell/238558>
71    pub(crate) const MISERY: u32 = 238_558;
72    ///<https://wowlab.gg/inspect/spell/1271911>
73    pub(crate) const POWER_WORD_FORTITUDE_HIGHLIGHT: u32 = 1_271_911;
74    ///<https://wowlab.gg/inspect/spell/10060>
75    pub(crate) const POWER_INFUSION: u32 = 10060;
76    ///<https://wowlab.gg/inspect/spell/289577>
77    pub(crate) const VOID_TORRENT: u32 = 289_577;
78    ///<https://wowlab.gg/inspect/spell/373212>
79    pub(crate) const INSIDIOUS_IRE: u32 = 373_212;
80    ///<https://wowlab.gg/inspect/spell/391092>
81    pub(crate) const SHATTERED_PSYCHE: u32 = 391_092;
82    ///<https://wowlab.gg/inspect/spell/450983>
83    pub(crate) const VOID_BLAST: u32 = 450_983;
84    ///<https://wowlab.gg/inspect/spell/407430>
85    pub(crate) const VOIDTOUCHED: u32 = 407_430;
86    ///<https://wowlab.gg/inspect/spell/1279437>
87    pub(crate) const CRUSHING_VOID: u32 = 1_279_437;
88    ///<https://wowlab.gg/inspect/spell/1227280>
89    pub(crate) const TENTACLE_SLAM: u32 = 1_227_280;
90    ///<https://wowlab.gg/inspect/spell/447448>
91    pub(crate) const ENTROPIC_RIFT: u32 = 447_448;
92    ///<https://wowlab.gg/inspect/spell/449887>
93    pub(crate) const VOIDHEART: u32 = 449_887;
94}
95pub(crate) mod TALENT {
96    ///<https://wowlab.gg/inspect/spell/1231346>
97    pub(crate) const ANCIENT_MADNESS: u32 = 1_231_346;
98    ///<https://wowlab.gg/inspect/spell/155271>
99    pub(crate) const AUSPICIOUS_SPIRITS: u32 = 155_271;
100    ///<https://wowlab.gg/inspect/spell/448403>
101    pub(crate) const COLLAPSING_VOID: u32 = 448_403;
102    ///<https://wowlab.gg/inspect/spell/1279437>
103    pub(crate) const CRUSHING_VOID: u32 = 1_279_437;
104    ///<https://wowlab.gg/inspect/spell/449912>
105    pub(crate) const DARKENING_HORIZON: u32 = 449_912;
106    ///<https://wowlab.gg/inspect/spell/392507>
107    pub(crate) const DEATHSPEAKER: u32 = 392_507;
108    ///<https://wowlab.gg/inspect/spell/120644>
109    pub(crate) const HALO: u32 = 120_644;
110    ///<https://wowlab.gg/inspect/spell/377349>
111    pub(crate) const IDOL_OF_CTHUN: u32 = 377_349;
112    ///<https://wowlab.gg/inspect/spell/373280>
113    pub(crate) const IDOL_OF_NZOTH: u32 = 373_280;
114    ///<https://wowlab.gg/inspect/spell/373273>
115    pub(crate) const IDOL_OF_YOGGSARON: u32 = 373_273;
116    ///<https://wowlab.gg/inspect/spell/341240>
117    pub(crate) const IMPROVED_VOIDFORM: u32 = 341_240;
118    ///<https://wowlab.gg/inspect/spell/373212>
119    pub(crate) const INSIDIOUS_IRE: u32 = 373_212;
120    ///<https://wowlab.gg/inspect/spell/1279353>
121    pub(crate) const MADDENING_TENTACLES: u32 = 1_279_353;
122    ///<https://wowlab.gg/inspect/spell/1240394>
123    pub(crate) const MADNESS_WEAVING: u32 = 1_240_394;
124    ///<https://wowlab.gg/inspect/spell/373202>
125    pub(crate) const MIND_DEVOURER: u32 = 373_202;
126    ///<https://wowlab.gg/inspect/spell/238558>
127    pub(crate) const MISERY: u32 = 238_558;
128    ///<https://wowlab.gg/inspect/spell/10060>
129    pub(crate) const POWER_INFUSION: u32 = 10060;
130    ///<https://wowlab.gg/inspect/spell/199484>
131    pub(crate) const PSYCHIC_LINK: u32 = 199_484;
132    ///<https://wowlab.gg/inspect/spell/375767>
133    pub(crate) const SCREAMS_OF_THE_VOID: u32 = 375_767;
134    ///<https://wowlab.gg/inspect/spell/341491>
135    pub(crate) const SHADOWY_APPARITIONS: u32 = 341_491;
136    ///<https://wowlab.gg/inspect/spell/375888>
137    pub(crate) const SHADOWY_INSIGHT: u32 = 375_888;
138    ///<https://wowlab.gg/inspect/spell/335467>
139    pub(crate) const SHADOW_WORD_MADNESS: u32 = 335_467;
140    ///<https://wowlab.gg/inspect/spell/391090>
141    pub(crate) const SHATTERED_PSYCHE: u32 = 391_090;
142    ///<https://wowlab.gg/inspect/spell/391399>
143    pub(crate) const SURGE_OF_INSANITY: u32 = 391_399;
144    ///<https://wowlab.gg/inspect/spell/1227280>
145    pub(crate) const TENTACLE_SLAM: u32 = 1_227_280;
146    ///<https://wowlab.gg/inspect/spell/391284>
147    pub(crate) const TORMENTED_SPIRITS: u32 = 391_284;
148    ///<https://wowlab.gg/inspect/spell/228260>
149    pub(crate) const VOIDFORM: u32 = 228_260;
150    ///<https://wowlab.gg/inspect/spell/449880>
151    pub(crate) const VOIDHEART: u32 = 449_880;
152    ///<https://wowlab.gg/inspect/spell/1264096>
153    pub(crate) const VOID_APPARITIONS_1: u32 = 1_264_096;
154    ///<https://wowlab.gg/inspect/spell/1264104>
155    pub(crate) const VOID_APPARITIONS_2: u32 = 1_264_104;
156    ///<https://wowlab.gg/inspect/spell/1264107>
157    pub(crate) const VOID_APPARITIONS_3: u32 = 1_264_107;
158    ///<https://wowlab.gg/inspect/spell/450405>
159    pub(crate) const VOID_BLAST: u32 = 450_405;
160    ///<https://wowlab.gg/inspect/spell/263165>
161    pub(crate) const VOID_TORRENT: u32 = 263_165;
162}
163pub(crate) mod HERO {
164    pub(crate) mod ARCHON {
165        pub(crate) mod SPELL {
166            ///<https://wowlab.gg/inspect/spell/120696>
167            pub(crate) const HALO_DAMAGE: u32 = 120_696;
168            ///<https://wowlab.gg/inspect/spell/391403>
169            pub(crate) const MIND_FLAY_INSANITY: u32 = 391_403;
170            ///<https://wowlab.gg/inspect/spell/1242189>
171            pub(crate) const VOID_VOLLEY_DAMAGE: u32 = 1_242_189;
172            ///<https://wowlab.gg/inspect/spell/1242173>
173            pub(crate) const VOID_VOLLEY_MISSILE: u32 = 1_242_173;
174        }
175        pub(crate) mod AURA {
176            ///<https://wowlab.gg/inspect/spell/391401>
177            pub(crate) const MIND_FLAY_INSANITY_BUFF: u32 = 391_401;
178            ///<https://wowlab.gg/inspect/spell/453112>
179            pub(crate) const POWER_SURGE: u32 = 453_112;
180            ///<https://wowlab.gg/inspect/spell/453850>
181            pub(crate) const RESONANT_ENERGY: u32 = 453_850;
182            ///<https://wowlab.gg/inspect/spell/454002>
183            pub(crate) const SUSTAINED_POTENCY: u32 = 454_002;
184        }
185    }
186    pub(crate) mod VOIDWEAVER {
187        pub(crate) mod SPELL {
188            ///<https://wowlab.gg/inspect/spell/448405>
189            pub(crate) const COLLAPSING_VOID: u32 = 448_405;
190            ///<https://wowlab.gg/inspect/spell/447448>
191            pub(crate) const ENTROPIC_RIFT_DAMAGE: u32 = 447_448;
192            ///<https://wowlab.gg/inspect/spell/451235>
193            pub(crate) const VOIDWRAITH: u32 = 451_235;
194        }
195        pub(crate) mod AURA {
196            ///<https://wowlab.gg/inspect/spell/459314>
197            pub(crate) const ENTROPIC_RIFT_DRIVER: u32 = 459_314;
198            ///<https://wowlab.gg/inspect/spell/449887>
199            pub(crate) const VOIDHEART_BUFF: u32 = 449_887;
200            ///<https://wowlab.gg/inspect/spell/450138>
201            pub(crate) const VOID_EMPOWERMENT: u32 = 450_138;
202        }
203    }
204}
205static HERO_TREE_ARCHON_SPELLS: &[(&str, u32)] = &[
206    ("HALO_DAMAGE", 120_696),
207    ("MIND_FLAY_INSANITY", 391_403),
208    ("VOID_VOLLEY_DAMAGE", 1_242_189),
209    ("VOID_VOLLEY_MISSILE", 1_242_173),
210];
211static HERO_TREE_ARCHON_AURAS: &[(&str, u32)] = &[
212    ("MIND_FLAY_INSANITY_BUFF", 391_401),
213    ("POWER_SURGE", 453_112),
214    ("RESONANT_ENERGY", 453_850),
215    ("SUSTAINED_POTENCY", 454_002),
216];
217static HERO_TREE_VOIDWEAVER_SPELLS: &[(&str, u32)] = &[
218    ("COLLAPSING_VOID", 448_405),
219    ("ENTROPIC_RIFT_DAMAGE", 447_448),
220    ("VOIDWRAITH", 451_235),
221];
222static HERO_TREE_VOIDWEAVER_AURAS: &[(&str, u32)] = &[
223    ("ENTROPIC_RIFT_DRIVER", 459_314),
224    ("VOIDHEART_BUFF", 449_887),
225    ("VOID_EMPOWERMENT", 450_138),
226];
227pub(crate) const AURA_SHADOWFORM: LocalAuraIdx = LocalAuraIdx::new(0);
228pub(crate) const AURA_VOIDFORM: LocalAuraIdx = LocalAuraIdx::new(1);
229pub(crate) const AURA_SHADOW_WORD_PAIN: LocalAuraIdx = LocalAuraIdx::new(2);
230pub(crate) const AURA_VAMPIRIC_TOUCH: LocalAuraIdx = LocalAuraIdx::new(3);
231pub(crate) const AURA_SHADOW_WORD_MADNESS: LocalAuraIdx = LocalAuraIdx::new(4);
232pub(crate) const AURA_SHADOWY_INSIGHT: LocalAuraIdx = LocalAuraIdx::new(5);
233pub(crate) const AURA_MIND_DEVOURER: LocalAuraIdx = LocalAuraIdx::new(6);
234pub(crate) const AURA_MIND_FLAY_INSANITY: LocalAuraIdx = LocalAuraIdx::new(7);
235pub(crate) const AURA_SCREAMS_OF_THE_VOID: LocalAuraIdx = LocalAuraIdx::new(8);
236pub(crate) const AURA_DEATHSPEAKER: LocalAuraIdx = LocalAuraIdx::new(9);
237pub(crate) const AURA_MISERY: LocalAuraIdx = LocalAuraIdx::new(10);
238pub(crate) const AURA_POWER_WORD_FORTITUDE_HIGHLIGHT: LocalAuraIdx = LocalAuraIdx::new(
239    11,
240);
241pub(crate) const AURA_POWER_INFUSION: LocalAuraIdx = LocalAuraIdx::new(12);
242pub(crate) const AURA_VOID_TORRENT: LocalAuraIdx = LocalAuraIdx::new(13);
243pub(crate) const AURA_INSIDIOUS_IRE: LocalAuraIdx = LocalAuraIdx::new(14);
244pub(crate) const AURA_SHATTERED_PSYCHE: LocalAuraIdx = LocalAuraIdx::new(15);
245pub(crate) const AURA_VOID_BLAST: LocalAuraIdx = LocalAuraIdx::new(16);
246pub(crate) const AURA_VOIDTOUCHED: LocalAuraIdx = LocalAuraIdx::new(17);
247pub(crate) const AURA_CRUSHING_VOID: LocalAuraIdx = LocalAuraIdx::new(18);
248pub(crate) const AURA_TENTACLE_SLAM: LocalAuraIdx = LocalAuraIdx::new(19);
249pub(crate) const AURA_ENTROPIC_RIFT: LocalAuraIdx = LocalAuraIdx::new(20);
250pub(crate) const AURA_VOIDHEART: LocalAuraIdx = LocalAuraIdx::new(21);
251pub(crate) const AURA_COUNT: usize = 22;
252const _: () = assert!(
253    AURA_COUNT == 22, "AURA index ABI: count changed -- update positional hook consumers"
254);
255pub(crate) const SPELL_MIND_BLAST: LocalSpellIdx = LocalSpellIdx::new(0);
256pub(crate) const SPELL_SHADOW_WORD_PAIN: LocalSpellIdx = LocalSpellIdx::new(1);
257pub(crate) const SPELL_VAMPIRIC_TOUCH: LocalSpellIdx = LocalSpellIdx::new(2);
258pub(crate) const SPELL_SHADOW_WORD_MADNESS: LocalSpellIdx = LocalSpellIdx::new(3);
259pub(crate) const SPELL_VOIDFORM: LocalSpellIdx = LocalSpellIdx::new(4);
260pub(crate) const SPELL_VOID_TORRENT: LocalSpellIdx = LocalSpellIdx::new(5);
261pub(crate) const SPELL_MIND_FLAY: LocalSpellIdx = LocalSpellIdx::new(6);
262pub(crate) const SPELL_SHADOW_WORD_DEATH: LocalSpellIdx = LocalSpellIdx::new(7);
263pub(crate) const SPELL_HALO: LocalSpellIdx = LocalSpellIdx::new(8);
264pub(crate) const SPELL_POWER_INFUSION: LocalSpellIdx = LocalSpellIdx::new(9);
265pub(crate) const SPELL_SHADOWFORM: LocalSpellIdx = LocalSpellIdx::new(10);
266pub(crate) const SPELL_POWER_WORD_FORTITUDE: LocalSpellIdx = LocalSpellIdx::new(11);
267pub(crate) const SPELL_SHADOWY_APPARITION: LocalSpellIdx = LocalSpellIdx::new(12);
268pub(crate) const SPELL_VOID_APPARITION: LocalSpellIdx = LocalSpellIdx::new(13);
269pub(crate) const SPELL_VOID_BOLT: LocalSpellIdx = LocalSpellIdx::new(14);
270pub(crate) const SPELL_TENTACLE_SLAM: LocalSpellIdx = LocalSpellIdx::new(15);
271pub(crate) const SPELL_TENTACLE_SLAM_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(16);
272pub(crate) const SPELL_COUNT: usize = 17;
273const _: () = assert!(
274    SPELL_COUNT == 17,
275    "SPELL index ABI: count changed -- update positional hook consumers"
276);
277pub(crate) mod EFFECT {
278    ///<https://wowlab.gg/inspect/spell/8092>
279    pub(crate) const MIND_BLAST_DAMAGE: (u32, u8) = (8092, 1);
280    ///<https://wowlab.gg/inspect/spell/450983>
281    pub(crate) const VOID_BLAST_DAMAGE: (u32, u8) = (450_983, 1);
282    ///<https://wowlab.gg/inspect/spell/448405>
283    pub(crate) const COLLAPSING_VOID_DAMAGE: (u32, u8) = (448_405, 1);
284    ///<https://wowlab.gg/inspect/spell/448403>
285    pub(crate) const COLLAPSING_VOID_PCT: (u32, u8) = (448_403, 3);
286    ///<https://wowlab.gg/inspect/spell/449912>
287    pub(crate) const DARKENING_HORIZON_MAX: (u32, u8) = (449_912, 2);
288    ///<https://wowlab.gg/inspect/spell/449912>
289    pub(crate) const DARKENING_HORIZON_EXT: (u32, u8) = (449_912, 3);
290    ///<https://wowlab.gg/inspect/spell/1227621>
291    pub(crate) const TENTACLE_SLAM_DAMAGE: (u32, u8) = (1_227_621, 1);
292    ///<https://wowlab.gg/inspect/spell/413231>
293    pub(crate) const SHADOWY_APPARITION_DAMAGE: (u32, u8) = (413_231, 1);
294    ///<https://wowlab.gg/inspect/spell/1264176>
295    pub(crate) const VOID_APPARITION_DAMAGE: (u32, u8) = (1_264_176, 1);
296    ///<https://wowlab.gg/inspect/spell/1264177>
297    pub(crate) const VOID_BOLT_DAMAGE: (u32, u8) = (1_264_177, 1);
298    ///<https://wowlab.gg/inspect/spell/1264104>
299    pub(crate) const VOID_APPARITIONS_CHANCE: (u32, u8) = (1_264_104, 2);
300    ///<https://wowlab.gg/inspect/spell/155271>
301    pub(crate) const AUSPICIOUS_SPIRITS_INSANITY: (u32, u8) = (155_271, 2);
302    ///<https://wowlab.gg/inspect/spell/373212>
303    pub(crate) const INSIDIOUS_IRE_BONUS: (u32, u8) = (373_212, 1);
304    ///<https://wowlab.gg/inspect/spell/15407>
305    pub(crate) const MIND_FLAY_TICK_INSANITY: (u32, u8) = (15407, 3);
306    ///<https://wowlab.gg/inspect/spell/32379>
307    pub(crate) const SHADOW_WORD_DEATH_DAMAGE: (u32, u8) = (32379, 2);
308    ///<https://wowlab.gg/inspect/spell/32379>
309    pub(crate) const SHADOW_WORD_DEATH_EXECUTE: (u32, u8) = (32379, 4);
310    ///<https://wowlab.gg/inspect/spell/32379>
311    pub(crate) const SHADOW_WORD_DEATH_THRESHOLD: (u32, u8) = (32379, 3);
312    ///<https://wowlab.gg/inspect/spell/391399>
313    pub(crate) const SURGE_OF_INSANITY_GEN: (u32, u8) = (391_399, 2);
314}
315static REPORTED_SPELLS: &[(&str, u32)] = &[];
316static DECLARED_SPELL_IDS: &[u32] = &[
317    8092, 589, 34914, 335_467, 228_260, 263_165, 15407, 32379, 120_644, 10060, 232_698,
318    21562, 413_231, 1_264_176, 1_264_177, 1_227_280, 1_227_621, 232_698, 194_249, 589,
319    34914, 335_467, 375_981, 373_204, 391_401, 393_919, 392_507, 238_558, 1_271_911,
320    10060, 289_577, 373_212, 391_092, 450_983, 407_430, 1_279_437, 1_227_280, 447_448,
321    449_887, 589, 8092, 15407, 32379, 34914, 155_271, 263_165, 335_467, 341_240, 343_690,
322    373_212, 390_964, 391_399, 413_231, 447_448, 448_403, 448_405, 449_912, 450_983,
323    459_314, 1_227_621, 1_264_104, 1_264_176, 1_264_177, 120_696, 391_403, 1_242_189,
324    1_242_173, 391_401, 453_112, 453_850, 454_002, 448_405, 447_448, 451_235, 459_314,
325    449_887, 450_138,
326];
327static DECLARED_AURA_IDS: &[u32] = &[
328    232_698, 194_249, 589, 34914, 335_467, 375_981, 373_204, 391_401, 393_919, 392_507,
329    238_558, 1_271_911, 10060, 289_577, 373_212, 391_092, 450_983, 407_430, 1_279_437,
330    1_227_280, 447_448, 449_887, 391_401, 453_112, 453_850, 454_002, 459_314, 449_887,
331    450_138,
332];
333static TALENTS: &[(&str, u32)] = &[
334    ("ANCIENT_MADNESS", TALENT::ANCIENT_MADNESS),
335    ("AUSPICIOUS_SPIRITS", TALENT::AUSPICIOUS_SPIRITS),
336    ("COLLAPSING_VOID", TALENT::COLLAPSING_VOID),
337    ("CRUSHING_VOID", TALENT::CRUSHING_VOID),
338    ("DARKENING_HORIZON", TALENT::DARKENING_HORIZON),
339    ("DEATHSPEAKER", TALENT::DEATHSPEAKER),
340    ("HALO", TALENT::HALO),
341    ("IDOL_OF_CTHUN", TALENT::IDOL_OF_CTHUN),
342    ("IDOL_OF_NZOTH", TALENT::IDOL_OF_NZOTH),
343    ("IDOL_OF_YOGGSARON", TALENT::IDOL_OF_YOGGSARON),
344    ("IMPROVED_VOIDFORM", TALENT::IMPROVED_VOIDFORM),
345    ("INSIDIOUS_IRE", TALENT::INSIDIOUS_IRE),
346    ("MADDENING_TENTACLES", TALENT::MADDENING_TENTACLES),
347    ("MADNESS_WEAVING", TALENT::MADNESS_WEAVING),
348    ("MIND_DEVOURER", TALENT::MIND_DEVOURER),
349    ("MISERY", TALENT::MISERY),
350    ("POWER_INFUSION", TALENT::POWER_INFUSION),
351    ("PSYCHIC_LINK", TALENT::PSYCHIC_LINK),
352    ("SCREAMS_OF_THE_VOID", TALENT::SCREAMS_OF_THE_VOID),
353    ("SHADOWY_APPARITIONS", TALENT::SHADOWY_APPARITIONS),
354    ("SHADOWY_INSIGHT", TALENT::SHADOWY_INSIGHT),
355    ("SHADOW_WORD_MADNESS", TALENT::SHADOW_WORD_MADNESS),
356    ("SHATTERED_PSYCHE", TALENT::SHATTERED_PSYCHE),
357    ("SURGE_OF_INSANITY", TALENT::SURGE_OF_INSANITY),
358    ("TENTACLE_SLAM", TALENT::TENTACLE_SLAM),
359    ("TORMENTED_SPIRITS", TALENT::TORMENTED_SPIRITS),
360    ("VOIDFORM", TALENT::VOIDFORM),
361    ("VOIDHEART", TALENT::VOIDHEART),
362    ("VOID_APPARITIONS_1", TALENT::VOID_APPARITIONS_1),
363    ("VOID_APPARITIONS_2", TALENT::VOID_APPARITIONS_2),
364    ("VOID_APPARITIONS_3", TALENT::VOID_APPARITIONS_3),
365    ("VOID_BLAST", TALENT::VOID_BLAST),
366    ("VOID_TORRENT", TALENT::VOID_TORRENT),
367];
368pub(crate) mod SHADOW_PRIEST {
369    pub(crate) const MIND_BLAST_CASTS: u32 = 0;
370    pub(crate) const SHADOW_WORD_MADNESS_CASTS: u32 = 1;
371    pub(crate) const VOIDFORM_CASTS: u32 = 2;
372    pub(crate) const VOID_TORRENT_CASTS: u32 = 3;
373    pub(crate) const SHADOW_WORD_DEATH_CASTS: u32 = 4;
374    pub(crate) const HALO_CASTS: u32 = 5;
375    pub(crate) const TENTACLE_SLAM_CASTS: u32 = 6;
376    pub(crate) const MIND_FLAY_CASTS: u32 = 7;
377    pub(crate) const VOIDFORM_UPTIME_MS: u32 = 8;
378    pub(crate) const SHADOW_WORD_PAIN_UPTIME_MS: u32 = 9;
379    pub(crate) const VAMPIRIC_TOUCH_UPTIME_MS: u32 = 10;
380}
381fn aura_shadowform(
382    a: AuraDefinitionDraft,
383    data: &ResolvedGameData,
384) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
385    Ok(
386        a
387            .on_player()
388            .apply_base_from_data(data, 232_698)?
389            .max_stacks(
390                data
391                    .require_aura_max_stacks(
392                        wowlab_types::sim::SpellIdx::from_raw(232_698),
393                    )?,
394            ),
395    )
396}
397fn aura_voidform(
398    a: AuraDefinitionDraft,
399    data: &ResolvedGameData,
400) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
401    Ok(
402        a
403            .on_player()
404            .apply_base_from_data(data, 194_249)?
405            .max_stacks(
406                data
407                    .require_aura_max_stacks(
408                        wowlab_types::sim::SpellIdx::from_raw(194_249),
409                    )?,
410            ),
411    )
412}
413fn aura_shadow_word_pain(
414    a: AuraDefinitionDraft,
415    data: &ResolvedGameData,
416) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
417    a.on_target()
418        .apply_base_from_data(data, 589)?
419        .max_stacks(
420            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(589))?,
421        )
422        .periodic_damage_sp(
423            wowlab_engine_combat::validated_milliseconds(
424                data.period(wowlab_types::sim::SpellIdx::from_raw(589), 2),
425                589,
426                "periodic_damage.tick_ms",
427            )?,
428            ((data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(589), 2)) * 10000.0)
429                .round() / 10000.0,
430            wowlab_engine_combat::DamageFlags::empty(),
431        )
432        .apply_periodic_behavior_from_data(data, 589)
433}
434fn aura_vampiric_touch(
435    a: AuraDefinitionDraft,
436    data: &ResolvedGameData,
437) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
438    a.on_target()
439        .apply_base_from_data(data, 34914)?
440        .max_stacks(
441            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(34914))?,
442        )
443        .periodic_damage_sp(
444            wowlab_engine_combat::validated_milliseconds(
445                data.period(wowlab_types::sim::SpellIdx::from_raw(34914), 2),
446                34914,
447                "periodic_damage.tick_ms",
448            )?,
449            ((data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(34914), 2)) * 10000.0)
450                .round() / 10000.0,
451            wowlab_engine_combat::DamageFlags::empty(),
452        )
453        .apply_periodic_behavior_from_data(data, 34914)
454}
455fn aura_shadow_word_madness(
456    a: AuraDefinitionDraft,
457    data: &ResolvedGameData,
458) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
459    a.on_target()
460        .apply_base_from_data(data, 335_467)?
461        .max_stacks(
462            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(335_467))?,
463        )
464        .periodic_damage_sp(
465            wowlab_engine_combat::validated_milliseconds(
466                data.period(wowlab_types::sim::SpellIdx::from_raw(335_467), 3),
467                335_467,
468                "periodic_damage.tick_ms",
469            )?,
470            ((data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(335_467), 3)) * 1000.0)
471                .round() / 1000.0,
472            wowlab_engine_combat::DamageFlags::empty(),
473        )
474        .apply_periodic_behavior_from_data(data, 335_467)
475}
476fn aura_shadowy_insight(
477    a: AuraDefinitionDraft,
478    data: &ResolvedGameData,
479) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
480    Ok(
481        a
482            .on_player()
483            .apply_base_from_data(data, 375_981)?
484            .max_stacks(
485                data
486                    .require_aura_max_stacks(
487                        wowlab_types::sim::SpellIdx::from_raw(375_981),
488                    )?,
489            ),
490    )
491}
492fn aura_mind_devourer(
493    a: AuraDefinitionDraft,
494    data: &ResolvedGameData,
495) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
496    Ok(
497        a
498            .on_player()
499            .apply_base_from_data(data, 373_204)?
500            .max_stacks(
501                data
502                    .require_aura_max_stacks(
503                        wowlab_types::sim::SpellIdx::from_raw(373_204),
504                    )?,
505            ),
506    )
507}
508fn aura_mind_flay_insanity(
509    a: AuraDefinitionDraft,
510    data: &ResolvedGameData,
511) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
512    Ok(
513        a
514            .on_player()
515            .apply_base_from_data(data, 391_401)?
516            .max_stacks(
517                data
518                    .require_aura_max_stacks(
519                        wowlab_types::sim::SpellIdx::from_raw(391_401),
520                    )?,
521            ),
522    )
523}
524fn aura_screams_of_the_void(
525    a: AuraDefinitionDraft,
526    data: &ResolvedGameData,
527) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
528    Ok(
529        a
530            .on_player()
531            .apply_base_from_data(data, 393_919)?
532            .max_stacks(
533                data
534                    .require_aura_max_stacks(
535                        wowlab_types::sim::SpellIdx::from_raw(393_919),
536                    )?,
537            ),
538    )
539}
540fn aura_deathspeaker(
541    a: AuraDefinitionDraft,
542    data: &ResolvedGameData,
543) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
544    Ok(
545        a
546            .on_player()
547            .apply_base_from_data(data, 392_507)?
548            .max_stacks(
549                data
550                    .require_aura_max_stacks(
551                        wowlab_types::sim::SpellIdx::from_raw(392_507),
552                    )?,
553            ),
554    )
555}
556fn aura_misery(
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, 238_558)?
564            .max_stacks(
565                data
566                    .require_aura_max_stacks(
567                        wowlab_types::sim::SpellIdx::from_raw(238_558),
568                    )?,
569            ),
570    )
571}
572fn aura_power_word_fortitude_highlight(
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, 1_271_911)?
580            .max_stacks(
581                data
582                    .require_aura_max_stacks(
583                        wowlab_types::sim::SpellIdx::from_raw(1_271_911),
584                    )?,
585            ),
586    )
587}
588fn aura_power_infusion(
589    a: AuraDefinitionDraft,
590    data: &ResolvedGameData,
591) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
592    Ok(
593        a
594            .on_player()
595            .apply_base_from_data(data, 10060)?
596            .max_stacks(
597                data
598                    .require_aura_max_stacks(
599                        wowlab_types::sim::SpellIdx::from_raw(10060),
600                    )?,
601            ),
602    )
603}
604fn aura_void_torrent(
605    a: AuraDefinitionDraft,
606    data: &ResolvedGameData,
607) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
608    Ok(
609        a
610            .on_player()
611            .apply_base_from_data(data, 289_577)?
612            .max_stacks(
613                data
614                    .require_aura_max_stacks(
615                        wowlab_types::sim::SpellIdx::from_raw(289_577),
616                    )?,
617            ),
618    )
619}
620fn aura_insidious_ire(
621    a: AuraDefinitionDraft,
622    data: &ResolvedGameData,
623) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
624    Ok(
625        a
626            .on_player()
627            .apply_base_from_data(data, 373_212)?
628            .max_stacks(
629                data
630                    .require_aura_max_stacks(
631                        wowlab_types::sim::SpellIdx::from_raw(373_212),
632                    )?,
633            ),
634    )
635}
636fn aura_shattered_psyche(
637    a: AuraDefinitionDraft,
638    data: &ResolvedGameData,
639) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
640    Ok(
641        a
642            .on_player()
643            .apply_base_from_data(data, 391_092)?
644            .max_stacks(
645                data
646                    .require_aura_max_stacks(
647                        wowlab_types::sim::SpellIdx::from_raw(391_092),
648                    )?,
649            ),
650    )
651}
652fn aura_void_blast(
653    a: AuraDefinitionDraft,
654    data: &ResolvedGameData,
655) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
656    a.on_player()
657        .duration_ms(
658            wowlab_engine_combat::validated_milliseconds(
659                f64::from(
660                    data
661                        .require_aura_duration_ms(
662                            wowlab_types::sim::SpellIdx::from_raw(459_314),
663                        )?,
664                ),
665                450_983,
666                "aura.duration_ms",
667            )?,
668        )
669        .apply_periodic_effect_from_data(data, 450_983)?
670        .apply_duration_behavior_from_data(data, 459_314)?
671        .apply_timing_modifiers_from_data(data, 450_983)?
672        .max_stacks(
673            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(450_983))?,
674        )
675        .apply_periodic_behavior_from_data(data, 459_314)
676}
677fn aura_voidtouched(
678    a: AuraDefinitionDraft,
679    data: &ResolvedGameData,
680) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
681    Ok(
682        a
683            .on_player()
684            .apply_base_from_data(data, 407_430)?
685            .max_stacks(
686                data
687                    .require_aura_max_stacks(
688                        wowlab_types::sim::SpellIdx::from_raw(407_430),
689                    )?,
690            ),
691    )
692}
693fn aura_crushing_void(
694    a: AuraDefinitionDraft,
695    data: &ResolvedGameData,
696) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
697    Ok(
698        a
699            .on_player()
700            .apply_base_from_data(data, 1_279_437)?
701            .max_stacks(
702                data
703                    .require_aura_max_stacks(
704                        wowlab_types::sim::SpellIdx::from_raw(1_279_437),
705                    )?,
706            ),
707    )
708}
709fn aura_tentacle_slam(
710    a: AuraDefinitionDraft,
711    data: &ResolvedGameData,
712) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
713    Ok(
714        a
715            .on_player()
716            .apply_base_from_data(data, 1_227_280)?
717            .max_stacks(
718                data
719                    .require_aura_max_stacks(
720                        wowlab_types::sim::SpellIdx::from_raw(1_227_280),
721                    )?,
722            ),
723    )
724}
725fn aura_entropic_rift(
726    a: AuraDefinitionDraft,
727    data: &ResolvedGameData,
728) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
729    Ok(
730        a
731            .on_player()
732            .duration_ms(
733                wowlab_engine_combat::validated_milliseconds(
734                    f64::from(
735                        data
736                            .require_aura_duration_ms(
737                                wowlab_types::sim::SpellIdx::from_raw(459_314),
738                            )?,
739                    ),
740                    447_448,
741                    "aura.duration_ms",
742                )?,
743            )
744            .apply_periodic_effect_from_data(data, 447_448)?
745            .apply_duration_behavior_from_data(data, 459_314)?
746            .apply_timing_modifiers_from_data(data, 447_448)?
747            .max_stacks(
748                data
749                    .require_aura_max_stacks(
750                        wowlab_types::sim::SpellIdx::from_raw(447_448),
751                    )?,
752            )
753            .no_pandemic()
754            .periodic_damage_sp_from_data(
755                data,
756                wowlab_engine_combat::PeriodicDamageDataInput {
757                    tick_ms: wowlab_engine_combat::validated_milliseconds(
758                        data.period(wowlab_types::sim::SpellIdx::from_raw(459_314), 1),
759                        447_448,
760                        "periodic_damage.tick_ms",
761                    )?,
762                    spell_id: 447_448,
763                    effect_index: 1,
764                    multiplier: 1.0,
765                    offset: 0.0,
766                    round_decimals: Some(1),
767                },
768            )?
769            .apply_periodic_behavior_from_data(data, 459_314)?
770            .on_expire(crate::hooks::shadow_priest::entropic_rift_expire_hook),
771    )
772}
773fn aura_voidheart(
774    a: AuraDefinitionDraft,
775    data: &ResolvedGameData,
776) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
777    Ok(
778        a
779            .on_player()
780            .apply_base_from_data(data, 449_887)?
781            .max_stacks(
782                data
783                    .require_aura_max_stacks(
784                        wowlab_types::sim::SpellIdx::from_raw(449_887),
785                    )?,
786            )
787            .no_pandemic(),
788    )
789}
790fn spell_mind_blast(
791    s: SpellDefinitionDraft,
792    data: &ResolvedGameData,
793) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
794    Ok(
795        s
796            .apply_base_from_data(data, 8092)?
797            .hasted_cooldown()
798            .damage_sp(0.0, wowlab_engine_combat::DamageFlags::empty())
799            .apply_aoe_from_data(data)
800            .on_cast(crate::hooks::shadow_priest::mind_blast_hook),
801    )
802}
803fn spell_shadow_word_pain(
804    s: SpellDefinitionDraft,
805    data: &ResolvedGameData,
806) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
807    Ok(
808        s
809            .apply_base_from_data(data, 589)?
810            .applies_inferred_aura(AURA_SHADOW_WORD_PAIN, 589)
811            .apply_aoe_from_data(data)
812            .on_cast(crate::hooks::shadow_priest::shadow_word_pain_hook),
813    )
814}
815fn spell_vampiric_touch(
816    s: SpellDefinitionDraft,
817    data: &ResolvedGameData,
818) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
819    Ok(
820        s
821            .apply_base_from_data(data, 34914)?
822            .damage_sp(0.0, wowlab_engine_combat::DamageFlags::empty())
823            .applies_inferred_aura(AURA_VAMPIRIC_TOUCH, 34914)
824            .apply_aoe_from_data(data)
825            .on_cast(crate::hooks::shadow_priest::vampiric_touch_hook),
826    )
827}
828fn spell_shadow_word_madness(
829    s: SpellDefinitionDraft,
830    data: &ResolvedGameData,
831) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
832    Ok(
833        s
834            .apply_base_from_data(data, 335_467)?
835            .cost(
836                wowlab_engine_combat::validated_nonnegative(40.0, 335_467, "spell.cost")?,
837            )
838            .applies_inferred_aura(AURA_SHADOW_WORD_MADNESS, 335_467)
839            .apply_aoe_from_data(data)
840            .on_cast(crate::hooks::shadow_priest::shadow_word_madness_hook),
841    )
842}
843fn spell_voidform(
844    s: SpellDefinitionDraft,
845    data: &ResolvedGameData,
846) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
847    Ok(
848        s
849            .apply_base_from_data(data, 228_260)?
850            .gain(data.base_points(wowlab_types::sim::SpellIdx::from_raw(341_240), 1))
851            .applies_aura(AURA_VOIDFORM)
852            .apply_aoe_from_data(data),
853    )
854}
855fn spell_void_torrent(
856    s: SpellDefinitionDraft,
857    data: &ResolvedGameData,
858) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
859    Ok(
860        s
861            .apply_base_from_data(data, 263_165)?
862            .damage_sp(0.0, wowlab_engine_combat::DamageFlags::empty())
863            .applies_inferred_aura(AURA_VOID_TORRENT, 289_577)
864            .apply_aoe_from_data(data)
865            .channel(
866                wowlab_engine_combat::validated_channel_tick_count(
867                    4.0,
868                    263_165,
869                    "channel.tick_count",
870                )?,
871            )
872            .channel_tick_damage_sp_from_data(
873                wowlab_engine_domain::dbc::EffectLookup::new(
874                    data,
875                    wowlab_types::sim::EffectRef::new(
876                        wowlab_types::sim::SpellIdx::from_raw(263_165),
877                        1,
878                    ),
879                ),
880            )?
881            .channel_complete_extend_aura(
882                AURA_ENTROPIC_RIFT,
883                wowlab_engine_combat::validated_milliseconds(
884                    f64::from(
885                        data
886                            .require_aura_duration_ms(
887                                wowlab_types::sim::SpellIdx::from_raw(263_165),
888                            )?,
889                    ),
890                    263_165,
891                    "channel.complete_effects.extend_aura.amount_ms",
892                )?,
893            )
894            .channel_complete_extend_aura(
895                AURA_VOIDHEART,
896                wowlab_engine_combat::validated_milliseconds(
897                    f64::from(
898                        data
899                            .require_aura_duration_ms(
900                                wowlab_types::sim::SpellIdx::from_raw(263_165),
901                            )?,
902                    ),
903                    263_165,
904                    "channel.complete_effects.extend_aura.amount_ms",
905                )?,
906            )
907            .on_cast(crate::hooks::shadow_priest::void_torrent_hook),
908    )
909}
910fn spell_mind_flay(
911    s: SpellDefinitionDraft,
912    data: &ResolvedGameData,
913) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
914    Ok(
915        s
916            .apply_base_from_data(data, 15407)?
917            .damage_sp(0.0, wowlab_engine_combat::DamageFlags::empty())
918            .apply_aoe_from_data(data)
919            .channel(
920                wowlab_engine_combat::validated_channel_tick_count(
921                    6.0,
922                    15407,
923                    "channel.tick_count",
924                )?,
925            )
926            .channel_tick_damage_sp_from_data(
927                wowlab_engine_domain::dbc::EffectLookup::new(
928                    data,
929                    wowlab_types::sim::EffectRef::new(
930                        wowlab_types::sim::SpellIdx::from_raw(15407),
931                        1,
932                    ),
933                ),
934            )?
935            .on_channel_tick(crate::hooks::shadow_priest::mind_flay_tick_hook),
936    )
937}
938fn spell_shadow_word_death(
939    s: SpellDefinitionDraft,
940    data: &ResolvedGameData,
941) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
942    Ok(
943        s
944            .apply_base_from_data(data, 32379)?
945            .gain(4.0)
946            .damage_sp(0.0, wowlab_engine_combat::DamageFlags::empty())
947            .apply_aoe_from_data(data)
948            .on_cast(crate::hooks::shadow_priest::shadow_word_death_hook),
949    )
950}
951fn spell_halo(
952    s: SpellDefinitionDraft,
953    data: &ResolvedGameData,
954) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
955    Ok(
956        s
957            .apply_base_from_data(data, 120_644)?
958            .damage_sp_from_data(
959                wowlab_engine_domain::dbc::EffectLookup::new(
960                    data,
961                    wowlab_types::sim::EffectRef::new(
962                        wowlab_types::sim::SpellIdx::from_raw(390_964),
963                        1,
964                    ),
965                ),
966            )?
967            .apply_aoe_from_data(data),
968    )
969}
970fn spell_power_infusion(
971    s: SpellDefinitionDraft,
972    data: &ResolvedGameData,
973) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
974    Ok(
975        s
976            .apply_base_from_data(data, 10060)?
977            .applies_inferred_aura(AURA_POWER_INFUSION, 10060)
978            .apply_aoe_from_data(data),
979    )
980}
981fn spell_shadowform(
982    s: SpellDefinitionDraft,
983    data: &ResolvedGameData,
984) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
985    Ok(
986        s
987            .apply_base_from_data(data, 232_698)?
988            .applies_inferred_aura(AURA_SHADOWFORM, 232_698)
989            .apply_aoe_from_data(data),
990    )
991}
992fn spell_power_word_fortitude(
993    s: SpellDefinitionDraft,
994    data: &ResolvedGameData,
995) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
996    Ok(s.apply_base_from_data(data, 21562)?.apply_aoe_from_data(data))
997}
998fn spell_shadowy_apparition(
999    s: SpellDefinitionDraft,
1000    data: &ResolvedGameData,
1001) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1002    Ok(s.apply_base_from_data(data, 413_231)?.apply_aoe_from_data(data))
1003}
1004fn spell_void_apparition(
1005    s: SpellDefinitionDraft,
1006    data: &ResolvedGameData,
1007) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1008    Ok(s.apply_base_from_data(data, 1_264_176)?.apply_aoe_from_data(data))
1009}
1010fn spell_void_bolt(
1011    s: SpellDefinitionDraft,
1012    data: &ResolvedGameData,
1013) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1014    Ok(s.apply_base_from_data(data, 1_264_177)?.apply_aoe_from_data(data))
1015}
1016fn spell_tentacle_slam(
1017    s: SpellDefinitionDraft,
1018    data: &ResolvedGameData,
1019) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1020    Ok(
1021        s
1022            .apply_base_from_data(data, 1_227_280)?
1023            .applies_aura(AURA_VAMPIRIC_TOUCH)
1024            .apply_aoe_from_data(data)
1025            .on_cast(crate::hooks::shadow_priest::tentacle_slam_hook),
1026    )
1027}
1028fn spell_tentacle_slam_damage(
1029    s: SpellDefinitionDraft,
1030    data: &ResolvedGameData,
1031) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1032    Ok(s.apply_base_from_data(data, 1_227_621)?.apply_aoe_from_data(data))
1033}
1034pub(crate) fn build_combat_system(
1035    params: &wowlab_engine_ports::HandlerParams<'_>,
1036) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1037    let builder = BuiltCombatSystem::builder(params.stats.clone())
1038        .spec_id(SpecId::Shadow)
1039        .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1040        .mastery_spell(343_690)
1041        .mastery_hook(crate::hooks::shadow_priest::mastery)
1042        .resource(
1043            "insanity",
1044            100.0,
1045            params
1046                .game_data
1047                .power_regen_for_max(13, 100.0)
1048                .ok_or_else(|| {
1049                    wowlab_engine_ports::EngineError::spec_construction(
1050                        "missing power-type power_regen_for_max for type_id 13",
1051                    )
1052                })?,
1053        )
1054        .resource_type_id(13)
1055        .resource_start(0.0)
1056        .aura("shadowform", AURA::SHADOWFORM, |a| aura_shadowform(a, &params.game_data))
1057        .aura("voidform", AURA::VOIDFORM, |a| aura_voidform(a, &params.game_data))
1058        .aura(
1059            "shadow_word_pain",
1060            AURA::SHADOW_WORD_PAIN,
1061            |a| aura_shadow_word_pain(a, &params.game_data),
1062        )
1063        .aura(
1064            "vampiric_touch",
1065            AURA::VAMPIRIC_TOUCH,
1066            |a| aura_vampiric_touch(a, &params.game_data),
1067        )
1068        .aura(
1069            "shadow_word_madness",
1070            AURA::SHADOW_WORD_MADNESS,
1071            |a| aura_shadow_word_madness(a, &params.game_data),
1072        )
1073        .aura(
1074            "shadowy_insight",
1075            AURA::SHADOWY_INSIGHT,
1076            |a| aura_shadowy_insight(a, &params.game_data),
1077        )
1078        .aura(
1079            "mind_devourer",
1080            AURA::MIND_DEVOURER,
1081            |a| aura_mind_devourer(a, &params.game_data),
1082        )
1083        .aura(
1084            "mind_flay_insanity",
1085            AURA::MIND_FLAY_INSANITY,
1086            |a| aura_mind_flay_insanity(a, &params.game_data),
1087        )
1088        .aura(
1089            "screams_of_the_void",
1090            AURA::SCREAMS_OF_THE_VOID,
1091            |a| aura_screams_of_the_void(a, &params.game_data),
1092        )
1093        .aura(
1094            "deathspeaker",
1095            AURA::DEATHSPEAKER,
1096            |a| aura_deathspeaker(a, &params.game_data),
1097        )
1098        .aura("misery", AURA::MISERY, |a| aura_misery(a, &params.game_data))
1099        .aura(
1100            "power_word_fortitude_highlight",
1101            AURA::POWER_WORD_FORTITUDE_HIGHLIGHT,
1102            |a| aura_power_word_fortitude_highlight(a, &params.game_data),
1103        )
1104        .aura(
1105            "power_infusion",
1106            AURA::POWER_INFUSION,
1107            |a| aura_power_infusion(a, &params.game_data),
1108        )
1109        .aura(
1110            "void_torrent",
1111            AURA::VOID_TORRENT,
1112            |a| aura_void_torrent(a, &params.game_data),
1113        )
1114        .aura(
1115            "insidious_ire",
1116            AURA::INSIDIOUS_IRE,
1117            |a| aura_insidious_ire(a, &params.game_data),
1118        )
1119        .aura(
1120            "shattered_psyche",
1121            AURA::SHATTERED_PSYCHE,
1122            |a| aura_shattered_psyche(a, &params.game_data),
1123        )
1124        .aura("void_blast", AURA::VOID_BLAST, |a| aura_void_blast(a, &params.game_data))
1125        .aura(
1126            "voidtouched",
1127            AURA::VOIDTOUCHED,
1128            |a| aura_voidtouched(a, &params.game_data),
1129        )
1130        .aura(
1131            "crushing_void",
1132            AURA::CRUSHING_VOID,
1133            |a| aura_crushing_void(a, &params.game_data),
1134        )
1135        .aura(
1136            "tentacle_slam",
1137            AURA::TENTACLE_SLAM,
1138            |a| aura_tentacle_slam(a, &params.game_data),
1139        )
1140        .aura(
1141            "entropic_rift",
1142            AURA::ENTROPIC_RIFT,
1143            |a| aura_entropic_rift(a, &params.game_data),
1144        )
1145        .aura("voidheart", AURA::VOIDHEART, |a| aura_voidheart(a, &params.game_data))
1146        .spell(
1147            "mind_blast",
1148            SPELL::MIND_BLAST,
1149            |s| spell_mind_blast(s, &params.game_data),
1150        )
1151        .spell(
1152            "shadow_word_pain",
1153            SPELL::SHADOW_WORD_PAIN,
1154            |s| spell_shadow_word_pain(s, &params.game_data),
1155        )
1156        .spell(
1157            "vampiric_touch",
1158            SPELL::VAMPIRIC_TOUCH,
1159            |s| spell_vampiric_touch(s, &params.game_data),
1160        )
1161        .spell(
1162            "shadow_word_madness",
1163            SPELL::SHADOW_WORD_MADNESS,
1164            |s| spell_shadow_word_madness(s, &params.game_data),
1165        )
1166        .spell("voidform", SPELL::VOIDFORM, |s| spell_voidform(s, &params.game_data))
1167        .spell(
1168            "void_torrent",
1169            SPELL::VOID_TORRENT,
1170            |s| spell_void_torrent(s, &params.game_data),
1171        )
1172        .spell("mind_flay", SPELL::MIND_FLAY, |s| spell_mind_flay(s, &params.game_data))
1173        .spell(
1174            "shadow_word_death",
1175            SPELL::SHADOW_WORD_DEATH,
1176            |s| spell_shadow_word_death(s, &params.game_data),
1177        )
1178        .spell("halo", SPELL::HALO, |s| spell_halo(s, &params.game_data))
1179        .spell(
1180            "power_infusion",
1181            SPELL::POWER_INFUSION,
1182            |s| spell_power_infusion(s, &params.game_data),
1183        )
1184        .spell(
1185            "shadowform",
1186            SPELL::SHADOWFORM,
1187            |s| spell_shadowform(s, &params.game_data),
1188        )
1189        .spell(
1190            "power_word_fortitude",
1191            SPELL::POWER_WORD_FORTITUDE,
1192            |s| spell_power_word_fortitude(s, &params.game_data),
1193        )
1194        .spell(
1195            "shadowy_apparition",
1196            SPELL::SHADOWY_APPARITION,
1197            |s| spell_shadowy_apparition(s, &params.game_data),
1198        )
1199        .spell(
1200            "void_apparition",
1201            SPELL::VOID_APPARITION,
1202            |s| spell_void_apparition(s, &params.game_data),
1203        )
1204        .spell("void_bolt", SPELL::VOID_BOLT, |s| spell_void_bolt(s, &params.game_data))
1205        .spell(
1206            "tentacle_slam",
1207            SPELL::TENTACLE_SLAM,
1208            |s| spell_tentacle_slam(s, &params.game_data),
1209        )
1210        .spell(
1211            "tentacle_slam_damage",
1212            SPELL::TENTACLE_SLAM_DAMAGE,
1213            |s| spell_tentacle_slam_damage(s, &params.game_data),
1214        )
1215        .game_data(params.game_data.clone())
1216        .talent_spell_ids(TALENTS)
1217        .talent_selections(params.talent_selections)
1218        .set_bonus_auras(params.set_bonus_auras)
1219        .encounter(params.encounter.clone());
1220    let builder = crate::generated::items::register_equipped(
1221        builder,
1222        &params.game_data,
1223        params.equipped_items,
1224    )?;
1225
1226    builder
1227        .build(params.rotation)
1228        .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1229}
1230fn new_handler(
1231    params: wowlab_engine_ports::HandlerParams<'_>,
1232) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1233    let handler = crate::composition::compose_handler(
1234        build_combat_system,
1235        &params,
1236        |parts, params| Ok(
1237            crate::hooks::shadow_priest::ShadowPriestHandler::new(parts, params),
1238        ),
1239    )?;
1240
1241    Ok(Box::new(handler))
1242}
1243static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1244    primary_resource: ResourceType::Insanity,
1245    secondary_resource: None,
1246    spell_ids: DECLARED_SPELL_IDS,
1247    aura_ids: DECLARED_AURA_IDS,
1248    server_proc_entries: &[],
1249    talents: TALENTS,
1250    rotation_field_schema: &[],
1251    metrics_plugin_id: None,
1252    hero_talent_trees: &[
1253        HeroTalentTreeDesc {
1254            name: "Archon",
1255            spells: HERO_TREE_ARCHON_SPELLS,
1256            auras: HERO_TREE_ARCHON_AURAS,
1257        },
1258        HeroTalentTreeDesc {
1259            name: "Voidweaver",
1260            spells: HERO_TREE_VOIDWEAVER_SPELLS,
1261            auras: HERO_TREE_VOIDWEAVER_AURAS,
1262        },
1263    ],
1264    reported_spells: REPORTED_SPELLS,
1265    masked_passive_effects: &[],
1266    passive_effect_overrides: &[],
1267};
1268pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1269    spec_id: SpecId::Shadow,
1270    display_name: "Shadow Priest",
1271    metadata: DECLARED_METADATA,
1272    handler_factory: new_handler,
1273};
1274wowlab_engine_combat::smoke_test!(build_combat_system);