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 OBLITERATE: u32 = 49020;
16 pub(crate) const FROST_STRIKE: u32 = 49143;
18 pub(crate) const HOWLING_BLAST: u32 = 49184;
20 pub(crate) const PILLAR_OF_FROST: u32 = 51271;
22 pub(crate) const EMPOWER_RUNE_WEAPON: u32 = 47568;
24 pub(crate) const FROSTWYRMS_FURY: u32 = 279_302;
26 pub(crate) const GLACIAL_ADVANCE: u32 = 194_913;
28 pub(crate) const FROSTSCYTHE: u32 = 207_230;
30 pub(crate) const SOUL_REAPER: u32 = 343_294;
32 pub(crate) const RUNE_STRIKE: u32 = 316_239;
34 pub(crate) const REMORSELESS_WINTER: u32 = 196_770;
36 pub(crate) const BREATH_OF_SINDRAGOSA: u32 = 1_249_658;
38 pub(crate) const REAPERS_MARK: u32 = 439_843;
40}
41pub(crate) mod AURA {
42 pub(crate) const KILLING_MACHINE: u32 = 51124;
44 pub(crate) const RIME: u32 = 59052;
46 pub(crate) const PILLAR_OF_FROST: u32 = 51271;
48 pub(crate) const EMPOWER_RUNE_WEAPON: u32 = 1_230_959;
50 pub(crate) const ICY_TALONS: u32 = 194_879;
52 pub(crate) const CHOSEN_OF_FROSTBROOD_HASTE: u32 = 1_265_630;
54 pub(crate) const FROSTBANE: u32 = 1_229_310;
56 pub(crate) const ICY_ONSLAUGHT: u32 = 1_230_273;
58 pub(crate) const KILLING_STREAK: u32 = 1_230_916;
60 pub(crate) const DARK_TALONS_ICY_TALONS: u32 = 443_595;
62 pub(crate) const FROST_FEVER: u32 = 55095;
64 pub(crate) const BONEGRINDER_CRIT: u32 = 377_101;
66 pub(crate) const BONEGRINDER_FROST: u32 = 377_103;
68 pub(crate) const RUNE_MASTERY: u32 = 374_585;
70 pub(crate) const RAZORICE: u32 = 51714;
72 pub(crate) const BRITTLE: u32 = 374_557;
74 pub(crate) const FROSTREAPER: u32 = 1_233_351;
76 pub(crate) const EMPOWERED_STRIKES: u32 = 1_269_300;
78 pub(crate) const MID1_4PC: u32 = 1_269_322;
80 pub(crate) const FROZEN_DOMINION: u32 = 377_226;
82 pub(crate) const BREATH_OF_SINDRAGOSA: u32 = 1_249_658;
84 pub(crate) const REMORSELESS_WINTER: u32 = 1_233_152;
86 pub(crate) const FROZEN_DOMINION_MASTERY: u32 = 377_253;
88 pub(crate) const EXTERMINATE: u32 = 441_416;
90}
91pub(crate) mod TALENT {
92 pub(crate) const BREATH_OF_SINDRAGOSA: u32 = 1_249_658;
94 pub(crate) const BRITTLE: u32 = 374_504;
96 pub(crate) const CHOSEN_OF_FROSTBROOD: u32 = 1_265_632;
98 pub(crate) const EMPOWER_RUNE_WEAPON: u32 = 47568;
100 pub(crate) const FROSTREAPER: u32 = 1_230_301;
102 pub(crate) const FROSTSCYTHE: u32 = 207_230;
104 pub(crate) const FROSTWYRMS_FURY: u32 = 279_302;
106 pub(crate) const FROST_STRIKE: u32 = 49143;
108 pub(crate) const FROZEN_DOMINION: u32 = 377_226;
110 pub(crate) const GLACIAL_ADVANCE: u32 = 194_913;
112 pub(crate) const HOWLING_BLAST: u32 = 49184;
114 pub(crate) const KILLING_MACHINE: u32 = 51128;
116 pub(crate) const OBLITERATE: u32 = 49020;
118 pub(crate) const OBLITERATION: u32 = 281_238;
120 pub(crate) const PILLAR_OF_FROST: u32 = 51271;
122 pub(crate) const REAPERS_MARK: u32 = 439_843;
124 pub(crate) const SOUL_REAPER: u32 = 343_294;
126}
127pub(crate) mod SET_BONUS {
128 pub(crate) const MID1_FROST_2PC: u32 = 1_264_801;
130 pub(crate) const MID1_FROST_4PC: u32 = 1_264_802;
132}
133pub(crate) mod REPORTED_SPELL {
134 pub(crate) const BREATH_OF_SINDRAGOSA_DAMAGE: u32 = 155_166;
136 pub(crate) const CHOSEN_OF_FROSTBROOD_RECALL: u32 = 1_265_384;
138 pub(crate) const HYPERPYREXIA: u32 = 458_169;
140}
141pub(crate) mod HERO {
142 pub(crate) mod DEATHBRINGER {
143 pub(crate) mod SPELL {
144 pub(crate) const EXTERMINATE: u32 = 441_424;
146 pub(crate) const EXTERMINATE_AOE: u32 = 441_426;
148 pub(crate) const REAPERS_MARK: u32 = 439_843;
150 pub(crate) const REAPERS_MARK_EXPLOSION: u32 = 436_304;
152 pub(crate) const WAVE_OF_SOULS: u32 = 435_802;
154 }
155 pub(crate) mod AURA {
156 pub(crate) const BIND_IN_DARKNESS: u32 = 443_532;
158 pub(crate) const EXTERMINATE_BUFF: u32 = 441_416;
160 pub(crate) const REAPERS_MARK_DEBUFF: u32 = 434_765;
162 }
163 }
164 pub(crate) mod FROST {
165 pub(crate) mod SPELL {
166 pub(crate) const CHOSEN_OF_FROSTBROOD: u32 = 1_265_384;
168 pub(crate) const FROSTREAPER: u32 = 1_233_619;
170 pub(crate) const GLACIAL_ADVANCE_ARCTIC_ASSAULT_OBLITERATE: u32 = 195_975;
172 pub(crate) const HOWLING_BLADES_FIRST: u32 = 1_231_083;
174 pub(crate) const HOWLING_BLADES_SECOND: u32 = 1_231_082;
176 pub(crate) const HYPERPYREXIA: u32 = 458_169;
178 pub(crate) const ICY_DEATH_TORRENT: u32 = 439_539;
180 pub(crate) const OBLITERATE_FROST: u32 = 1_264_084;
182 }
183 }
184}
185static HERO_TREE_DEATHBRINGER_SPELLS: &[(&str, u32)] = &[
186 ("EXTERMINATE", 441_424),
187 ("EXTERMINATE_AOE", 441_426),
188 ("REAPERS_MARK", 439_843),
189 ("REAPERS_MARK_EXPLOSION", 436_304),
190 ("WAVE_OF_SOULS", 435_802),
191];
192static HERO_TREE_DEATHBRINGER_AURAS: &[(&str, u32)] = &[
193 ("BIND_IN_DARKNESS", 443_532),
194 ("EXTERMINATE_BUFF", 441_416),
195 ("REAPERS_MARK_DEBUFF", 434_765),
196];
197static HERO_TREE_FROST_SPELLS: &[(&str, u32)] = &[
198 ("CHOSEN_OF_FROSTBROOD", 1_265_384),
199 ("FROSTREAPER", 1_233_619),
200 ("GLACIAL_ADVANCE_ARCTIC_ASSAULT_OBLITERATE", 195_975),
201 ("HOWLING_BLADES_FIRST", 1_231_083),
202 ("HOWLING_BLADES_SECOND", 1_231_082),
203 ("HYPERPYREXIA", 458_169),
204 ("ICY_DEATH_TORRENT", 439_539),
205 ("OBLITERATE_FROST", 1_264_084),
206];
207static HERO_TREE_FROST_AURAS: &[(&str, u32)] = &[];
208pub(crate) const AURA_KILLING_MACHINE: LocalAuraIdx = LocalAuraIdx::new(0);
209pub(crate) const AURA_RIME: LocalAuraIdx = LocalAuraIdx::new(1);
210pub(crate) const AURA_PILLAR_OF_FROST: LocalAuraIdx = LocalAuraIdx::new(2);
211pub(crate) const AURA_EMPOWER_RUNE_WEAPON: LocalAuraIdx = LocalAuraIdx::new(3);
212pub(crate) const AURA_ICY_TALONS: LocalAuraIdx = LocalAuraIdx::new(4);
213pub(crate) const AURA_CHOSEN_OF_FROSTBROOD_HASTE: LocalAuraIdx = LocalAuraIdx::new(5);
214pub(crate) const AURA_FROSTBANE: LocalAuraIdx = LocalAuraIdx::new(6);
215pub(crate) const AURA_ICY_ONSLAUGHT: LocalAuraIdx = LocalAuraIdx::new(7);
216pub(crate) const AURA_KILLING_STREAK: LocalAuraIdx = LocalAuraIdx::new(8);
217pub(crate) const AURA_DARK_TALONS_ICY_TALONS: LocalAuraIdx = LocalAuraIdx::new(9);
218pub(crate) const AURA_FROST_FEVER: LocalAuraIdx = LocalAuraIdx::new(10);
219pub(crate) const AURA_BONEGRINDER_CRIT: LocalAuraIdx = LocalAuraIdx::new(11);
220pub(crate) const AURA_BONEGRINDER_FROST: LocalAuraIdx = LocalAuraIdx::new(12);
221pub(crate) const AURA_RUNE_MASTERY: LocalAuraIdx = LocalAuraIdx::new(13);
222pub(crate) const AURA_RAZORICE: LocalAuraIdx = LocalAuraIdx::new(14);
223pub(crate) const AURA_BRITTLE: LocalAuraIdx = LocalAuraIdx::new(15);
224pub(crate) const AURA_FROSTREAPER: LocalAuraIdx = LocalAuraIdx::new(16);
225pub(crate) const AURA_EMPOWERED_STRIKES: LocalAuraIdx = LocalAuraIdx::new(17);
226pub(crate) const AURA_MID1_4PC: LocalAuraIdx = LocalAuraIdx::new(18);
227pub(crate) const AURA_FROZEN_DOMINION: LocalAuraIdx = LocalAuraIdx::new(19);
228pub(crate) const AURA_BREATH_OF_SINDRAGOSA: LocalAuraIdx = LocalAuraIdx::new(20);
229pub(crate) const AURA_REMORSELESS_WINTER: LocalAuraIdx = LocalAuraIdx::new(21);
230pub(crate) const AURA_FROZEN_DOMINION_MASTERY: LocalAuraIdx = LocalAuraIdx::new(22);
231pub(crate) const AURA_EXTERMINATE: LocalAuraIdx = LocalAuraIdx::new(23);
232pub(crate) const AURA_COUNT: usize = 24;
233const _: () = assert!(
234 AURA_COUNT == 24, "AURA index ABI: count changed -- update positional hook consumers"
235);
236pub(crate) const SPELL_OBLITERATE: LocalSpellIdx = LocalSpellIdx::new(0);
237pub(crate) const SPELL_FROST_STRIKE: LocalSpellIdx = LocalSpellIdx::new(1);
238pub(crate) const SPELL_HOWLING_BLAST: LocalSpellIdx = LocalSpellIdx::new(2);
239pub(crate) const SPELL_PILLAR_OF_FROST: LocalSpellIdx = LocalSpellIdx::new(3);
240pub(crate) const SPELL_EMPOWER_RUNE_WEAPON: LocalSpellIdx = LocalSpellIdx::new(4);
241pub(crate) const SPELL_FROSTWYRMS_FURY: LocalSpellIdx = LocalSpellIdx::new(5);
242pub(crate) const SPELL_GLACIAL_ADVANCE: LocalSpellIdx = LocalSpellIdx::new(6);
243pub(crate) const SPELL_FROSTSCYTHE: LocalSpellIdx = LocalSpellIdx::new(7);
244pub(crate) const SPELL_SOUL_REAPER: LocalSpellIdx = LocalSpellIdx::new(8);
245pub(crate) const SPELL_RUNE_STRIKE: LocalSpellIdx = LocalSpellIdx::new(9);
246pub(crate) const SPELL_REMORSELESS_WINTER: LocalSpellIdx = LocalSpellIdx::new(10);
247pub(crate) const SPELL_BREATH_OF_SINDRAGOSA: LocalSpellIdx = LocalSpellIdx::new(11);
248pub(crate) const SPELL_REAPERS_MARK: LocalSpellIdx = LocalSpellIdx::new(12);
249pub(crate) const SPELL_COUNT: usize = 13;
250const _: () = assert!(
251 SPELL_COUNT == 13,
252 "SPELL index ABI: count changed -- update positional hook consumers"
253);
254pub(crate) mod EFFECT {
255 pub(crate) const ARCTIC_ASSAULT_PCT: (u32, u8) = (456_230, 1);
257 pub(crate) const BIND_IN_DARKNESS_HB_PCT: (u32, u8) = (440_031, 4);
259 pub(crate) const BOS_DAMAGE: (u32, u8) = (155_166, 2);
261 pub(crate) const BOS_RUNE_REFUND: (u32, u8) = (1_234_304, 1);
263 pub(crate) const COF_FWF_PCT: (u32, u8) = (1_265_637, 1);
265 pub(crate) const COF_SPELLS_PCT: (u32, u8) = (1_265_637, 3);
267 pub(crate) const DARK_TALONS_CHANCE: (u32, u8) = (436_687, 1);
269 pub(crate) const DEATHLY_BLOWS_FS_PCT: (u32, u8) = (1_265_932, 1);
271 pub(crate) const ECHOING_FURY_STACKS: (u32, u8) = (1_265_855, 1);
273 pub(crate) const ERW_RP: (u32, u8) = (1_230_959, 1);
275 pub(crate) const EXTERMINATE_AOE: (u32, u8) = (441_426, 2);
277 pub(crate) const EXTERMINATE_HIT: (u32, u8) = (441_424, 2);
279 pub(crate) const EXTERMINATE_STACKS: (u32, u8) = (441_378, 3);
281 pub(crate) const FRIGID_EXECUTIONER_PCT: (u32, u8) = (377_073, 2);
283 pub(crate) const FROSTREAPER_DAMAGE: (u32, u8) = (1_233_619, 1);
285 pub(crate) const FROSTWYRMS_FURY_DAMAGE: (u32, u8) = (279_303, 1);
287 pub(crate) const FROST_DK_SPEC_PCT: (u32, u8) = (137_006, 1);
289 pub(crate) const FROST_STRIKE_2H: (u32, u8) = (325_464, 1);
291 pub(crate) const GLACIAL_ADVANCE_DAMAGE: (u32, u8) = (195_975, 1);
293 pub(crate) const GRIM_REAPER_MAX_PCT: (u32, u8) = (434_905, 1);
295 pub(crate) const HOWLING_BLADES_FIRST: (u32, u8) = (1_231_083, 1);
297 pub(crate) const HOWLING_BLADES_KM_PCT: (u32, u8) = (1_230_223, 1);
299 pub(crate) const HOWLING_BLADES_SECOND: (u32, u8) = (1_231_082, 1);
301 pub(crate) const HOWLING_BLAST_DAMAGE: (u32, u8) = (49184, 1);
303 pub(crate) const HYPERPYREXIA_PORTION_PCT: (u32, u8) = (456_238, 1);
305 pub(crate) const ICEBREAKER_PCT: (u32, u8) = (392_950, 1);
307 pub(crate) const ICY_DEATH_TORRENT_DAMAGE: (u32, u8) = (439_539, 1);
309 pub(crate) const MOTFW_ALL_PCT: (u32, u8) = (81333, 2);
311 pub(crate) const MURDEROUS_EFFICIENCY_PCT: (u32, u8) = (207_061, 1);
313 pub(crate) const NORTHWINDS_RIME_PCT: (u32, u8) = (1_230_284, 1);
315 pub(crate) const OBLITERATE_FROST: (u32, u8) = (1_264_084, 1);
317 pub(crate) const OBLITERATE_PHYS: (u32, u8) = (325_461, 1);
319 pub(crate) const OBLITERATION_RUNE_PCT: (u32, u8) = (281_238, 2);
321 pub(crate) const RAGE_OF_FROZEN_CHAMPION_RP: (u32, u8) = (377_077, 1);
323 pub(crate) const REAPERS_MARK_EXPLOSION: (u32, u8) = (436_304, 2);
325 pub(crate) const REAPERS_MARK_STACKS: (u32, u8) = (434_765, 1);
327 pub(crate) const RIME_HB_BONUS_PCT: (u32, u8) = (59052, 2);
329 pub(crate) const RIME_PROC_PCT: (u32, u8) = (59057, 2);
331 pub(crate) const RUNIC_EMPOWERMENT_PCT: (u32, u8) = (81229, 1);
333 pub(crate) const RUNIC_OVERFLOW_FS_PCT: (u32, u8) = (316_803, 1);
335 pub(crate) const WAVE_OF_SOULS_DAMAGE: (u32, u8) = (435_802, 2);
337}
338static REPORTED_SPELLS: &[(&str, u32)] = &[
339 ("breath_of_sindragosa_damage", 155_166),
340 ("chosen_of_frostbrood_recall", 1_265_384),
341 ("hyperpyrexia", 458_169),
342];
343static DECLARED_SPELL_IDS: &[u32] = &[
344 49020, 49143, 49184, 51271, 47568, 279_302, 194_913, 207_230, 343_294, 316_239,
345 196_770, 1_249_658, 439_843, 51124, 59052, 51271, 1_230_959, 194_879, 1_265_630,
346 1_229_310, 1_230_273, 1_230_916, 443_595, 55095, 377_101, 377_103, 374_585, 51714,
347 374_557, 1_233_351, 1_269_300, 1_269_322, 377_226, 1_249_658, 1_233_152, 377_253,
348 441_416, 6603, 49184, 51271, 55095, 59052, 59057, 77514, 81229, 81333, 137_006,
349 155_166, 194_878, 194_879, 195_975, 196_771, 207_061, 279_303, 281_238, 316_803,
350 325_461, 325_464, 374_574, 377_073, 377_077, 392_950, 434_765, 434_905, 435_802,
351 436_304, 436_687, 439_539, 440_031, 441_378, 441_424, 441_426, 456_230, 456_238,
352 458_169, 1_230_223, 1_230_284, 1_230_916, 1_230_959, 1_231_082, 1_231_083, 1_233_619,
353 1_234_304, 1_249_658, 1_264_084, 1_265_384, 1_265_637, 1_265_855, 1_265_932, 155_166,
354 1_265_384, 458_169, 441_424, 441_426, 439_843, 436_304, 435_802, 443_532, 441_416,
355 434_765, 1_265_384, 1_233_619, 195_975, 1_231_083, 1_231_082, 458_169, 439_539,
356 1_264_084,
357];
358static DECLARED_AURA_IDS: &[u32] = &[
359 51124, 59052, 51271, 1_230_959, 194_879, 1_265_630, 1_229_310, 1_230_273, 1_230_916,
360 443_595, 55095, 377_101, 377_103, 374_585, 51714, 374_557, 1_233_351, 1_269_300,
361 1_269_322, 377_226, 1_249_658, 1_233_152, 377_253, 441_416, 443_532, 441_416, 434_765,
362];
363static TALENTS: &[(&str, u32)] = &[
364 ("BREATH_OF_SINDRAGOSA", TALENT::BREATH_OF_SINDRAGOSA),
365 ("BRITTLE", TALENT::BRITTLE),
366 ("CHOSEN_OF_FROSTBROOD", TALENT::CHOSEN_OF_FROSTBROOD),
367 ("EMPOWER_RUNE_WEAPON", TALENT::EMPOWER_RUNE_WEAPON),
368 ("FROSTREAPER", TALENT::FROSTREAPER),
369 ("FROSTSCYTHE", TALENT::FROSTSCYTHE),
370 ("FROSTWYRMS_FURY", TALENT::FROSTWYRMS_FURY),
371 ("FROST_STRIKE", TALENT::FROST_STRIKE),
372 ("FROZEN_DOMINION", TALENT::FROZEN_DOMINION),
373 ("GLACIAL_ADVANCE", TALENT::GLACIAL_ADVANCE),
374 ("HOWLING_BLAST", TALENT::HOWLING_BLAST),
375 ("KILLING_MACHINE", TALENT::KILLING_MACHINE),
376 ("OBLITERATE", TALENT::OBLITERATE),
377 ("OBLITERATION", TALENT::OBLITERATION),
378 ("PILLAR_OF_FROST", TALENT::PILLAR_OF_FROST),
379 ("REAPERS_MARK", TALENT::REAPERS_MARK),
380 ("SOUL_REAPER", TALENT::SOUL_REAPER),
381];
382pub(crate) mod FROST_DK {
383 pub(crate) const OBLITERATE_CASTS: u32 = 0;
384 pub(crate) const FROST_STRIKE_CASTS: u32 = 1;
385 pub(crate) const HOWLING_BLAST_CASTS: u32 = 2;
386 pub(crate) const PILLAR_OF_FROST_CASTS: u32 = 3;
387 pub(crate) const BREATH_OF_SINDRAGOSA_CASTS: u32 = 4;
388 pub(crate) const REMORSELESS_WINTER_CASTS: u32 = 5;
389 pub(crate) const FROSTWYRMS_FURY_CASTS: u32 = 6;
390 pub(crate) const KILLING_MACHINE_UPTIME_MS: u32 = 7;
391 pub(crate) const PILLAR_OF_FROST_UPTIME_MS: u32 = 8;
392}
393fn aura_killing_machine(
394 a: AuraDefinitionDraft,
395 data: &ResolvedGameData,
396) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
397 Ok(
398 a
399 .on_player()
400 .apply_base_from_data(data, 51124)?
401 .max_stacks(
402 data
403 .require_aura_max_stacks(
404 wowlab_types::sim::SpellIdx::from_raw(51124),
405 )?,
406 )
407 .on_consume_extend(
408 LocalAuraIdx::new(20),
409 wowlab_engine_combat::validated_milliseconds(
410 data
411 .base_points(
412 wowlab_types::sim::SpellIdx::from_raw(1_249_658),
413 3,
414 ),
415 51124,
416 "aura.on_consume.extend_aura.amount_ms",
417 )?,
418 ),
419 )
420}
421fn aura_rime(
422 a: AuraDefinitionDraft,
423 data: &ResolvedGameData,
424) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
425 Ok(
426 a
427 .on_player()
428 .apply_base_from_data(data, 59052)?
429 .max_stacks(
430 data
431 .require_aura_max_stacks(
432 wowlab_types::sim::SpellIdx::from_raw(59052),
433 )?,
434 )
435 .on_consume_extend(
436 LocalAuraIdx::new(20),
437 wowlab_engine_combat::validated_milliseconds(
438 data
439 .base_points(
440 wowlab_types::sim::SpellIdx::from_raw(1_249_658),
441 3,
442 ),
443 59052,
444 "aura.on_consume.extend_aura.amount_ms",
445 )?,
446 ),
447 )
448}
449fn aura_pillar_of_frost(
450 a: AuraDefinitionDraft,
451 data: &ResolvedGameData,
452) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
453 a.on_player()
454 .apply_base_from_data(data, 51271)?
455 .max_stacks(
456 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(51271))?,
457 )
458 .primary_pct_per_stack(
459 data.base_points(wowlab_types::sim::SpellIdx::from_raw(51271), 1),
460 )
461}
462fn aura_empower_rune_weapon(
463 a: AuraDefinitionDraft,
464 data: &ResolvedGameData,
465) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
466 Ok(
467 a
468 .on_player()
469 .apply_base_from_data(data, 1_230_959)?
470 .max_stacks(
471 data
472 .require_aura_max_stacks(
473 wowlab_types::sim::SpellIdx::from_raw(1_230_959),
474 )?,
475 ),
476 )
477}
478fn aura_icy_talons(
479 a: AuraDefinitionDraft,
480 data: &ResolvedGameData,
481) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
482 Ok(
483 a
484 .on_player()
485 .apply_base_from_data(data, 194_879)?
486 .max_stacks(
487 data
488 .require_aura_max_stacks(
489 wowlab_types::sim::SpellIdx::from_raw(194_879),
490 )?,
491 ),
492 )
493}
494fn aura_chosen_of_frostbrood_haste(
495 a: AuraDefinitionDraft,
496 data: &ResolvedGameData,
497) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
498 Ok(
499 a
500 .on_player()
501 .apply_base_from_data(data, 1_265_630)?
502 .max_stacks(
503 data
504 .require_aura_max_stacks(
505 wowlab_types::sim::SpellIdx::from_raw(1_265_630),
506 )?,
507 ),
508 )
509}
510fn aura_frostbane(
511 a: AuraDefinitionDraft,
512 data: &ResolvedGameData,
513) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
514 Ok(
515 a
516 .on_player()
517 .apply_base_from_data(data, 1_229_310)?
518 .max_stacks(
519 data
520 .require_aura_max_stacks(
521 wowlab_types::sim::SpellIdx::from_raw(1_229_310),
522 )?,
523 ),
524 )
525}
526fn aura_icy_onslaught(
527 a: AuraDefinitionDraft,
528 data: &ResolvedGameData,
529) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
530 Ok(
531 a
532 .on_player()
533 .apply_base_from_data(data, 1_230_273)?
534 .max_stacks(
535 data
536 .require_aura_max_stacks(
537 wowlab_types::sim::SpellIdx::from_raw(1_230_273),
538 )?,
539 ),
540 )
541}
542fn aura_killing_streak(
543 a: AuraDefinitionDraft,
544 data: &ResolvedGameData,
545) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
546 Ok(
547 a
548 .on_player()
549 .apply_base_from_data(data, 1_230_916)?
550 .max_stacks(
551 data
552 .require_aura_max_stacks(
553 wowlab_types::sim::SpellIdx::from_raw(1_230_916),
554 )?,
555 )
556 .haste_per_stack(
557 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(1_230_916), 1))
558 * 0.1,
559 )?
560 .async_stacks(),
561 )
562}
563fn aura_dark_talons_icy_talons(
564 a: AuraDefinitionDraft,
565 data: &ResolvedGameData,
566) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
567 a.on_player()
568 .apply_base_from_data(data, 443_595)?
569 .max_stacks(
570 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(443_595))?,
571 )
572 .attack_speed_per_stack(
573 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(194_878), 1)) * 3.0,
574 )?
575 .auto_attack_damage_per_stack(
576 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(194_879), 2)) * 3.0,
577 )
578}
579fn aura_frost_fever(
580 a: AuraDefinitionDraft,
581 data: &ResolvedGameData,
582) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
583 Ok(
584 a
585 .on_target()
586 .apply_base_from_data(data, 55095)?
587 .max_stacks(
588 data
589 .require_aura_max_stacks(
590 wowlab_types::sim::SpellIdx::from_raw(55095),
591 )?,
592 )
593 .periodic_hook(
594 wowlab_engine_combat::validated_milliseconds(
595 data.period(wowlab_types::sim::SpellIdx::from_raw(55095), 1),
596 55095,
597 "periodic_hook.tick_ms",
598 )?,
599 )
600 .apply_periodic_behavior_from_data(data, 55095)?
601 .tick_hook(crate::hooks::frost_death_knight::frost_fever_tick_hook),
602 )
603}
604fn aura_bonegrinder_crit(
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, 377_101)?
612 .max_stacks(
613 wowlab_engine_combat::validated_max_stacks(
614 5.0,
615 377_101,
616 "aura.max_stacks",
617 )?,
618 ),
619 )
620}
621fn aura_bonegrinder_frost(
622 a: AuraDefinitionDraft,
623 data: &ResolvedGameData,
624) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
625 Ok(
626 a
627 .on_player()
628 .apply_base_from_data(data, 377_103)?
629 .max_stacks(
630 data
631 .require_aura_max_stacks(
632 wowlab_types::sim::SpellIdx::from_raw(377_103),
633 )?,
634 ),
635 )
636}
637fn aura_rune_mastery(
638 a: AuraDefinitionDraft,
639 data: &ResolvedGameData,
640) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
641 a.on_player()
642 .apply_base_from_data(data, 374_585)?
643 .max_stacks(
644 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(374_585))?,
645 )
646 .primary_pct_per_stack(
647 data.base_points(wowlab_types::sim::SpellIdx::from_raw(374_574), 1),
648 )
649}
650fn aura_razorice(
651 a: AuraDefinitionDraft,
652 data: &ResolvedGameData,
653) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
654 Ok(
655 a
656 .on_target()
657 .apply_base_from_data(data, 51714)?
658 .max_stacks(
659 data
660 .require_aura_max_stacks(
661 wowlab_types::sim::SpellIdx::from_raw(51714),
662 )?,
663 ),
664 )
665}
666fn aura_brittle(
667 a: AuraDefinitionDraft,
668 data: &ResolvedGameData,
669) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
670 Ok(
671 a
672 .on_target()
673 .apply_base_from_data(data, 374_557)?
674 .max_stacks(
675 data
676 .require_aura_max_stacks(
677 wowlab_types::sim::SpellIdx::from_raw(374_557),
678 )?,
679 ),
680 )
681}
682fn aura_frostreaper(
683 a: AuraDefinitionDraft,
684 data: &ResolvedGameData,
685) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
686 Ok(
687 a
688 .on_target()
689 .apply_base_from_data(data, 1_233_351)?
690 .max_stacks(
691 data
692 .require_aura_max_stacks(
693 wowlab_types::sim::SpellIdx::from_raw(1_233_351),
694 )?,
695 ),
696 )
697}
698fn aura_empowered_strikes(
699 a: AuraDefinitionDraft,
700 data: &ResolvedGameData,
701) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
702 Ok(
703 a
704 .on_player()
705 .apply_base_from_data(data, 1_269_300)?
706 .max_stacks(
707 data
708 .require_aura_max_stacks(
709 wowlab_types::sim::SpellIdx::from_raw(1_269_300),
710 )?,
711 ),
712 )
713}
714fn aura_mid1_4pc(
715 a: AuraDefinitionDraft,
716 data: &ResolvedGameData,
717) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
718 Ok(
719 a
720 .on_player()
721 .apply_base_from_data(data, 1_269_322)?
722 .max_stacks(
723 data
724 .require_aura_max_stacks(
725 wowlab_types::sim::SpellIdx::from_raw(1_269_322),
726 )?,
727 ),
728 )
729}
730fn aura_frozen_dominion(
731 a: AuraDefinitionDraft,
732 data: &ResolvedGameData,
733) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
734 Ok(
735 a
736 .on_player()
737 .apply_base_from_data(data, 377_226)?
738 .max_stacks(
739 data
740 .require_aura_max_stacks(
741 wowlab_types::sim::SpellIdx::from_raw(377_226),
742 )?,
743 ),
744 )
745}
746fn aura_breath_of_sindragosa(
747 a: AuraDefinitionDraft,
748 data: &ResolvedGameData,
749) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
750 Ok(
751 a
752 .on_player()
753 .apply_base_from_data(data, 1_249_658)?
754 .max_stacks(
755 data
756 .require_aura_max_stacks(
757 wowlab_types::sim::SpellIdx::from_raw(1_249_658),
758 )?,
759 )
760 .periodic_hook(
761 wowlab_engine_combat::validated_milliseconds(
762 data.period(wowlab_types::sim::SpellIdx::from_raw(1_249_658), 1),
763 1_249_658,
764 "periodic_hook.tick_ms",
765 )?,
766 )
767 .apply_periodic_behavior_from_data(data, 1_249_658)?
768 .on_expire(
769 crate::hooks::frost_death_knight::breath_of_sindragosa_expire_hook,
770 )
771 .tick_hook(crate::hooks::frost_death_knight::breath_of_sindragosa_tick_hook),
772 )
773}
774fn aura_remorseless_winter(
775 a: AuraDefinitionDraft,
776 data: &ResolvedGameData,
777) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
778 a.on_player()
779 .apply_base_from_data(data, 1_233_152)?
780 .max_stacks(
781 data
782 .require_aura_max_stacks(
783 wowlab_types::sim::SpellIdx::from_raw(1_233_152),
784 )?,
785 )
786 .periodic_damage_from_spell(
787 wowlab_engine_combat::validated_milliseconds(
788 1000.0,
789 1_233_152,
790 "periodic_damage.tick_ms",
791 )?,
792 wowlab_engine_combat::DamagePayload::new(
793 196_771,
794 ((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(196_771), 1))
795 * 100_000.0)
796 .round() / 100_000.0,
797 wowlab_engine_combat::DamageFlags::empty(),
798 ),
799 )
800 .apply_periodic_behavior_from_data(data, 1_233_152)
801}
802fn aura_frozen_dominion_mastery(
803 a: AuraDefinitionDraft,
804 data: &ResolvedGameData,
805) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
806 Ok(
807 a
808 .on_player()
809 .apply_base_from_data(data, 377_253)?
810 .max_stacks(
811 data
812 .require_aura_max_stacks(
813 wowlab_types::sim::SpellIdx::from_raw(377_253),
814 )?,
815 ),
816 )
817}
818fn aura_exterminate(
819 a: AuraDefinitionDraft,
820 data: &ResolvedGameData,
821) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
822 Ok(
823 a
824 .on_player()
825 .apply_base_from_data(data, 441_416)?
826 .max_stacks(
827 data
828 .require_aura_max_stacks(
829 wowlab_types::sim::SpellIdx::from_raw(441_416),
830 )?,
831 ),
832 )
833}
834fn spell_obliterate(
835 s: SpellDefinitionDraft,
836 data: &ResolvedGameData,
837) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
838 Ok(
839 s
840 .apply_base_from_data(data, 49020)?
841 .without_data_damage()
842 .apply_aoe_from_data(data)
843 .on_cast(crate::hooks::frost_death_knight::obliterate_hook)
844 .cost_free_when_aura(1_230_959),
845 )
846}
847fn spell_frost_strike(
848 s: SpellDefinitionDraft,
849 data: &ResolvedGameData,
850) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
851 Ok(
852 s
853 .apply_base_from_data(data, 49143)?
854 .without_data_damage()
855 .apply_aoe_from_data(data)
856 .on_cast(crate::hooks::frost_death_knight::frost_strike_hook),
857 )
858}
859fn spell_howling_blast(
860 s: SpellDefinitionDraft,
861 data: &ResolvedGameData,
862) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
863 Ok(
864 s
865 .apply_base_from_data(data, 49184)?
866 .without_data_damage()
867 .apply_aoe_from_data(data)
868 .on_cast(crate::hooks::frost_death_knight::howling_blast_hook)
869 .cost_free_when_aura(59052),
870 )
871}
872fn spell_pillar_of_frost(
873 s: SpellDefinitionDraft,
874 data: &ResolvedGameData,
875) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
876 Ok(
877 s
878 .apply_base_from_data(data, 51271)?
879 .applies_inferred_aura(AURA_PILLAR_OF_FROST, 51271)
880 .apply_aoe_from_data(data)
881 .on_cast(crate::hooks::frost_death_knight::pillar_of_frost_hook),
882 )
883}
884fn spell_empower_rune_weapon(
885 s: SpellDefinitionDraft,
886 data: &ResolvedGameData,
887) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
888 Ok(
889 s
890 .apply_base_from_data(data, 47568)?
891 .applies_inferred_aura(AURA_EMPOWER_RUNE_WEAPON, 1_230_959)
892 .apply_aoe_from_data(data)
893 .on_cast(crate::hooks::frost_death_knight::empower_rune_weapon_hook)
894 .cooldown_bypass_when_aura(AURA::MID1_4PC),
895 )
896}
897fn spell_frostwyrms_fury(
898 s: SpellDefinitionDraft,
899 data: &ResolvedGameData,
900) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
901 Ok(
902 s
903 .apply_base_from_data(data, 279_302)?
904 .without_data_damage()
905 .apply_aoe_from_data(data)
906 .on_cast(crate::hooks::frost_death_knight::frostwyrms_fury_hook),
907 )
908}
909fn spell_glacial_advance(
910 s: SpellDefinitionDraft,
911 data: &ResolvedGameData,
912) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
913 Ok(
914 s
915 .apply_base_from_data(data, 194_913)?
916 .damage_ap_from_data(
917 wowlab_engine_domain::dbc::EffectLookup::new(
918 data,
919 wowlab_types::sim::EffectRef::new(
920 wowlab_types::sim::SpellIdx::from_raw(195_975),
921 1,
922 ),
923 ),
924 )?
925 .apply_aoe_from_data(data),
926 )
927}
928fn spell_frostscythe(
929 s: SpellDefinitionDraft,
930 data: &ResolvedGameData,
931) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
932 Ok(s.apply_base_from_data(data, 207_230)?.apply_aoe_from_data(data))
933}
934fn spell_soul_reaper(
935 s: SpellDefinitionDraft,
936 data: &ResolvedGameData,
937) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
938 Ok(s.apply_base_from_data(data, 343_294)?.apply_aoe_from_data(data))
939}
940fn spell_rune_strike(
941 s: SpellDefinitionDraft,
942 data: &ResolvedGameData,
943) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
944 Ok(s.apply_base_from_data(data, 316_239)?.apply_aoe_from_data(data))
945}
946fn spell_remorseless_winter(
947 s: SpellDefinitionDraft,
948 data: &ResolvedGameData,
949) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
950 Ok(
951 s
952 .apply_base_from_data(data, 196_770)?
953 .applies_inferred_aura(AURA_REMORSELESS_WINTER, 1_233_152)
954 .apply_aoe_from_data(data)
955 .on_cast(crate::hooks::frost_death_knight::remorseless_winter_hook),
956 )
957}
958fn spell_breath_of_sindragosa(
959 s: SpellDefinitionDraft,
960 data: &ResolvedGameData,
961) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
962 Ok(
963 s
964 .apply_base_from_data(data, 1_249_658)?
965 .without_data_damage()
966 .applies_aura(AURA_BREATH_OF_SINDRAGOSA)
967 .apply_aoe_from_data(data)
968 .on_cast(crate::hooks::frost_death_knight::breath_of_sindragosa_hook),
969 )
970}
971fn spell_reapers_mark(
972 s: SpellDefinitionDraft,
973 data: &ResolvedGameData,
974) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
975 Ok(
976 s
977 .apply_base_from_data(data, 439_843)?
978 .apply_aoe_from_data(data)
979 .on_cast(crate::hooks::frost_death_knight::reapers_mark_hook),
980 )
981}
982pub(crate) fn build_combat_system(
983 params: &wowlab_engine_ports::HandlerParams<'_>,
984) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
985 let builder = BuiltCombatSystem::builder(params.stats.clone())
986 .spec_id(SpecId::FrostDK)
987 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
988 .mastery_spell(77514)
989 .mastery_hook(crate::hooks::frost_death_knight::mastery)
990 .resource("runes", 6.0, 0.0)
991 .resource_type_id(5)
992 .resource_start(6.0)
993 .secondary_resource("runic_power", 100.0)
994 .secondary_resource_type_id(6)
995 .aura(
996 "killing_machine",
997 AURA::KILLING_MACHINE,
998 |a| aura_killing_machine(a, ¶ms.game_data),
999 )
1000 .aura("rime", AURA::RIME, |a| aura_rime(a, ¶ms.game_data))
1001 .aura(
1002 "pillar_of_frost",
1003 AURA::PILLAR_OF_FROST,
1004 |a| aura_pillar_of_frost(a, ¶ms.game_data),
1005 )
1006 .aura(
1007 "empower_rune_weapon",
1008 AURA::EMPOWER_RUNE_WEAPON,
1009 |a| aura_empower_rune_weapon(a, ¶ms.game_data),
1010 )
1011 .aura("icy_talons", AURA::ICY_TALONS, |a| aura_icy_talons(a, ¶ms.game_data))
1012 .aura(
1013 "chosen_of_frostbrood_haste",
1014 AURA::CHOSEN_OF_FROSTBROOD_HASTE,
1015 |a| aura_chosen_of_frostbrood_haste(a, ¶ms.game_data),
1016 )
1017 .aura("frostbane", AURA::FROSTBANE, |a| aura_frostbane(a, ¶ms.game_data))
1018 .aura(
1019 "icy_onslaught",
1020 AURA::ICY_ONSLAUGHT,
1021 |a| aura_icy_onslaught(a, ¶ms.game_data),
1022 )
1023 .aura(
1024 "killing_streak",
1025 AURA::KILLING_STREAK,
1026 |a| aura_killing_streak(a, ¶ms.game_data),
1027 )
1028 .aura(
1029 "dark_talons_icy_talons",
1030 AURA::DARK_TALONS_ICY_TALONS,
1031 |a| aura_dark_talons_icy_talons(a, ¶ms.game_data),
1032 )
1033 .aura(
1034 "frost_fever",
1035 AURA::FROST_FEVER,
1036 |a| aura_frost_fever(a, ¶ms.game_data),
1037 )
1038 .aura(
1039 "bonegrinder_crit",
1040 AURA::BONEGRINDER_CRIT,
1041 |a| aura_bonegrinder_crit(a, ¶ms.game_data),
1042 )
1043 .aura(
1044 "bonegrinder_frost",
1045 AURA::BONEGRINDER_FROST,
1046 |a| aura_bonegrinder_frost(a, ¶ms.game_data),
1047 )
1048 .aura(
1049 "rune_mastery",
1050 AURA::RUNE_MASTERY,
1051 |a| aura_rune_mastery(a, ¶ms.game_data),
1052 )
1053 .aura("razorice", AURA::RAZORICE, |a| aura_razorice(a, ¶ms.game_data))
1054 .aura("brittle", AURA::BRITTLE, |a| aura_brittle(a, ¶ms.game_data))
1055 .aura(
1056 "frostreaper",
1057 AURA::FROSTREAPER,
1058 |a| aura_frostreaper(a, ¶ms.game_data),
1059 )
1060 .aura(
1061 "empowered_strikes",
1062 AURA::EMPOWERED_STRIKES,
1063 |a| aura_empowered_strikes(a, ¶ms.game_data),
1064 )
1065 .aura("mid1_4pc", AURA::MID1_4PC, |a| aura_mid1_4pc(a, ¶ms.game_data))
1066 .aura(
1067 "frozen_dominion",
1068 AURA::FROZEN_DOMINION,
1069 |a| aura_frozen_dominion(a, ¶ms.game_data),
1070 )
1071 .aura(
1072 "breath_of_sindragosa",
1073 AURA::BREATH_OF_SINDRAGOSA,
1074 |a| aura_breath_of_sindragosa(a, ¶ms.game_data),
1075 )
1076 .aura(
1077 "remorseless_winter",
1078 AURA::REMORSELESS_WINTER,
1079 |a| aura_remorseless_winter(a, ¶ms.game_data),
1080 )
1081 .aura(
1082 "frozen_dominion_mastery",
1083 AURA::FROZEN_DOMINION_MASTERY,
1084 |a| aura_frozen_dominion_mastery(a, ¶ms.game_data),
1085 )
1086 .aura(
1087 "exterminate",
1088 AURA::EXTERMINATE,
1089 |a| aura_exterminate(a, ¶ms.game_data),
1090 )
1091 .spell(
1092 "obliterate",
1093 SPELL::OBLITERATE,
1094 |s| spell_obliterate(s, ¶ms.game_data),
1095 )
1096 .spell(
1097 "frost_strike",
1098 SPELL::FROST_STRIKE,
1099 |s| spell_frost_strike(s, ¶ms.game_data),
1100 )
1101 .spell(
1102 "howling_blast",
1103 SPELL::HOWLING_BLAST,
1104 |s| spell_howling_blast(s, ¶ms.game_data),
1105 )
1106 .spell(
1107 "pillar_of_frost",
1108 SPELL::PILLAR_OF_FROST,
1109 |s| spell_pillar_of_frost(s, ¶ms.game_data),
1110 )
1111 .spell(
1112 "empower_rune_weapon",
1113 SPELL::EMPOWER_RUNE_WEAPON,
1114 |s| spell_empower_rune_weapon(s, ¶ms.game_data),
1115 )
1116 .spell(
1117 "frostwyrms_fury",
1118 SPELL::FROSTWYRMS_FURY,
1119 |s| spell_frostwyrms_fury(s, ¶ms.game_data),
1120 )
1121 .spell(
1122 "glacial_advance",
1123 SPELL::GLACIAL_ADVANCE,
1124 |s| spell_glacial_advance(s, ¶ms.game_data),
1125 )
1126 .spell(
1127 "frostscythe",
1128 SPELL::FROSTSCYTHE,
1129 |s| spell_frostscythe(s, ¶ms.game_data),
1130 )
1131 .spell(
1132 "soul_reaper",
1133 SPELL::SOUL_REAPER,
1134 |s| spell_soul_reaper(s, ¶ms.game_data),
1135 )
1136 .spell(
1137 "rune_strike",
1138 SPELL::RUNE_STRIKE,
1139 |s| spell_rune_strike(s, ¶ms.game_data),
1140 )
1141 .spell(
1142 "remorseless_winter",
1143 SPELL::REMORSELESS_WINTER,
1144 |s| spell_remorseless_winter(s, ¶ms.game_data),
1145 )
1146 .spell(
1147 "breath_of_sindragosa",
1148 SPELL::BREATH_OF_SINDRAGOSA,
1149 |s| spell_breath_of_sindragosa(s, ¶ms.game_data),
1150 )
1151 .spell(
1152 "reapers_mark",
1153 SPELL::REAPERS_MARK,
1154 |s| spell_reapers_mark(s, ¶ms.game_data),
1155 )
1156 .auto_attack(|a| {
1157 a
1158 .spell_id(6603)
1159 .swing_ms(3600)
1160 .apply_base_from_data(¶ms.game_data)
1161 .on_swing(crate::hooks::frost_death_knight::swing_hook)
1162 })
1163 .game_data(params.game_data.clone())
1164 .talent_spell_ids(TALENTS)
1165 .talent_selections(params.talent_selections)
1166 .set_bonus_auras(params.set_bonus_auras)
1167 .encounter(params.encounter.clone());
1168 let builder = crate::generated::items::register_equipped(
1169 builder,
1170 ¶ms.game_data,
1171 params.equipped_items,
1172 )?;
1173
1174 builder
1175 .build(params.rotation)
1176 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1177}
1178fn new_handler(
1179 params: wowlab_engine_ports::HandlerParams<'_>,
1180) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1181 let handler = crate::composition::compose_handler(
1182 build_combat_system,
1183 ¶ms,
1184 crate::hooks::frost_death_knight::FrostDkHandler::try_new,
1185 )?;
1186
1187 Ok(Box::new(handler))
1188}
1189static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1190 primary_resource: ResourceType::Runes,
1191 secondary_resource: Some(ResourceType::RunicPower),
1192 spell_ids: DECLARED_SPELL_IDS,
1193 aura_ids: DECLARED_AURA_IDS,
1194 server_proc_entries: &[],
1195 talents: TALENTS,
1196 rotation_field_schema: &[],
1197 metrics_plugin_id: None,
1198 hero_talent_trees: &[
1199 HeroTalentTreeDesc {
1200 name: "Deathbringer",
1201 spells: HERO_TREE_DEATHBRINGER_SPELLS,
1202 auras: HERO_TREE_DEATHBRINGER_AURAS,
1203 },
1204 HeroTalentTreeDesc {
1205 name: "Frost",
1206 spells: HERO_TREE_FROST_SPELLS,
1207 auras: HERO_TREE_FROST_AURAS,
1208 },
1209 ],
1210 reported_spells: REPORTED_SPELLS,
1211 masked_passive_effects: &[],
1212 passive_effect_overrides: &[],
1213};
1214pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1215 spec_id: SpecId::FrostDK,
1216 display_name: "Frost Death Knight",
1217 metadata: DECLARED_METADATA,
1218 handler_factory: new_handler,
1219};
1220wowlab_engine_combat::smoke_test!(build_combat_system);