1#![allow(non_snake_case, dead_code)]
4use wowlab_types::{combat::ResourceType, game::SpecId};
5use wowlab_engine_domain::dbc::ProcAttributes;
6use wowlab_engine_combat::{
7 BuiltCombatSystem, AuraDefinitionDraft, LocalAuraIdx, LocalSpellIdx,
8 SpellDefinitionDraft,
9};
10use wowlab_engine_ports::{
11 DeclaredSpecMetadata, SpecDescriptor, SpecHandler, HeroTalentTreeDesc,
12 DeclaredServerProcEntry,
13};
14use wowlab_engine_gamedata::ResolvedGameData;
15pub(crate) mod SPELL {
16 pub(crate) const LIVING_FLAME: u32 = 361_469;
18 pub(crate) const AZURE_STRIKE: u32 = 362_969;
20 pub(crate) const DISINTEGRATE: u32 = 356_995;
22 pub(crate) const FIRE_BREATH: u32 = 357_208;
24 pub(crate) const ETERNITY_SURGE: u32 = 359_073;
26 pub(crate) const PYRE: u32 = 357_211;
28 pub(crate) const DRAGONRAGE: u32 = 375_087;
30 pub(crate) const TIP_THE_SCALES: u32 = 370_553;
32 pub(crate) const SCINTILLATION: u32 = 370_821;
34 pub(crate) const SHATTERING_STAR: u32 = 1_265_804;
36 pub(crate) const BLESSING_OF_THE_BRONZE: u32 = 381_748;
38 pub(crate) const DEEP_BREATH: u32 = 357_210;
40}
41pub(crate) mod AURA {
42 pub(crate) const DRAGONRAGE: u32 = 375_087;
44 pub(crate) const ESSENCE_BURST: u32 = 359_618;
46 pub(crate) const BURNOUT: u32 = 375_802;
48 pub(crate) const CHARGED_BLAST: u32 = 370_454;
50 pub(crate) const IRIDESCENCE_BLUE: u32 = 386_399;
52 pub(crate) const IRIDESCENCE_RED: u32 = 386_353;
54 pub(crate) const LEAPING_FLAMES: u32 = 370_901;
56 pub(crate) const ANCIENT_FLAME: u32 = 375_583;
58 pub(crate) const TIP_THE_SCALES: u32 = 370_553;
60 pub(crate) const POWER_SWELL: u32 = 376_850;
62 pub(crate) const IMMINENT_DESTRUCTION: u32 = 411_055;
64 pub(crate) const FIRE_BREATH: u32 = 357_209;
66 pub(crate) const CONSUME_FLAME: u32 = 444_088;
68 pub(crate) const AZURE_SWEEP: u32 = 1_265_871;
70 pub(crate) const RECALL: u32 = 371_807;
72 pub(crate) const BLESSING_OF_THE_BRONZE: u32 = 381_748;
74 pub(crate) const BLESSING_OF_THE_BRONZE_HIGHLIGHT: u32 = 381_748;
76 pub(crate) const RISING_FURY: u32 = 1_271_783;
78 pub(crate) const DEEP_BREATH_TRIGGER: u32 = 353_759;
80 pub(crate) const MELT_ARMOR_DOT: u32 = 441_172;
82 pub(crate) const STRAFING_RUN: u32 = 1_266_165;
84 pub(crate) const BOMBARDMENTS: u32 = 434_473;
86 pub(crate) const MASS_DISINTEGRATE: u32 = 436_336;
88}
89pub(crate) mod TALENT {
90 pub(crate) const ANIMOSITY: u32 = 375_797;
92 pub(crate) const AZURE_CELERITY: u32 = 1_219_723;
94 pub(crate) const AZURE_ESSENCE_BURST: u32 = 375_721;
96 pub(crate) const AZURE_SWEEP: u32 = 1_265_867;
98 pub(crate) const BLAST_FURNACE: u32 = 375_510;
100 pub(crate) const BOMBARDMENTS_GATE: u32 = 434_300;
102 pub(crate) const BURNOUT: u32 = 375_801;
104 pub(crate) const CATALYZE: u32 = 386_283;
106 pub(crate) const CAUSALITY: u32 = 375_777;
108 pub(crate) const CHARGED_BLAST: u32 = 370_455;
110 pub(crate) const DRAGONRAGE: u32 = 375_087;
112 pub(crate) const ESSENCE_ATTUNEMENT: u32 = 375_722;
114 pub(crate) const ETERNITY_SPAN: u32 = 375_757;
116 pub(crate) const ETERNITY_SURGE: u32 = 359_073;
118 pub(crate) const EYE_OF_INFINITY: u32 = 411_165;
120 pub(crate) const FEED_THE_FLAMES: u32 = 369_846;
122 pub(crate) const FONT_OF_MAGIC: u32 = 411_212;
124 pub(crate) const IMMINENT_DESTRUCTION: u32 = 370_781;
126 pub(crate) const IRIDESCENCE: u32 = 370_867;
128 pub(crate) const LEAPING_FLAMES: u32 = 369_939;
130 pub(crate) const MANEUVERABILITY_GATE: u32 = 433_871;
132 pub(crate) const MASS_DISINTEGRATE_GATE: u32 = 436_335;
134 pub(crate) const MELT_ARMOR_GATE: u32 = 441_176;
136 pub(crate) const POWER_NEXUS: u32 = 369_908;
138 pub(crate) const POWER_SWELL: u32 = 370_839;
140 pub(crate) const PYRE: u32 = 357_211;
142 pub(crate) const RISING_FURY: u32 = 1_271_687;
144 pub(crate) const RUBY_ESSENCE_BURST: u32 = 376_872;
146 pub(crate) const SCINTILLATION: u32 = 370_821;
148 pub(crate) const SCORCHING_EMBERS: u32 = 370_819;
150 pub(crate) const SHATTERING_STARS: u32 = 1_265_802;
152 pub(crate) const STRAFING_RUN_GATE: u32 = 1_266_151;
154 pub(crate) const TIP_THE_SCALES: u32 = 370_553;
156 pub(crate) const TITANIC_WRATH: u32 = 386_272;
158 pub(crate) const TYRANNY: u32 = 376_888;
160 pub(crate) const VOLATILITY: u32 = 369_089;
162}
163pub(crate) mod REPORTED_SPELL {
164 pub(crate) const ETERNITY_SURGE_DAMAGE: u32 = 359_077;
166 pub(crate) const FIRE_BREATH_DAMAGE: u32 = 357_209;
168 pub(crate) const LIVING_FLAME_DAMAGE: u32 = 361_500;
170 pub(crate) const PYRE_DAMAGE: u32 = 357_212;
172}
173pub(crate) mod HERO {
174 pub(crate) mod FLAMESHAPER {
175 pub(crate) mod SPELL {
176 pub(crate) const ENKINDLE: u32 = 444_017;
178 pub(crate) const TWIN_FLAME: u32 = 1_265_980;
180 }
181 pub(crate) mod AURA {
182 pub(crate) const BURNOUT: u32 = 375_802;
184 pub(crate) const CONSUME_FLAME: u32 = 444_088;
186 pub(crate) const ESSENCE_WELL: u32 = 1_265_993;
188 pub(crate) const INNER_FLAME: u32 = 1_236_776;
190 }
191 }
192 pub(crate) mod CHRONOWARDEN {
193 pub(crate) mod SPELL {
194 pub(crate) const CHRONO_FLAME: u32 = 431_583;
196 pub(crate) const TEMPORAL_BURST: u32 = 431_698;
198 }
199 pub(crate) mod AURA {
200 pub(crate) const PRIMACY: u32 = 431_654;
202 pub(crate) const TEMPORAL_BURST: u32 = 431_698;
204 pub(crate) const TIME_CONVERGENCE: u32 = 431_991;
206 }
207 }
208 pub(crate) mod SCALECOMMANDER {
209 pub(crate) mod SPELL {
210 pub(crate) const BOMBARDMENTS_DAMAGE: u32 = 434_481;
212 pub(crate) const MASS_DISINTEGRATE: u32 = 436_336;
214 pub(crate) const MELT_ARMOR_DOT: u32 = 441_172;
216 }
217 pub(crate) mod AURA {
218 pub(crate) const BOMBARDMENTS: u32 = 434_473;
220 pub(crate) const MASS_DISINTEGRATE: u32 = 436_336;
222 pub(crate) const MELT_ARMOR: u32 = 441_172;
224 pub(crate) const STRAFING_RUN: u32 = 1_266_165;
226 pub(crate) const UNRELENTING_SIEGE: u32 = 441_248;
228 }
229 }
230}
231static HERO_TREE_FLAMESHAPER_SPELLS: &[(&str, u32)] = &[
232 ("ENKINDLE", 444_017),
233 ("TWIN_FLAME", 1_265_980),
234];
235static HERO_TREE_FLAMESHAPER_AURAS: &[(&str, u32)] = &[
236 ("BURNOUT", 375_802),
237 ("CONSUME_FLAME", 444_088),
238 ("ESSENCE_WELL", 1_265_993),
239 ("INNER_FLAME", 1_236_776),
240];
241static HERO_TREE_CHRONOWARDEN_SPELLS: &[(&str, u32)] = &[
242 ("CHRONO_FLAME", 431_583),
243 ("TEMPORAL_BURST", 431_698),
244];
245static HERO_TREE_CHRONOWARDEN_AURAS: &[(&str, u32)] = &[
246 ("PRIMACY", 431_654),
247 ("TEMPORAL_BURST", 431_698),
248 ("TIME_CONVERGENCE", 431_991),
249];
250static HERO_TREE_SCALECOMMANDER_SPELLS: &[(&str, u32)] = &[
251 ("BOMBARDMENTS_DAMAGE", 434_481),
252 ("MASS_DISINTEGRATE", 436_336),
253 ("MELT_ARMOR_DOT", 441_172),
254];
255static HERO_TREE_SCALECOMMANDER_AURAS: &[(&str, u32)] = &[
256 ("BOMBARDMENTS", 434_473),
257 ("MASS_DISINTEGRATE", 436_336),
258 ("MELT_ARMOR", 441_172),
259 ("STRAFING_RUN", 1_266_165),
260 ("UNRELENTING_SIEGE", 441_248),
261];
262pub(crate) const AURA_DRAGONRAGE: LocalAuraIdx = LocalAuraIdx::new(0);
263pub(crate) const AURA_ESSENCE_BURST: LocalAuraIdx = LocalAuraIdx::new(1);
264pub(crate) const AURA_BURNOUT: LocalAuraIdx = LocalAuraIdx::new(2);
265pub(crate) const AURA_CHARGED_BLAST: LocalAuraIdx = LocalAuraIdx::new(3);
266pub(crate) const AURA_IRIDESCENCE_BLUE: LocalAuraIdx = LocalAuraIdx::new(4);
267pub(crate) const AURA_IRIDESCENCE_RED: LocalAuraIdx = LocalAuraIdx::new(5);
268pub(crate) const AURA_LEAPING_FLAMES: LocalAuraIdx = LocalAuraIdx::new(6);
269pub(crate) const AURA_ANCIENT_FLAME: LocalAuraIdx = LocalAuraIdx::new(7);
270pub(crate) const AURA_TIP_THE_SCALES: LocalAuraIdx = LocalAuraIdx::new(8);
271pub(crate) const AURA_POWER_SWELL: LocalAuraIdx = LocalAuraIdx::new(9);
272pub(crate) const AURA_IMMINENT_DESTRUCTION: LocalAuraIdx = LocalAuraIdx::new(10);
273pub(crate) const AURA_FIRE_BREATH: LocalAuraIdx = LocalAuraIdx::new(11);
274pub(crate) const AURA_CONSUME_FLAME: LocalAuraIdx = LocalAuraIdx::new(12);
275pub(crate) const AURA_AZURE_SWEEP: LocalAuraIdx = LocalAuraIdx::new(13);
276pub(crate) const AURA_RECALL: LocalAuraIdx = LocalAuraIdx::new(14);
277pub(crate) const AURA_BLESSING_OF_THE_BRONZE: LocalAuraIdx = LocalAuraIdx::new(15);
278pub(crate) const AURA_BLESSING_OF_THE_BRONZE_HIGHLIGHT: LocalAuraIdx = LocalAuraIdx::new(
279 16,
280);
281pub(crate) const AURA_RISING_FURY: LocalAuraIdx = LocalAuraIdx::new(17);
282pub(crate) const AURA_DEEP_BREATH_TRIGGER: LocalAuraIdx = LocalAuraIdx::new(18);
283pub(crate) const AURA_MELT_ARMOR_DOT: LocalAuraIdx = LocalAuraIdx::new(19);
284pub(crate) const AURA_STRAFING_RUN: LocalAuraIdx = LocalAuraIdx::new(20);
285pub(crate) const AURA_BOMBARDMENTS: LocalAuraIdx = LocalAuraIdx::new(21);
286pub(crate) const AURA_MASS_DISINTEGRATE: LocalAuraIdx = LocalAuraIdx::new(22);
287pub(crate) const AURA_COUNT: usize = 23;
288const _: () = assert!(
289 AURA_COUNT == 23, "AURA index ABI: count changed -- update positional hook consumers"
290);
291pub(crate) const SPELL_LIVING_FLAME: LocalSpellIdx = LocalSpellIdx::new(0);
292pub(crate) const SPELL_AZURE_STRIKE: LocalSpellIdx = LocalSpellIdx::new(1);
293pub(crate) const SPELL_DISINTEGRATE: LocalSpellIdx = LocalSpellIdx::new(2);
294pub(crate) const SPELL_FIRE_BREATH: LocalSpellIdx = LocalSpellIdx::new(3);
295pub(crate) const SPELL_ETERNITY_SURGE: LocalSpellIdx = LocalSpellIdx::new(4);
296pub(crate) const SPELL_PYRE: LocalSpellIdx = LocalSpellIdx::new(5);
297pub(crate) const SPELL_DRAGONRAGE: LocalSpellIdx = LocalSpellIdx::new(6);
298pub(crate) const SPELL_TIP_THE_SCALES: LocalSpellIdx = LocalSpellIdx::new(7);
299pub(crate) const SPELL_SCINTILLATION: LocalSpellIdx = LocalSpellIdx::new(8);
300pub(crate) const SPELL_SHATTERING_STAR: LocalSpellIdx = LocalSpellIdx::new(9);
301pub(crate) const SPELL_BLESSING_OF_THE_BRONZE: LocalSpellIdx = LocalSpellIdx::new(10);
302pub(crate) const SPELL_DEEP_BREATH: LocalSpellIdx = LocalSpellIdx::new(11);
303pub(crate) const SPELL_COUNT: usize = 12;
304const _: () = assert!(
305 SPELL_COUNT == 12,
306 "SPELL index ABI: count changed -- update positional hook consumers"
307);
308pub(crate) mod EFFECT {
309 pub(crate) const BLAST_FURNACE_DURATION: (u32, u8) = (375_510, 1);
311 pub(crate) const DEEP_BREATH_PATH: (u32, u8) = (353_759, 1);
313 pub(crate) const PYRE_DAMAGE: (u32, u8) = (357_212, 1);
315 pub(crate) const SCINTILLATION_CHANCE: (u32, u8) = (370_821, 2);
317 pub(crate) const SCINTILLATION_POWER: (u32, u8) = (370_821, 1);
319 pub(crate) const ETERNITY_SURGE_DAMAGE: (u32, u8) = (359_077, 2);
321 pub(crate) const SHATTERING_STAR: (u32, u8) = (1_265_804, 1);
323 pub(crate) const CAUSALITY_DISINTEGRATE_CDR: (u32, u8) = (375_777, 1);
325 pub(crate) const ANIMOSITY_EXTEND: (u32, u8) = (375_797, 1);
327 pub(crate) const AZURE_EB_CHANCE: (u32, u8) = (375_721, 1);
329 pub(crate) const RUBY_EB_CHANCE: (u32, u8) = (376_872, 1);
331 pub(crate) const BURNOUT_CHANCE: (u32, u8) = (375_801, 1);
333 pub(crate) const IRIDESCENCE_BLUE_MULT: (u32, u8) = (386_399, 1);
335 pub(crate) const IRIDESCENCE_RED_MULT: (u32, u8) = (386_353, 1);
337 pub(crate) const TITANIC_WRATH_MULT: (u32, u8) = (386_272, 1);
339}
340static REPORTED_SPELLS: &[(&str, u32)] = &[
341 ("eternity_surge_damage", 359_077),
342 ("fire_breath_damage", 357_209),
343 ("living_flame_damage", 361_500),
344 ("pyre_damage", 357_212),
345];
346static DECLARED_SPELL_IDS: &[u32] = &[
347 361_469, 362_969, 356_995, 357_208, 359_073, 357_211, 375_087, 370_553, 370_821,
348 1_265_804, 381_748, 357_210, 375_087, 359_618, 375_802, 370_454, 386_399, 386_353,
349 370_901, 375_583, 370_553, 376_850, 411_055, 357_209, 444_088, 1_265_871, 371_807,
350 381_748, 381_748, 1_271_783, 353_759, 441_172, 1_266_165, 434_473, 436_336, 353_759,
351 356_995, 357_209, 357_212, 359_077, 361_500, 362_980, 370_821, 375_510, 375_721,
352 375_777, 375_797, 375_801, 376_872, 386_272, 386_353, 386_399, 434_481, 443_788,
353 1_265_804, 1_271_783, 359_077, 357_209, 361_500, 357_212, 444_017, 1_265_980,
354 375_802, 444_088, 1_265_993, 1_236_776, 431_583, 431_698, 431_654, 431_698, 431_991,
355 434_481, 436_336, 441_172, 434_473, 436_336, 441_172, 1_266_165, 441_248,
356];
357static DECLARED_AURA_IDS: &[u32] = &[
358 375_087, 359_618, 375_802, 370_454, 386_399, 386_353, 370_901, 375_583, 370_553,
359 376_850, 411_055, 357_209, 444_088, 1_265_871, 371_807, 381_748, 381_748, 1_271_783,
360 353_759, 441_172, 1_266_165, 434_473, 436_336, 375_802, 444_088, 1_265_993,
361 1_236_776, 431_654, 431_698, 431_991, 434_473, 436_336, 441_172, 1_266_165, 441_248,
362];
363static TALENTS: &[(&str, u32)] = &[
364 ("ANIMOSITY", TALENT::ANIMOSITY),
365 ("AZURE_CELERITY", TALENT::AZURE_CELERITY),
366 ("AZURE_ESSENCE_BURST", TALENT::AZURE_ESSENCE_BURST),
367 ("AZURE_SWEEP", TALENT::AZURE_SWEEP),
368 ("BLAST_FURNACE", TALENT::BLAST_FURNACE),
369 ("BOMBARDMENTS_GATE", TALENT::BOMBARDMENTS_GATE),
370 ("BURNOUT", TALENT::BURNOUT),
371 ("CATALYZE", TALENT::CATALYZE),
372 ("CAUSALITY", TALENT::CAUSALITY),
373 ("CHARGED_BLAST", TALENT::CHARGED_BLAST),
374 ("DRAGONRAGE", TALENT::DRAGONRAGE),
375 ("ESSENCE_ATTUNEMENT", TALENT::ESSENCE_ATTUNEMENT),
376 ("ETERNITY_SPAN", TALENT::ETERNITY_SPAN),
377 ("ETERNITY_SURGE", TALENT::ETERNITY_SURGE),
378 ("EYE_OF_INFINITY", TALENT::EYE_OF_INFINITY),
379 ("FEED_THE_FLAMES", TALENT::FEED_THE_FLAMES),
380 ("FONT_OF_MAGIC", TALENT::FONT_OF_MAGIC),
381 ("IMMINENT_DESTRUCTION", TALENT::IMMINENT_DESTRUCTION),
382 ("IRIDESCENCE", TALENT::IRIDESCENCE),
383 ("LEAPING_FLAMES", TALENT::LEAPING_FLAMES),
384 ("MANEUVERABILITY_GATE", TALENT::MANEUVERABILITY_GATE),
385 ("MASS_DISINTEGRATE_GATE", TALENT::MASS_DISINTEGRATE_GATE),
386 ("MELT_ARMOR_GATE", TALENT::MELT_ARMOR_GATE),
387 ("POWER_NEXUS", TALENT::POWER_NEXUS),
388 ("POWER_SWELL", TALENT::POWER_SWELL),
389 ("PYRE", TALENT::PYRE),
390 ("RISING_FURY", TALENT::RISING_FURY),
391 ("RUBY_ESSENCE_BURST", TALENT::RUBY_ESSENCE_BURST),
392 ("SCINTILLATION", TALENT::SCINTILLATION),
393 ("SCORCHING_EMBERS", TALENT::SCORCHING_EMBERS),
394 ("SHATTERING_STARS", TALENT::SHATTERING_STARS),
395 ("STRAFING_RUN_GATE", TALENT::STRAFING_RUN_GATE),
396 ("TIP_THE_SCALES", TALENT::TIP_THE_SCALES),
397 ("TITANIC_WRATH", TALENT::TITANIC_WRATH),
398 ("TYRANNY", TALENT::TYRANNY),
399 ("VOLATILITY", TALENT::VOLATILITY),
400];
401pub(crate) mod DEVASTATION_EVOKER {
402 pub(crate) const LIVING_FLAME_CASTS: u32 = 0;
403 pub(crate) const AZURE_STRIKE_CASTS: u32 = 1;
404 pub(crate) const DISINTEGRATE_CASTS: u32 = 2;
405 pub(crate) const FIRE_BREATH_CASTS: u32 = 3;
406 pub(crate) const ETERNITY_SURGE_CASTS: u32 = 4;
407 pub(crate) const PYRE_CASTS: u32 = 5;
408 pub(crate) const DRAGONRAGE_CASTS: u32 = 6;
409 pub(crate) const DRAGONRAGE_UPTIME_MS: u32 = 7;
410}
411fn aura_dragonrage(
412 a: AuraDefinitionDraft,
413 data: &ResolvedGameData,
414) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
415 Ok(
416 a
417 .on_player()
418 .apply_base_from_data(data, 375_087)?
419 .max_stacks(
420 data
421 .require_aura_max_stacks(
422 wowlab_types::sim::SpellIdx::from_raw(375_087),
423 )?,
424 )
425 .damage_multiplier(1.2)?
426 .on_expire(crate::hooks::devastation_evoker::dragonrage_expire_hook),
427 )
428}
429fn aura_essence_burst(
430 a: AuraDefinitionDraft,
431 data: &ResolvedGameData,
432) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
433 Ok(
434 a
435 .on_player()
436 .apply_base_from_data(data, 359_618)?
437 .max_stacks(
438 data
439 .require_aura_max_stacks(
440 wowlab_types::sim::SpellIdx::from_raw(359_618),
441 )?,
442 ),
443 )
444}
445fn aura_burnout(
446 a: AuraDefinitionDraft,
447 data: &ResolvedGameData,
448) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
449 Ok(
450 a
451 .on_player()
452 .apply_base_from_data(data, 375_802)?
453 .max_stacks(
454 data
455 .require_aura_max_stacks(
456 wowlab_types::sim::SpellIdx::from_raw(375_802),
457 )?,
458 ),
459 )
460}
461fn aura_charged_blast(
462 a: AuraDefinitionDraft,
463 data: &ResolvedGameData,
464) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
465 Ok(
466 a
467 .on_player()
468 .apply_base_from_data(data, 370_454)?
469 .max_stacks(
470 data
471 .require_aura_max_stacks(
472 wowlab_types::sim::SpellIdx::from_raw(370_454),
473 )?,
474 ),
475 )
476}
477fn aura_iridescence_blue(
478 a: AuraDefinitionDraft,
479 data: &ResolvedGameData,
480) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
481 a.on_player()
482 .apply_base_from_data(data, 386_399)?
483 .max_stacks(
484 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(386_399))?,
485 )
486 .damage_percent_spells(
487 data.base_points(wowlab_types::sim::SpellIdx::from_raw(386_399), 1),
488 &[356_995, 362_969, 370_821, 1_265_804],
489 )
490}
491fn aura_iridescence_red(
492 a: AuraDefinitionDraft,
493 data: &ResolvedGameData,
494) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
495 Ok(
496 a
497 .on_player()
498 .apply_base_from_data(data, 386_353)?
499 .max_stacks(
500 data
501 .require_aura_max_stacks(
502 wowlab_types::sim::SpellIdx::from_raw(386_353),
503 )?,
504 ),
505 )
506}
507fn aura_leaping_flames(
508 a: AuraDefinitionDraft,
509 data: &ResolvedGameData,
510) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
511 Ok(
512 a
513 .on_player()
514 .apply_base_from_data(data, 370_901)?
515 .max_stacks(
516 data
517 .require_aura_max_stacks(
518 wowlab_types::sim::SpellIdx::from_raw(370_901),
519 )?,
520 ),
521 )
522}
523fn aura_ancient_flame(
524 a: AuraDefinitionDraft,
525 data: &ResolvedGameData,
526) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
527 Ok(
528 a
529 .on_player()
530 .apply_base_from_data(data, 375_583)?
531 .max_stacks(
532 data
533 .require_aura_max_stacks(
534 wowlab_types::sim::SpellIdx::from_raw(375_583),
535 )?,
536 ),
537 )
538}
539fn aura_tip_the_scales(
540 a: AuraDefinitionDraft,
541 data: &ResolvedGameData,
542) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
543 Ok(
544 a
545 .on_player()
546 .apply_base_from_data(data, 370_553)?
547 .max_stacks(
548 data
549 .require_aura_max_stacks(
550 wowlab_types::sim::SpellIdx::from_raw(370_553),
551 )?,
552 ),
553 )
554}
555fn aura_power_swell(
556 a: AuraDefinitionDraft,
557 data: &ResolvedGameData,
558) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
559 Ok(
560 a
561 .on_player()
562 .apply_base_from_data(data, 376_850)?
563 .max_stacks(
564 data
565 .require_aura_max_stacks(
566 wowlab_types::sim::SpellIdx::from_raw(376_850),
567 )?,
568 ),
569 )
570}
571fn aura_imminent_destruction(
572 a: AuraDefinitionDraft,
573 data: &ResolvedGameData,
574) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
575 Ok(
576 a
577 .on_player()
578 .apply_base_from_data(data, 411_055)?
579 .max_stacks(
580 data
581 .require_aura_max_stacks(
582 wowlab_types::sim::SpellIdx::from_raw(411_055),
583 )?,
584 ),
585 )
586}
587fn aura_fire_breath(
588 a: AuraDefinitionDraft,
589 data: &ResolvedGameData,
590) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
591 Ok(
592 a
593 .on_target()
594 .apply_base_from_data(data, 357_209)?
595 .max_stacks(
596 data
597 .require_aura_max_stacks(
598 wowlab_types::sim::SpellIdx::from_raw(357_209),
599 )?,
600 ),
601 )
602}
603fn aura_consume_flame(
604 a: AuraDefinitionDraft,
605 data: &ResolvedGameData,
606) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
607 Ok(
608 a
609 .on_player()
610 .apply_base_from_data(data, 444_088)?
611 .max_stacks(
612 data
613 .require_aura_max_stacks(
614 wowlab_types::sim::SpellIdx::from_raw(444_088),
615 )?,
616 ),
617 )
618}
619fn aura_azure_sweep(
620 a: AuraDefinitionDraft,
621 data: &ResolvedGameData,
622) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
623 Ok(
624 a
625 .on_player()
626 .apply_base_from_data(data, 1_265_871)?
627 .max_stacks(
628 data
629 .require_aura_max_stacks(
630 wowlab_types::sim::SpellIdx::from_raw(1_265_871),
631 )?,
632 ),
633 )
634}
635fn aura_recall(
636 a: AuraDefinitionDraft,
637 data: &ResolvedGameData,
638) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
639 Ok(
640 a
641 .on_player()
642 .apply_base_from_data(data, 371_807)?
643 .max_stacks(
644 data
645 .require_aura_max_stacks(
646 wowlab_types::sim::SpellIdx::from_raw(371_807),
647 )?,
648 ),
649 )
650}
651fn aura_blessing_of_the_bronze(
652 a: AuraDefinitionDraft,
653 data: &ResolvedGameData,
654) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
655 Ok(
656 a
657 .on_player()
658 .apply_base_from_data(data, 381_748)?
659 .max_stacks(
660 data
661 .require_aura_max_stacks(
662 wowlab_types::sim::SpellIdx::from_raw(381_748),
663 )?,
664 ),
665 )
666}
667fn aura_blessing_of_the_bronze_highlight(
668 a: AuraDefinitionDraft,
669 data: &ResolvedGameData,
670) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
671 Ok(
672 a
673 .on_player()
674 .apply_base_from_data(data, 381_748)?
675 .max_stacks(
676 data
677 .require_aura_max_stacks(
678 wowlab_types::sim::SpellIdx::from_raw(381_748),
679 )?,
680 ),
681 )
682}
683fn aura_rising_fury(
684 a: AuraDefinitionDraft,
685 data: &ResolvedGameData,
686) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
687 a.on_player()
688 .apply_base_from_data(data, 1_271_783)?
689 .max_stacks(
690 data
691 .require_aura_max_stacks(
692 wowlab_types::sim::SpellIdx::from_raw(1_271_783),
693 )?,
694 )
695 .periodic_apply_aura(
696 wowlab_engine_combat::validated_milliseconds(
697 data.period(wowlab_types::sim::SpellIdx::from_raw(1_271_783), 4),
698 1_271_783,
699 "periodic_apply_aura.tick_ms",
700 )?,
701 17,
702 )
703 .apply_periodic_behavior_from_data(data, 1_271_783)
704}
705fn aura_deep_breath_trigger(
706 a: AuraDefinitionDraft,
707 data: &ResolvedGameData,
708) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
709 Ok(
710 a
711 .on_target()
712 .apply_base_from_data(data, 353_759)?
713 .max_stacks(
714 data
715 .require_aura_max_stacks(
716 wowlab_types::sim::SpellIdx::from_raw(353_759),
717 )?,
718 ),
719 )
720}
721fn aura_melt_armor_dot(
722 a: AuraDefinitionDraft,
723 data: &ResolvedGameData,
724) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
725 Ok(
726 a
727 .on_target()
728 .apply_base_from_data(data, 441_172)?
729 .max_stacks(
730 data
731 .require_aura_max_stacks(
732 wowlab_types::sim::SpellIdx::from_raw(441_172),
733 )?,
734 ),
735 )
736}
737fn aura_strafing_run(
738 a: AuraDefinitionDraft,
739 data: &ResolvedGameData,
740) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
741 Ok(
742 a
743 .on_player()
744 .apply_base_from_data(data, 1_266_165)?
745 .max_stacks(
746 data
747 .require_aura_max_stacks(
748 wowlab_types::sim::SpellIdx::from_raw(1_266_165),
749 )?,
750 ),
751 )
752}
753fn aura_bombardments(
754 a: AuraDefinitionDraft,
755 data: &ResolvedGameData,
756) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
757 a.on_target()
758 .apply_base_from_data(data, 434_473)?
759 .max_stacks(
760 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(434_473))?,
761 )
762 .periodic_damage_sp_from_spell(
763 wowlab_engine_combat::validated_milliseconds(
764 f64::from(
765 data
766 .require_proc_category_recovery_ms(
767 wowlab_types::sim::SpellIdx::from_raw(443_788),
768 )?,
769 ),
770 434_473,
771 "periodic_damage.tick_ms",
772 )?,
773 wowlab_engine_combat::DamagePayload::new(
774 434_481,
775 data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(434_481), 1),
776 wowlab_engine_combat::DamageFlags::empty(),
777 ),
778 )
779 .apply_periodic_behavior_from_data(data, 434_473)
780}
781fn aura_mass_disintegrate(
782 a: AuraDefinitionDraft,
783 data: &ResolvedGameData,
784) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
785 Ok(
786 a
787 .on_player()
788 .apply_base_from_data(data, 436_336)?
789 .max_stacks(
790 wowlab_engine_combat::validated_max_stacks(
791 3.0,
792 436_336,
793 "aura.max_stacks",
794 )?,
795 ),
796 )
797}
798fn spell_living_flame(
799 s: SpellDefinitionDraft,
800 data: &ResolvedGameData,
801) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
802 Ok(
803 s
804 .apply_base_from_data(data, 361_469)?
805 .damage_sp_from_data(
806 wowlab_engine_domain::dbc::EffectLookup::new(
807 data,
808 wowlab_types::sim::EffectRef::new(
809 wowlab_types::sim::SpellIdx::from_raw(361_500),
810 1,
811 ),
812 ),
813 )?
814 .apply_aoe_from_data(data)
815 .on_cast(crate::hooks::devastation_evoker::living_flame_hook),
816 )
817}
818fn spell_azure_strike(
819 s: SpellDefinitionDraft,
820 data: &ResolvedGameData,
821) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
822 Ok(
823 s
824 .apply_base_from_data(data, 362_969)?
825 .apply_aoe_from_data(data)
826 .on_cast(crate::hooks::devastation_evoker::azure_strike_hook),
827 )
828}
829fn spell_disintegrate(
830 s: SpellDefinitionDraft,
831 data: &ResolvedGameData,
832) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
833 Ok(
834 s
835 .apply_base_from_data(data, 356_995)?
836 .apply_aoe_from_data(data)
837 .channel(
838 wowlab_engine_combat::validated_channel_tick_count(
839 5.0,
840 356_995,
841 "channel.tick_count",
842 )?,
843 )
844 .channel_tick_damage_sp_from_data(
845 wowlab_engine_domain::dbc::EffectLookup::new(
846 data,
847 wowlab_types::sim::EffectRef::new(
848 wowlab_types::sim::SpellIdx::from_raw(356_995),
849 1,
850 ),
851 ),
852 )?
853 .on_channel_tick(crate::hooks::devastation_evoker::disintegrate_tick_hook)
854 .on_cast(crate::hooks::devastation_evoker::disintegrate_hook)
855 .cost_free_when_aura(359_618)
856 .consume_aura_on_cast(411_055),
857 )
858}
859fn spell_fire_breath(
860 s: SpellDefinitionDraft,
861 data: &ResolvedGameData,
862) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
863 Ok(
864 s
865 .apply_base_from_data(data, 357_208)?
866 .max_empower_when_aura(AURA::TIP_THE_SCALES)
867 .on_empower_release(
868 crate::hooks::devastation_evoker::fire_breath_empower_release,
869 )
870 .damage_sp_from_data(
871 wowlab_engine_domain::dbc::EffectLookup::new(
872 data,
873 wowlab_types::sim::EffectRef::new(
874 wowlab_types::sim::SpellIdx::from_raw(357_209),
875 1,
876 ),
877 ),
878 )?
879 .applies_inferred_aura(AURA_FIRE_BREATH, 357_209)
880 .apply_aoe_from_data(data)
881 .on_cast(crate::hooks::devastation_evoker::fire_breath_hook),
882 )
883}
884fn spell_eternity_surge(
885 s: SpellDefinitionDraft,
886 data: &ResolvedGameData,
887) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
888 Ok(
889 s
890 .apply_base_from_data(data, 359_073)?
891 .max_empower_when_aura(AURA::TIP_THE_SCALES)
892 .damage_sp_from_data(
893 wowlab_engine_domain::dbc::EffectLookup::new(
894 data,
895 wowlab_types::sim::EffectRef::new(
896 wowlab_types::sim::SpellIdx::from_raw(359_077),
897 2,
898 ),
899 ),
900 )?
901 .apply_aoe_from_data(data)
902 .on_cast(crate::hooks::devastation_evoker::eternity_surge_hook),
903 )
904}
905fn spell_pyre(
906 s: SpellDefinitionDraft,
907 data: &ResolvedGameData,
908) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
909 Ok(
910 s
911 .apply_base_from_data(data, 357_211)?
912 .damage_sp_from_data(
913 wowlab_engine_domain::dbc::EffectLookup::new(
914 data,
915 wowlab_types::sim::EffectRef::new(
916 wowlab_types::sim::SpellIdx::from_raw(357_212),
917 1,
918 ),
919 ),
920 )?
921 .apply_aoe_from_data(data)
922 .on_cast(crate::hooks::devastation_evoker::pyre_hook)
923 .cost_free_when_aura(359_618)
924 .consume_aura_on_cast(411_055),
925 )
926}
927fn spell_dragonrage(
928 s: SpellDefinitionDraft,
929 data: &ResolvedGameData,
930) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
931 Ok(
932 s
933 .apply_base_from_data(data, 375_087)?
934 .applies_inferred_aura(AURA_DRAGONRAGE, 375_087)
935 .apply_aoe_from_data(data)
936 .on_cast(crate::hooks::devastation_evoker::dragonrage_hook),
937 )
938}
939fn spell_tip_the_scales(
940 s: SpellDefinitionDraft,
941 data: &ResolvedGameData,
942) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
943 Ok(
944 s
945 .apply_base_from_data(data, 370_553)?
946 .applies_aura(AURA_TIP_THE_SCALES)
947 .apply_aoe_from_data(data),
948 )
949}
950fn spell_scintillation(
951 s: SpellDefinitionDraft,
952 data: &ResolvedGameData,
953) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
954 Ok(s.apply_base_from_data(data, 370_821)?.apply_aoe_from_data(data))
955}
956fn spell_shattering_star(
957 s: SpellDefinitionDraft,
958 data: &ResolvedGameData,
959) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
960 Ok(s.apply_base_from_data(data, 1_265_804)?.apply_aoe_from_data(data))
961}
962fn spell_blessing_of_the_bronze(
963 s: SpellDefinitionDraft,
964 data: &ResolvedGameData,
965) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
966 Ok(
967 s
968 .apply_base_from_data(data, 381_748)?
969 .applies_inferred_aura(AURA_BLESSING_OF_THE_BRONZE, 381_748)
970 .apply_aoe_from_data(data),
971 )
972}
973fn spell_deep_breath(
974 s: SpellDefinitionDraft,
975 data: &ResolvedGameData,
976) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
977 Ok(
978 s
979 .apply_base_from_data(data, 357_210)?
980 .apply_aoe_from_data(data)
981 .on_cast(crate::hooks::devastation_evoker::deep_breath_hook),
982 )
983}
984pub(crate) fn build_combat_system(
985 params: &wowlab_engine_ports::HandlerParams<'_>,
986) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
987 let builder = BuiltCombatSystem::builder(params.stats.clone())
988 .spec_id(SpecId::Devastation)
989 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
990 .mastery_spell(362_980)
991 .mastery_hook(crate::hooks::devastation_evoker::mastery)
992 .resource(
993 "essence",
994 params
995 .game_data
996 .power_max(19)
997 .ok_or_else(|| {
998 wowlab_engine_ports::EngineError::spec_construction(
999 "missing power-type power_max for type_id 19",
1000 )
1001 })?,
1002 0.2,
1003 )
1004 .resource_type_id(19)
1005 .resource_start(
1006 params
1007 .game_data
1008 .power_default(19)
1009 .ok_or_else(|| {
1010 wowlab_engine_ports::EngineError::spec_construction(
1011 "missing power-type power_default for type_id 19",
1012 )
1013 })?,
1014 )
1015 .aura("dragonrage", AURA::DRAGONRAGE, |a| aura_dragonrage(a, ¶ms.game_data))
1016 .aura(
1017 "essence_burst",
1018 AURA::ESSENCE_BURST,
1019 |a| aura_essence_burst(a, ¶ms.game_data),
1020 )
1021 .aura("burnout", AURA::BURNOUT, |a| aura_burnout(a, ¶ms.game_data))
1022 .aura(
1023 "charged_blast",
1024 AURA::CHARGED_BLAST,
1025 |a| aura_charged_blast(a, ¶ms.game_data),
1026 )
1027 .aura(
1028 "iridescence_blue",
1029 AURA::IRIDESCENCE_BLUE,
1030 |a| aura_iridescence_blue(a, ¶ms.game_data),
1031 )
1032 .aura(
1033 "iridescence_red",
1034 AURA::IRIDESCENCE_RED,
1035 |a| aura_iridescence_red(a, ¶ms.game_data),
1036 )
1037 .aura(
1038 "leaping_flames",
1039 AURA::LEAPING_FLAMES,
1040 |a| aura_leaping_flames(a, ¶ms.game_data),
1041 )
1042 .aura(
1043 "ancient_flame",
1044 AURA::ANCIENT_FLAME,
1045 |a| aura_ancient_flame(a, ¶ms.game_data),
1046 )
1047 .aura(
1048 "tip_the_scales",
1049 AURA::TIP_THE_SCALES,
1050 |a| aura_tip_the_scales(a, ¶ms.game_data),
1051 )
1052 .aura(
1053 "power_swell",
1054 AURA::POWER_SWELL,
1055 |a| aura_power_swell(a, ¶ms.game_data),
1056 )
1057 .aura(
1058 "imminent_destruction",
1059 AURA::IMMINENT_DESTRUCTION,
1060 |a| aura_imminent_destruction(a, ¶ms.game_data),
1061 )
1062 .aura(
1063 "fire_breath",
1064 AURA::FIRE_BREATH,
1065 |a| aura_fire_breath(a, ¶ms.game_data),
1066 )
1067 .aura(
1068 "consume_flame",
1069 AURA::CONSUME_FLAME,
1070 |a| aura_consume_flame(a, ¶ms.game_data),
1071 )
1072 .aura(
1073 "azure_sweep",
1074 AURA::AZURE_SWEEP,
1075 |a| aura_azure_sweep(a, ¶ms.game_data),
1076 )
1077 .aura("recall", AURA::RECALL, |a| aura_recall(a, ¶ms.game_data))
1078 .aura(
1079 "blessing_of_the_bronze",
1080 AURA::BLESSING_OF_THE_BRONZE,
1081 |a| aura_blessing_of_the_bronze(a, ¶ms.game_data),
1082 )
1083 .aura(
1084 "blessing_of_the_bronze_highlight",
1085 AURA::BLESSING_OF_THE_BRONZE_HIGHLIGHT,
1086 |a| aura_blessing_of_the_bronze_highlight(a, ¶ms.game_data),
1087 )
1088 .aura(
1089 "rising_fury",
1090 AURA::RISING_FURY,
1091 |a| aura_rising_fury(a, ¶ms.game_data),
1092 )
1093 .aura(
1094 "deep_breath_trigger",
1095 AURA::DEEP_BREATH_TRIGGER,
1096 |a| aura_deep_breath_trigger(a, ¶ms.game_data),
1097 )
1098 .aura(
1099 "melt_armor_dot",
1100 AURA::MELT_ARMOR_DOT,
1101 |a| aura_melt_armor_dot(a, ¶ms.game_data),
1102 )
1103 .aura(
1104 "strafing_run",
1105 AURA::STRAFING_RUN,
1106 |a| aura_strafing_run(a, ¶ms.game_data),
1107 )
1108 .aura(
1109 "bombardments",
1110 AURA::BOMBARDMENTS,
1111 |a| aura_bombardments(a, ¶ms.game_data),
1112 )
1113 .aura(
1114 "mass_disintegrate",
1115 AURA::MASS_DISINTEGRATE,
1116 |a| aura_mass_disintegrate(a, ¶ms.game_data),
1117 )
1118 .spell(
1119 "living_flame",
1120 SPELL::LIVING_FLAME,
1121 |s| spell_living_flame(s, ¶ms.game_data),
1122 )
1123 .spell(
1124 "azure_strike",
1125 SPELL::AZURE_STRIKE,
1126 |s| spell_azure_strike(s, ¶ms.game_data),
1127 )
1128 .spell(
1129 "disintegrate",
1130 SPELL::DISINTEGRATE,
1131 |s| spell_disintegrate(s, ¶ms.game_data),
1132 )
1133 .spell(
1134 "fire_breath",
1135 SPELL::FIRE_BREATH,
1136 |s| spell_fire_breath(s, ¶ms.game_data),
1137 )
1138 .spell(
1139 "eternity_surge",
1140 SPELL::ETERNITY_SURGE,
1141 |s| spell_eternity_surge(s, ¶ms.game_data),
1142 )
1143 .spell("pyre", SPELL::PYRE, |s| spell_pyre(s, ¶ms.game_data))
1144 .spell(
1145 "dragonrage",
1146 SPELL::DRAGONRAGE,
1147 |s| spell_dragonrage(s, ¶ms.game_data),
1148 )
1149 .spell(
1150 "tip_the_scales",
1151 SPELL::TIP_THE_SCALES,
1152 |s| spell_tip_the_scales(s, ¶ms.game_data),
1153 )
1154 .spell(
1155 "scintillation",
1156 SPELL::SCINTILLATION,
1157 |s| spell_scintillation(s, ¶ms.game_data),
1158 )
1159 .spell(
1160 "shattering_star",
1161 SPELL::SHATTERING_STAR,
1162 |s| spell_shattering_star(s, ¶ms.game_data),
1163 )
1164 .spell(
1165 "blessing_of_the_bronze",
1166 SPELL::BLESSING_OF_THE_BRONZE,
1167 |s| spell_blessing_of_the_bronze(s, ¶ms.game_data),
1168 )
1169 .spell(
1170 "deep_breath",
1171 SPELL::DEEP_BREATH,
1172 |s| spell_deep_breath(s, ¶ms.game_data),
1173 )
1174 .game_data(params.game_data.clone())
1175 .talent_spell_ids(TALENTS)
1176 .talent_selections(params.talent_selections)
1177 .set_bonus_auras(params.set_bonus_auras)
1178 .encounter(params.encounter.clone());
1179 let builder = crate::generated::items::register_equipped(
1180 builder,
1181 ¶ms.game_data,
1182 params.equipped_items,
1183 )?;
1184
1185 builder
1186 .build(params.rotation)
1187 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1188}
1189fn new_handler(
1190 params: wowlab_engine_ports::HandlerParams<'_>,
1191) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1192 let handler = crate::composition::compose_handler(
1193 build_combat_system,
1194 ¶ms,
1195 |parts, params| Ok(
1196 crate::hooks::devastation_evoker::DevastationHandler::new(parts, params),
1197 ),
1198 )?;
1199
1200 Ok(Box::new(handler))
1201}
1202static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1203 primary_resource: ResourceType::Essence,
1204 secondary_resource: None,
1205 spell_ids: DECLARED_SPELL_IDS,
1206 aura_ids: DECLARED_AURA_IDS,
1207 server_proc_entries: &[
1208 DeclaredServerProcEntry {
1209 spell_id: 359_618,
1210 attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
1211 | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1212 },
1213 DeclaredServerProcEntry {
1214 spell_id: 375_802,
1215 attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
1216 | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1217 },
1218 ],
1219 talents: TALENTS,
1220 rotation_field_schema: &[],
1221 metrics_plugin_id: None,
1222 hero_talent_trees: &[
1223 HeroTalentTreeDesc {
1224 name: "Flameshaper",
1225 spells: HERO_TREE_FLAMESHAPER_SPELLS,
1226 auras: HERO_TREE_FLAMESHAPER_AURAS,
1227 },
1228 HeroTalentTreeDesc {
1229 name: "Chronowarden",
1230 spells: HERO_TREE_CHRONOWARDEN_SPELLS,
1231 auras: HERO_TREE_CHRONOWARDEN_AURAS,
1232 },
1233 HeroTalentTreeDesc {
1234 name: "Scalecommander",
1235 spells: HERO_TREE_SCALECOMMANDER_SPELLS,
1236 auras: HERO_TREE_SCALECOMMANDER_AURAS,
1237 },
1238 ],
1239 reported_spells: REPORTED_SPELLS,
1240 masked_passive_effects: &[],
1241 passive_effect_overrides: &[],
1242};
1243pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1244 spec_id: SpecId::Devastation,
1245 display_name: "Devastation Evoker",
1246 metadata: DECLARED_METADATA,
1247 handler_factory: new_handler,
1248};
1249wowlab_engine_combat::smoke_test!(build_combat_system);