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 BLOODTHIRST: u32 = 23881;
18 pub(crate) const RAGING_BLOW: u32 = 85288;
20 pub(crate) const RAMPAGE: u32 = 184_367;
22 pub(crate) const EXECUTE: u32 = 280_735;
24 pub(crate) const WHIRLWIND: u32 = 190_411;
26 pub(crate) const RECKLESSNESS: u32 = 1719;
28 pub(crate) const AVATAR: u32 = 107_574;
30 pub(crate) const BLOODBATH: u32 = 335_096;
32 pub(crate) const CRUSHING_BLOW: u32 = 335_097;
34 pub(crate) const THUNDER_CLAP: u32 = 6343;
36 pub(crate) const REND: u32 = 772;
38 pub(crate) const BATTLE_SHOUT: u32 = 6673;
40 pub(crate) const SLAM: u32 = 1464;
42 pub(crate) const HEROIC_THROW: u32 = 57755;
44 pub(crate) const BLADESTORM: u32 = 227_847;
46 pub(crate) const ODYNS_FURY: u32 = 385_059;
48 pub(crate) const RAVAGER: u32 = 228_920;
50 pub(crate) const SLAYERS_STRIKE: u32 = 445_579;
52 pub(crate) const REAP_THE_STORM_EXECUTE: u32 = 446_005;
54}
55pub(crate) mod AURA {
56 pub(crate) const ENRAGE: u32 = 184_362;
58 pub(crate) const RECKLESSNESS: u32 = 1719;
60 pub(crate) const WHIRLWIND: u32 = 85739;
62 pub(crate) const AVATAR: u32 = 107_574;
64 pub(crate) const FRENZY: u32 = 335_082;
66 pub(crate) const SUDDEN_DEATH: u32 = 52437;
68 pub(crate) const REND: u32 = 388_539;
70 pub(crate) const BLOODBATH_DOT: u32 = 113_344;
72 pub(crate) const GUSHING_WOUND: u32 = 385_042;
74 pub(crate) const BATTLE_SHOUT: u32 = 6673;
76 pub(crate) const BATTLE_SHOUT_HIGHLIGHT: u32 = 6673;
78 pub(crate) const RAMPAGE: u32 = 184_367;
80 pub(crate) const DEEP_WOUNDS: u32 = 262_115;
82 pub(crate) const WILD_STRIKES: u32 = 392_778;
84 pub(crate) const SURGE_OF_ADRENALINE: u32 = 1_265_560;
86 pub(crate) const BLOODBORNE: u32 = 1_265_406;
88 pub(crate) const BERSERKER_STANCE: u32 = 386_196;
90 pub(crate) const BLADESTORM: u32 = 227_847;
92 pub(crate) const ODYNS_FURY_DOT: u32 = 385_060;
94 pub(crate) const RAVAGER: u32 = 228_920;
96 pub(crate) const EXECUTIONER: u32 = 445_584;
98 pub(crate) const OVERWHELMED: u32 = 445_836;
100 pub(crate) const IMMINENT_DEMISE: u32 = 445_606;
102 pub(crate) const EXECUTIONERS_WRATH: u32 = 1_265_575;
104 pub(crate) const THUNDER_BLAST: u32 = 435_615;
106 pub(crate) const CRASHING_THUNDER: u32 = 436_707;
108}
109pub(crate) mod TALENT {
110 pub(crate) const ANGER_MANAGEMENT: u32 = 152_278;
112 pub(crate) const AVATAR: u32 = 107_574;
114 pub(crate) const BERSERKER_STANCE: u32 = 386_196;
116 pub(crate) const BLOODBORNE: u32 = 385_703;
118 pub(crate) const COLD_STEEL_HOT_BLOOD: u32 = 383_959;
120 pub(crate) const DEEP_WOUNDS: u32 = 1_261_060;
122 pub(crate) const EXECUTIONERS_WRATH: u32 = 1_265_570;
124 pub(crate) const FROTHING_BERSERKER: u32 = 392_792;
126 pub(crate) const HACK_AND_SLASH: u32 = 383_877;
128 pub(crate) const IMMINENT_DEMISE: u32 = 444_769;
130 pub(crate) const IMPROVED_EXECUTE: u32 = 316_402;
132 pub(crate) const IMPROVED_RAGING_BLOW: u32 = 383_854;
134 pub(crate) const IMPROVED_WHIRLWIND: u32 = 12950;
136 pub(crate) const MASSACRE: u32 = 206_315;
138 pub(crate) const OVERWHELMING_BLADES: u32 = 444_772;
140 pub(crate) const RAMPAGING_BERSERKER: u32 = 1_269_308;
142 pub(crate) const RAMPAGING_BERSERKER_2: u32 = 1_269_309;
144 pub(crate) const RAMPAGING_RUIN: u32 = 1_265_357;
146 pub(crate) const REAP_THE_STORM: u32 = 444_775;
148 pub(crate) const RECKLESS_ABANDON: u32 = 396_749;
150 pub(crate) const SLAYERS_DOMINANCE: u32 = 444_767;
152 pub(crate) const SLAYERS_MALICE: u32 = 444_779;
154 pub(crate) const SUDDEN_DEATH: u32 = 29725;
156 pub(crate) const SURGE_OF_ADRENALINE: u32 = 1_265_359;
158 pub(crate) const THUNDER_CLAP: u32 = 6343;
160 pub(crate) const UNHINGED: u32 = 386_628;
162 pub(crate) const UNRELENTING_ONSLAUGHT: u32 = 444_780;
164 pub(crate) const WAR_MACHINE: u32 = 262_231;
166 pub(crate) const WILD_STRIKES: u32 = 382_946;
168 pub(crate) const WRATH_AND_FURY: u32 = 392_936;
170}
171pub(crate) mod SET_BONUS {
172 pub(crate) const MID1_FURY_2PC: u32 = 1_264_877;
174 pub(crate) const MID1_FURY_4PC: u32 = 1_264_878;
176}
177pub(crate) mod HERO {
178 pub(crate) mod SLAYER {
179 pub(crate) mod SPELL {
180 pub(crate) const REAP_THE_STORM: u32 = 446_005;
182 pub(crate) const SLAYERS_STRIKE: u32 = 445_579;
184 }
185 pub(crate) mod AURA {
186 pub(crate) const BRUTAL_FINISH: u32 = 446_918;
188 pub(crate) const FIERCE_FOLLOWTHROUGH: u32 = 458_689;
190 pub(crate) const OPPORTUNIST: u32 = 456_120;
192 pub(crate) const VIOLENT_EUPHORIA: u32 = 1_270_731;
194 }
195 }
196 pub(crate) mod MOUNTAIN_THANE {
197 pub(crate) mod SPELL {
198 pub(crate) const GROUND_CURRENT: u32 = 460_670;
200 pub(crate) const LIGHTNING_STRIKE: u32 = 435_791;
202 pub(crate) const THUNDER_BLAST: u32 = 435_222;
204 }
205 pub(crate) mod AURA {
206 pub(crate) const BURST_OF_POWER: u32 = 437_121;
208 pub(crate) const THUNDER_BLAST_BUFF: u32 = 435_615;
210 }
211 }
212}
213static HERO_TREE_SLAYER_SPELLS: &[(&str, u32)] = &[
214 ("REAP_THE_STORM", 446_005),
215 ("SLAYERS_STRIKE", 445_579),
216];
217static HERO_TREE_SLAYER_AURAS: &[(&str, u32)] = &[
218 ("BRUTAL_FINISH", 446_918),
219 ("FIERCE_FOLLOWTHROUGH", 458_689),
220 ("OPPORTUNIST", 456_120),
221 ("VIOLENT_EUPHORIA", 1_270_731),
222];
223static HERO_TREE_MOUNTAIN_THANE_SPELLS: &[(&str, u32)] = &[
224 ("GROUND_CURRENT", 460_670),
225 ("LIGHTNING_STRIKE", 435_791),
226 ("THUNDER_BLAST", 435_222),
227];
228static HERO_TREE_MOUNTAIN_THANE_AURAS: &[(&str, u32)] = &[
229 ("BURST_OF_POWER", 437_121),
230 ("THUNDER_BLAST_BUFF", 435_615),
231];
232pub(crate) const AURA_ENRAGE: LocalAuraIdx = LocalAuraIdx::new(0);
233pub(crate) const AURA_RECKLESSNESS: LocalAuraIdx = LocalAuraIdx::new(1);
234pub(crate) const AURA_WHIRLWIND: LocalAuraIdx = LocalAuraIdx::new(2);
235pub(crate) const AURA_AVATAR: LocalAuraIdx = LocalAuraIdx::new(3);
236pub(crate) const AURA_FRENZY: LocalAuraIdx = LocalAuraIdx::new(4);
237pub(crate) const AURA_SUDDEN_DEATH: LocalAuraIdx = LocalAuraIdx::new(5);
238pub(crate) const AURA_REND: LocalAuraIdx = LocalAuraIdx::new(6);
239pub(crate) const AURA_BLOODBATH_DOT: LocalAuraIdx = LocalAuraIdx::new(7);
240pub(crate) const AURA_GUSHING_WOUND: LocalAuraIdx = LocalAuraIdx::new(8);
241pub(crate) const AURA_BATTLE_SHOUT: LocalAuraIdx = LocalAuraIdx::new(9);
242pub(crate) const AURA_BATTLE_SHOUT_HIGHLIGHT: LocalAuraIdx = LocalAuraIdx::new(10);
243pub(crate) const AURA_RAMPAGE: LocalAuraIdx = LocalAuraIdx::new(11);
244pub(crate) const AURA_DEEP_WOUNDS: LocalAuraIdx = LocalAuraIdx::new(12);
245pub(crate) const AURA_WILD_STRIKES: LocalAuraIdx = LocalAuraIdx::new(13);
246pub(crate) const AURA_SURGE_OF_ADRENALINE: LocalAuraIdx = LocalAuraIdx::new(14);
247pub(crate) const AURA_BLOODBORNE: LocalAuraIdx = LocalAuraIdx::new(15);
248pub(crate) const AURA_BERSERKER_STANCE: LocalAuraIdx = LocalAuraIdx::new(16);
249pub(crate) const AURA_BLADESTORM: LocalAuraIdx = LocalAuraIdx::new(17);
250pub(crate) const AURA_ODYNS_FURY_DOT: LocalAuraIdx = LocalAuraIdx::new(18);
251pub(crate) const AURA_RAVAGER: LocalAuraIdx = LocalAuraIdx::new(19);
252pub(crate) const AURA_EXECUTIONER: LocalAuraIdx = LocalAuraIdx::new(20);
253pub(crate) const AURA_OVERWHELMED: LocalAuraIdx = LocalAuraIdx::new(21);
254pub(crate) const AURA_IMMINENT_DEMISE: LocalAuraIdx = LocalAuraIdx::new(22);
255pub(crate) const AURA_EXECUTIONERS_WRATH: LocalAuraIdx = LocalAuraIdx::new(23);
256pub(crate) const AURA_THUNDER_BLAST: LocalAuraIdx = LocalAuraIdx::new(24);
257pub(crate) const AURA_CRASHING_THUNDER: LocalAuraIdx = LocalAuraIdx::new(25);
258pub(crate) const AURA_COUNT: usize = 26;
259const _: () = assert!(
260 AURA_COUNT == 26, "AURA index ABI: count changed -- update positional hook consumers"
261);
262pub(crate) const SPELL_BLOODTHIRST: LocalSpellIdx = LocalSpellIdx::new(0);
263pub(crate) const SPELL_RAGING_BLOW: LocalSpellIdx = LocalSpellIdx::new(1);
264pub(crate) const SPELL_RAMPAGE: LocalSpellIdx = LocalSpellIdx::new(2);
265pub(crate) const SPELL_EXECUTE: LocalSpellIdx = LocalSpellIdx::new(3);
266pub(crate) const SPELL_WHIRLWIND: LocalSpellIdx = LocalSpellIdx::new(4);
267pub(crate) const SPELL_RECKLESSNESS: LocalSpellIdx = LocalSpellIdx::new(5);
268pub(crate) const SPELL_AVATAR: LocalSpellIdx = LocalSpellIdx::new(6);
269pub(crate) const SPELL_BLOODBATH: LocalSpellIdx = LocalSpellIdx::new(7);
270pub(crate) const SPELL_CRUSHING_BLOW: LocalSpellIdx = LocalSpellIdx::new(8);
271pub(crate) const SPELL_THUNDER_CLAP: LocalSpellIdx = LocalSpellIdx::new(9);
272pub(crate) const SPELL_REND: LocalSpellIdx = LocalSpellIdx::new(10);
273pub(crate) const SPELL_BATTLE_SHOUT: LocalSpellIdx = LocalSpellIdx::new(11);
274pub(crate) const SPELL_SLAM: LocalSpellIdx = LocalSpellIdx::new(12);
275pub(crate) const SPELL_HEROIC_THROW: LocalSpellIdx = LocalSpellIdx::new(13);
276pub(crate) const SPELL_BLADESTORM: LocalSpellIdx = LocalSpellIdx::new(14);
277pub(crate) const SPELL_ODYNS_FURY: LocalSpellIdx = LocalSpellIdx::new(15);
278pub(crate) const SPELL_RAVAGER: LocalSpellIdx = LocalSpellIdx::new(16);
279pub(crate) const SPELL_SLAYERS_STRIKE: LocalSpellIdx = LocalSpellIdx::new(17);
280pub(crate) const SPELL_REAP_THE_STORM_EXECUTE: LocalSpellIdx = LocalSpellIdx::new(18);
281pub(crate) const SPELL_COUNT: usize = 19;
282const _: () = assert!(
283 SPELL_COUNT == 19,
284 "SPELL index ABI: count changed -- update positional hook consumers"
285);
286pub(crate) mod EFFECT {
287 pub(crate) const BLOODTHIRST_ENRAGE_CHANCE: (u32, u8) = (23881, 3);
289 pub(crate) const BLOODTHIRST_DAMAGE: (u32, u8) = (23881, 1);
291 pub(crate) const BLOODTHIRST_RAGE: (u32, u8) = (23881, 2);
293 pub(crate) const BLOODBATH_DAMAGE: (u32, u8) = (335_096, 1);
295 pub(crate) const BLOODBATH_RAGE: (u32, u8) = (335_096, 2);
297 pub(crate) const BLADESTORM_PERIOD: (u32, u8) = (227_847, 1);
299 pub(crate) const RAMPAGING_BERSERKER_COST: (u32, u8) = (1_269_309, 1);
301 pub(crate) const RAMPAGING_BERSERKER_DMG: (u32, u8) = (1_269_309, 2);
303 pub(crate) const BLOODBATH_ENRAGE_CHANCE: (u32, u8) = (335_096, 3);
305 pub(crate) const COLD_STEEL_HOT_BLOOD_RAGE: (u32, u8) = (383_978, 1);
307 pub(crate) const RB_RESET_CHANCE: (u32, u8) = (85288, 1);
309 pub(crate) const WNF_RESET_CHANCE: (u32, u8) = (392_936, 1);
311 pub(crate) const IMPROVED_EXECUTE_RAGE: (u32, u8) = (316_402, 3);
313 pub(crate) const EXECUTIONERS_WRATH_RAGE: (u32, u8) = (1_265_570, 1);
315 pub(crate) const MASSACRE_EXECUTE_CDR_MS: (u32, u8) = (206_315, 3);
317 pub(crate) const MASSACRE_PCT: (u32, u8) = (206_315, 2);
319 pub(crate) const SLAYERS_STRIKE_DMG: (u32, u8) = (445_579, 1);
321 pub(crate) const IMMINENT_DEMISE_EVERY: (u32, u8) = (444_769, 1);
323 pub(crate) const IMMINENT_DEMISE_REAP_CHANCE: (u32, u8) = (444_769, 2);
325 pub(crate) const REAP_DMG: (u32, u8) = (446_005, 1);
327 pub(crate) const UNRELENTING_CDR_S: (u32, u8) = (444_780, 1);
329 pub(crate) const UNRELENTING_OVERWHELMED: (u32, u8) = (444_780, 2);
331 pub(crate) const ANGER_MANAGEMENT_DIV: (u32, u8) = (152_278, 3);
333 pub(crate) const FROTHING_REFUND: (u32, u8) = (392_792, 1);
335 pub(crate) const RECKLESS_ABANDON_RAGE: (u32, u8) = (396_749, 1);
337 pub(crate) const SET4PC_ODYNS_CDR_MS: (u32, u8) = (1_264_878, 1);
339}
340static REPORTED_SPELLS: &[(&str, u32)] = &[];
341static DECLARED_SPELL_IDS: &[u32] = &[
342 23881, 85288, 184_367, 280_735, 190_411, 1719, 107_574, 335_096, 335_097, 6343, 772,
343 6673, 1464, 57755, 227_847, 385_059, 228_920, 445_579, 446_005, 184_362, 1719, 85739,
344 107_574, 335_082, 52437, 388_539, 113_344, 385_042, 6673, 6673, 184_367, 262_115,
345 392_778, 1_265_560, 1_265_406, 386_196, 227_847, 385_060, 228_920, 445_584, 445_836,
346 445_606, 1_265_575, 435_615, 436_707, 6603, 6603, 1719, 23881, 76856, 85288, 152_278,
347 206_315, 227_847, 316_402, 335_096, 383_978, 385_042, 392_792, 392_936, 396_749,
348 444_769, 444_780, 445_579, 446_005, 1_264_878, 1_265_570, 1_269_309, 446_005,
349 445_579, 446_918, 458_689, 456_120, 1_270_731, 460_670, 435_791, 435_222, 437_121,
350 435_615,
351];
352static DECLARED_AURA_IDS: &[u32] = &[
353 184_362, 1719, 85739, 107_574, 335_082, 52437, 388_539, 113_344, 385_042, 6673, 6673,
354 184_367, 262_115, 392_778, 1_265_560, 1_265_406, 386_196, 227_847, 385_060, 228_920,
355 445_584, 445_836, 445_606, 1_265_575, 435_615, 436_707, 446_918, 458_689, 456_120,
356 1_270_731, 437_121, 435_615,
357];
358static TALENTS: &[(&str, u32)] = &[
359 ("ANGER_MANAGEMENT", TALENT::ANGER_MANAGEMENT),
360 ("AVATAR", TALENT::AVATAR),
361 ("BERSERKER_STANCE", TALENT::BERSERKER_STANCE),
362 ("BLOODBORNE", TALENT::BLOODBORNE),
363 ("COLD_STEEL_HOT_BLOOD", TALENT::COLD_STEEL_HOT_BLOOD),
364 ("DEEP_WOUNDS", TALENT::DEEP_WOUNDS),
365 ("EXECUTIONERS_WRATH", TALENT::EXECUTIONERS_WRATH),
366 ("FROTHING_BERSERKER", TALENT::FROTHING_BERSERKER),
367 ("HACK_AND_SLASH", TALENT::HACK_AND_SLASH),
368 ("IMMINENT_DEMISE", TALENT::IMMINENT_DEMISE),
369 ("IMPROVED_EXECUTE", TALENT::IMPROVED_EXECUTE),
370 ("IMPROVED_RAGING_BLOW", TALENT::IMPROVED_RAGING_BLOW),
371 ("IMPROVED_WHIRLWIND", TALENT::IMPROVED_WHIRLWIND),
372 ("MASSACRE", TALENT::MASSACRE),
373 ("OVERWHELMING_BLADES", TALENT::OVERWHELMING_BLADES),
374 ("RAMPAGING_BERSERKER", TALENT::RAMPAGING_BERSERKER),
375 ("RAMPAGING_BERSERKER_2", TALENT::RAMPAGING_BERSERKER_2),
376 ("RAMPAGING_RUIN", TALENT::RAMPAGING_RUIN),
377 ("REAP_THE_STORM", TALENT::REAP_THE_STORM),
378 ("RECKLESS_ABANDON", TALENT::RECKLESS_ABANDON),
379 ("SLAYERS_DOMINANCE", TALENT::SLAYERS_DOMINANCE),
380 ("SLAYERS_MALICE", TALENT::SLAYERS_MALICE),
381 ("SUDDEN_DEATH", TALENT::SUDDEN_DEATH),
382 ("SURGE_OF_ADRENALINE", TALENT::SURGE_OF_ADRENALINE),
383 ("THUNDER_CLAP", TALENT::THUNDER_CLAP),
384 ("UNHINGED", TALENT::UNHINGED),
385 ("UNRELENTING_ONSLAUGHT", TALENT::UNRELENTING_ONSLAUGHT),
386 ("WAR_MACHINE", TALENT::WAR_MACHINE),
387 ("WILD_STRIKES", TALENT::WILD_STRIKES),
388 ("WRATH_AND_FURY", TALENT::WRATH_AND_FURY),
389];
390pub(crate) mod FURY_WARRIOR {
391 pub(crate) const BLOODTHIRST_CASTS: u32 = 0;
392 pub(crate) const RAGING_BLOW_CASTS: u32 = 1;
393 pub(crate) const RAMPAGE_CASTS: u32 = 2;
394 pub(crate) const EXECUTE_CASTS: u32 = 3;
395 pub(crate) const RECKLESSNESS_CASTS: u32 = 4;
396 pub(crate) const AVATAR_CASTS: u32 = 5;
397 pub(crate) const ENRAGE_UPTIME_MS: u32 = 6;
398 pub(crate) const RECKLESSNESS_UPTIME_MS: u32 = 7;
399}
400fn aura_enrage(
401 a: AuraDefinitionDraft,
402 data: &ResolvedGameData,
403) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
404 Ok(
405 a
406 .on_player()
407 .apply_base_from_data(data, 184_362)?
408 .max_stacks(
409 data
410 .require_aura_max_stacks(
411 wowlab_types::sim::SpellIdx::from_raw(184_362),
412 )?,
413 ),
414 )
415}
416fn aura_recklessness(
417 a: AuraDefinitionDraft,
418 data: &ResolvedGameData,
419) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
420 a.on_player()
421 .apply_base_from_data(data, 1719)?
422 .max_stacks(
423 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(1719))?,
424 )
425 .resource_gain_mult_per_stack(
426 data.base_points(wowlab_types::sim::SpellIdx::from_raw(1719), 1),
427 )
428}
429fn aura_whirlwind(
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, 85739)?
437 .max_stacks(
438 data
439 .require_aura_max_stacks(
440 wowlab_types::sim::SpellIdx::from_raw(85739),
441 )?,
442 ),
443 )
444}
445fn aura_avatar(
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, 107_574)?
453 .max_stacks(
454 data
455 .require_aura_max_stacks(
456 wowlab_types::sim::SpellIdx::from_raw(107_574),
457 )?,
458 ),
459 )
460}
461fn aura_frenzy(
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, 335_082)?
469 .max_stacks(
470 data
471 .require_aura_max_stacks(
472 wowlab_types::sim::SpellIdx::from_raw(335_082),
473 )?,
474 ),
475 )
476}
477fn aura_sudden_death(
478 a: AuraDefinitionDraft,
479 data: &ResolvedGameData,
480) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
481 Ok(
482 a
483 .on_player()
484 .apply_base_from_data(data, 52437)?
485 .max_stacks(
486 data
487 .require_aura_max_stacks(
488 wowlab_types::sim::SpellIdx::from_raw(52437),
489 )?,
490 ),
491 )
492}
493fn aura_rend(
494 a: AuraDefinitionDraft,
495 data: &ResolvedGameData,
496) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
497 Ok(
498 a
499 .on_target()
500 .apply_base_from_data(data, 388_539)?
501 .max_stacks(
502 data
503 .require_aura_max_stacks(
504 wowlab_types::sim::SpellIdx::from_raw(388_539),
505 )?,
506 ),
507 )
508}
509fn aura_bloodbath_dot(
510 a: AuraDefinitionDraft,
511 data: &ResolvedGameData,
512) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
513 Ok(
514 a
515 .on_target()
516 .apply_base_from_data(data, 113_344)?
517 .max_stacks(
518 data
519 .require_aura_max_stacks(
520 wowlab_types::sim::SpellIdx::from_raw(113_344),
521 )?,
522 ),
523 )
524}
525fn aura_gushing_wound(
526 a: AuraDefinitionDraft,
527 data: &ResolvedGameData,
528) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
529 a.on_target()
530 .apply_base_from_data(data, 385_042)?
531 .max_stacks(
532 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(385_042))?,
533 )
534 .periodic_damage(
535 wowlab_engine_combat::validated_milliseconds(
536 data.period(wowlab_types::sim::SpellIdx::from_raw(385_042), 1),
537 385_042,
538 "periodic_damage.tick_ms",
539 )?,
540 data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(385_042), 1),
541 wowlab_engine_combat::DamageFlags::PHYSICAL,
542 )
543 .apply_periodic_behavior_from_data(data, 385_042)
544}
545fn aura_battle_shout(
546 a: AuraDefinitionDraft,
547 data: &ResolvedGameData,
548) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
549 Ok(
550 a
551 .on_player()
552 .apply_base_from_data(data, 6673)?
553 .max_stacks(
554 data
555 .require_aura_max_stacks(
556 wowlab_types::sim::SpellIdx::from_raw(6673),
557 )?,
558 ),
559 )
560}
561fn aura_battle_shout_highlight(
562 a: AuraDefinitionDraft,
563 data: &ResolvedGameData,
564) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
565 Ok(
566 a
567 .on_player()
568 .apply_base_from_data(data, 6673)?
569 .max_stacks(
570 data
571 .require_aura_max_stacks(
572 wowlab_types::sim::SpellIdx::from_raw(6673),
573 )?,
574 ),
575 )
576}
577fn aura_rampage(
578 a: AuraDefinitionDraft,
579 data: &ResolvedGameData,
580) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
581 Ok(
582 a
583 .on_player()
584 .apply_base_from_data(data, 184_367)?
585 .max_stacks(
586 data
587 .require_aura_max_stacks(
588 wowlab_types::sim::SpellIdx::from_raw(184_367),
589 )?,
590 ),
591 )
592}
593fn aura_deep_wounds(
594 a: AuraDefinitionDraft,
595 data: &ResolvedGameData,
596) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
597 Ok(
598 a
599 .on_target()
600 .apply_base_from_data(data, 262_115)?
601 .max_stacks(
602 data
603 .require_aura_max_stacks(
604 wowlab_types::sim::SpellIdx::from_raw(262_115),
605 )?,
606 ),
607 )
608}
609fn aura_wild_strikes(
610 a: AuraDefinitionDraft,
611 data: &ResolvedGameData,
612) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
613 Ok(
614 a
615 .on_player()
616 .apply_base_from_data(data, 392_778)?
617 .max_stacks(
618 data
619 .require_aura_max_stacks(
620 wowlab_types::sim::SpellIdx::from_raw(392_778),
621 )?,
622 ),
623 )
624}
625fn aura_surge_of_adrenaline(
626 a: AuraDefinitionDraft,
627 data: &ResolvedGameData,
628) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
629 Ok(
630 a
631 .on_player()
632 .apply_base_from_data(data, 1_265_560)?
633 .max_stacks(
634 data
635 .require_aura_max_stacks(
636 wowlab_types::sim::SpellIdx::from_raw(1_265_560),
637 )?,
638 ),
639 )
640}
641fn aura_bloodborne(
642 a: AuraDefinitionDraft,
643 data: &ResolvedGameData,
644) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
645 Ok(
646 a
647 .on_player()
648 .apply_base_from_data(data, 1_265_406)?
649 .max_stacks(
650 data
651 .require_aura_max_stacks(
652 wowlab_types::sim::SpellIdx::from_raw(1_265_406),
653 )?,
654 ),
655 )
656}
657fn aura_berserker_stance(
658 a: AuraDefinitionDraft,
659 data: &ResolvedGameData,
660) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
661 Ok(
662 a
663 .on_player()
664 .apply_base_from_data(data, 386_196)?
665 .max_stacks(
666 data
667 .require_aura_max_stacks(
668 wowlab_types::sim::SpellIdx::from_raw(386_196),
669 )?,
670 ),
671 )
672}
673fn aura_bladestorm(
674 a: AuraDefinitionDraft,
675 data: &ResolvedGameData,
676) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
677 Ok(
678 a
679 .on_player()
680 .apply_base_from_data(data, 227_847)?
681 .max_stacks(
682 data
683 .require_aura_max_stacks(
684 wowlab_types::sim::SpellIdx::from_raw(227_847),
685 )?,
686 )
687 .periodic_hook(
688 wowlab_engine_combat::validated_milliseconds(
689 data.period(wowlab_types::sim::SpellIdx::from_raw(227_847), 1),
690 227_847,
691 "periodic_hook.tick_ms",
692 )?,
693 )
694 .apply_periodic_behavior_from_data(data, 227_847)?
695 .tick_hook(crate::hooks::fury_warrior::bladestorm_tick_hook),
696 )
697}
698fn aura_odyns_fury_dot(
699 a: AuraDefinitionDraft,
700 data: &ResolvedGameData,
701) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
702 Ok(
703 a
704 .on_target()
705 .apply_base_from_data(data, 385_060)?
706 .max_stacks(
707 data
708 .require_aura_max_stacks(
709 wowlab_types::sim::SpellIdx::from_raw(385_060),
710 )?,
711 ),
712 )
713}
714fn aura_ravager(
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, 228_920)?
722 .max_stacks(
723 data
724 .require_aura_max_stacks(
725 wowlab_types::sim::SpellIdx::from_raw(228_920),
726 )?,
727 ),
728 )
729}
730fn aura_executioner(
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, 445_584)?
738 .max_stacks(
739 data
740 .require_aura_max_stacks(
741 wowlab_types::sim::SpellIdx::from_raw(445_584),
742 )?,
743 ),
744 )
745}
746fn aura_overwhelmed(
747 a: AuraDefinitionDraft,
748 data: &ResolvedGameData,
749) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
750 Ok(
751 a
752 .on_target()
753 .apply_base_from_data(data, 445_836)?
754 .max_stacks(
755 data
756 .require_aura_max_stacks(
757 wowlab_types::sim::SpellIdx::from_raw(445_836),
758 )?,
759 ),
760 )
761}
762fn aura_imminent_demise(
763 a: AuraDefinitionDraft,
764 data: &ResolvedGameData,
765) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
766 Ok(
767 a
768 .on_player()
769 .apply_base_from_data(data, 445_606)?
770 .max_stacks(
771 data
772 .require_aura_max_stacks(
773 wowlab_types::sim::SpellIdx::from_raw(445_606),
774 )?,
775 ),
776 )
777}
778fn aura_executioners_wrath(
779 a: AuraDefinitionDraft,
780 data: &ResolvedGameData,
781) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
782 Ok(
783 a
784 .on_player()
785 .apply_base_from_data(data, 1_265_575)?
786 .max_stacks(
787 data
788 .require_aura_max_stacks(
789 wowlab_types::sim::SpellIdx::from_raw(1_265_575),
790 )?,
791 ),
792 )
793}
794fn aura_thunder_blast(
795 a: AuraDefinitionDraft,
796 data: &ResolvedGameData,
797) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
798 Ok(
799 a
800 .on_player()
801 .apply_base_from_data(data, 435_615)?
802 .max_stacks(
803 data
804 .require_aura_max_stacks(
805 wowlab_types::sim::SpellIdx::from_raw(435_615),
806 )?,
807 ),
808 )
809}
810fn aura_crashing_thunder(
811 a: AuraDefinitionDraft,
812 data: &ResolvedGameData,
813) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
814 Ok(
815 a
816 .on_player()
817 .apply_base_from_data(data, 436_707)?
818 .max_stacks(
819 data
820 .require_aura_max_stacks(
821 wowlab_types::sim::SpellIdx::from_raw(436_707),
822 )?,
823 ),
824 )
825}
826fn spell_bloodthirst(
827 s: SpellDefinitionDraft,
828 data: &ResolvedGameData,
829) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
830 Ok(
831 s
832 .apply_base_from_data(data, 23881)?
833 .apply_aoe_from_data(data)
834 .on_cast(crate::hooks::fury_warrior::bloodthirst_hook),
835 )
836}
837fn spell_raging_blow(
838 s: SpellDefinitionDraft,
839 data: &ResolvedGameData,
840) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
841 Ok(
842 s
843 .apply_base_from_data(data, 85288)?
844 .without_primary_data_damage()
845 .apply_aoe_from_data(data)
846 .on_cast(crate::hooks::fury_warrior::raging_blow_hook),
847 )
848}
849fn spell_rampage(
850 s: SpellDefinitionDraft,
851 data: &ResolvedGameData,
852) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
853 Ok(
854 s
855 .apply_base_from_data(data, 184_367)?
856 .without_primary_data_damage()
857 .trigger_program_predicate(
858 2,
859 crate::hooks::fury_warrior::rampage_single_target_trigger,
860 )
861 .trigger_program_predicate(
862 3,
863 crate::hooks::fury_warrior::rampage_single_target_trigger,
864 )
865 .trigger_program_predicate(
866 4,
867 crate::hooks::fury_warrior::rampage_single_target_trigger,
868 )
869 .trigger_program_predicate(
870 5,
871 crate::hooks::fury_warrior::rampage_single_target_trigger,
872 )
873 .trigger_program_predicate(
874 6,
875 crate::hooks::fury_warrior::rampaging_ruin_trigger,
876 )
877 .trigger_program_predicate(
878 7,
879 crate::hooks::fury_warrior::rampaging_ruin_trigger,
880 )
881 .trigger_program_predicate(
882 8,
883 crate::hooks::fury_warrior::rampaging_ruin_trigger,
884 )
885 .trigger_program_predicate(
886 9,
887 crate::hooks::fury_warrior::rampaging_ruin_trigger,
888 )
889 .applies_aura(AURA_ENRAGE)
890 .apply_aoe_from_data(data)
891 .on_cast(crate::hooks::fury_warrior::rampage_hook),
892 )
893}
894fn spell_execute(
895 s: SpellDefinitionDraft,
896 data: &ResolvedGameData,
897) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
898 Ok(
899 s
900 .apply_base_from_data(data, 280_735)?
901 .apply_aoe_from_data(data)
902 .on_cast(crate::hooks::fury_warrior::execute_hook),
903 )
904}
905fn spell_whirlwind(
906 s: SpellDefinitionDraft,
907 data: &ResolvedGameData,
908) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
909 Ok(
910 s
911 .apply_base_from_data(data, 190_411)?
912 .applies_aura(AURA_WHIRLWIND)
913 .apply_aoe_from_data(data)
914 .on_cast(crate::hooks::fury_warrior::whirlwind_hook),
915 )
916}
917fn spell_recklessness(
918 s: SpellDefinitionDraft,
919 data: &ResolvedGameData,
920) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
921 Ok(
922 s
923 .apply_base_from_data(data, 1719)?
924 .applies_inferred_aura(AURA_RECKLESSNESS, 1719)
925 .apply_aoe_from_data(data),
926 )
927}
928fn spell_avatar(
929 s: SpellDefinitionDraft,
930 data: &ResolvedGameData,
931) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
932 Ok(
933 s
934 .apply_base_from_data(data, 107_574)?
935 .applies_inferred_aura(AURA_AVATAR, 107_574)
936 .apply_aoe_from_data(data),
937 )
938}
939fn spell_bloodbath(
940 s: SpellDefinitionDraft,
941 data: &ResolvedGameData,
942) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
943 Ok(
944 s
945 .apply_base_from_data(data, 335_096)?
946 .apply_aoe_from_data(data)
947 .on_cast(crate::hooks::fury_warrior::bloodbath_hook),
948 )
949}
950fn spell_crushing_blow(
951 s: SpellDefinitionDraft,
952 data: &ResolvedGameData,
953) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
954 Ok(
955 s
956 .apply_base_from_data(data, 335_097)?
957 .without_primary_data_damage()
958 .apply_aoe_from_data(data)
959 .on_cast(crate::hooks::fury_warrior::crushing_blow_hook),
960 )
961}
962fn spell_thunder_clap(
963 s: SpellDefinitionDraft,
964 data: &ResolvedGameData,
965) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
966 Ok(
967 s
968 .apply_base_from_data(data, 6343)?
969 .gain(5.0)
970 .apply_aoe_from_data(data)
971 .on_cast(crate::hooks::fury_warrior::thunder_clap_hook),
972 )
973}
974fn spell_rend(
975 s: SpellDefinitionDraft,
976 data: &ResolvedGameData,
977) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
978 Ok(
979 s
980 .apply_base_from_data(data, 772)?
981 .applies_aura(AURA_REND)
982 .apply_aoe_from_data(data)
983 .on_cast(crate::hooks::fury_warrior::rend_hook),
984 )
985}
986fn spell_battle_shout(
987 s: SpellDefinitionDraft,
988 data: &ResolvedGameData,
989) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
990 Ok(
991 s
992 .apply_base_from_data(data, 6673)?
993 .applies_inferred_aura(AURA_BATTLE_SHOUT, 6673)
994 .apply_aoe_from_data(data),
995 )
996}
997fn spell_slam(
998 s: SpellDefinitionDraft,
999 data: &ResolvedGameData,
1000) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1001 Ok(
1002 s
1003 .apply_base_from_data(data, 1464)?
1004 .apply_aoe_from_data(data)
1005 .on_cast(crate::hooks::fury_warrior::slam_hook),
1006 )
1007}
1008fn spell_heroic_throw(
1009 s: SpellDefinitionDraft,
1010 data: &ResolvedGameData,
1011) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1012 Ok(s.apply_base_from_data(data, 57755)?.apply_aoe_from_data(data))
1013}
1014fn spell_bladestorm(
1015 s: SpellDefinitionDraft,
1016 data: &ResolvedGameData,
1017) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1018 Ok(
1019 s
1020 .apply_base_from_data(data, 227_847)?
1021 .applies_inferred_aura(AURA_BLADESTORM, 227_847)
1022 .apply_aoe_from_data(data)
1023 .on_cast(crate::hooks::fury_warrior::bladestorm_hook),
1024 )
1025}
1026fn spell_odyns_fury(
1027 s: SpellDefinitionDraft,
1028 data: &ResolvedGameData,
1029) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1030 Ok(
1031 s
1032 .apply_base_from_data(data, 385_059)?
1033 .without_primary_data_damage()
1034 .applies_aura(AURA_ENRAGE)
1035 .apply_aoe_from_data(data)
1036 .on_cast(crate::hooks::fury_warrior::odyns_fury_hook),
1037 )
1038}
1039fn spell_ravager(
1040 s: SpellDefinitionDraft,
1041 data: &ResolvedGameData,
1042) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1043 Ok(
1044 s
1045 .apply_base_from_data(data, 228_920)?
1046 .applies_inferred_aura(AURA_RAVAGER, 228_920)
1047 .apply_aoe_from_data(data),
1048 )
1049}
1050fn spell_slayers_strike(
1051 s: SpellDefinitionDraft,
1052 data: &ResolvedGameData,
1053) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1054 Ok(s.apply_base_from_data(data, 445_579)?.apply_aoe_from_data(data))
1055}
1056fn spell_reap_the_storm_execute(
1057 s: SpellDefinitionDraft,
1058 data: &ResolvedGameData,
1059) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1060 Ok(s.apply_base_from_data(data, 446_005)?.apply_aoe_from_data(data))
1061}
1062pub(crate) fn build_combat_system(
1063 params: &wowlab_engine_ports::HandlerParams<'_>,
1064) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1065 let builder = BuiltCombatSystem::builder(params.stats.clone())
1066 .spec_id(SpecId::Fury)
1067 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1068 .mastery_spell(76856)
1069 .mastery_hook(crate::hooks::fury_warrior::mastery)
1070 .resource(
1071 "rage",
1072 params
1073 .game_data
1074 .power_max(1)
1075 .ok_or_else(|| {
1076 wowlab_engine_ports::EngineError::spec_construction(
1077 "missing power-type power_max for type_id 1",
1078 )
1079 })?,
1080 params
1081 .game_data
1082 .power_regen_for_max(
1083 1,
1084 params
1085 .game_data
1086 .power_max(1)
1087 .ok_or_else(|| {
1088 wowlab_engine_ports::EngineError::spec_construction(
1089 "missing power-type power_max for type_id 1",
1090 )
1091 })?,
1092 )
1093 .ok_or_else(|| {
1094 wowlab_engine_ports::EngineError::spec_construction(
1095 "missing power-type power_regen_for_max for type_id 1",
1096 )
1097 })?,
1098 )
1099 .resource_type_id(1)
1100 .resource_start(
1101 params
1102 .game_data
1103 .power_default(1)
1104 .ok_or_else(|| {
1105 wowlab_engine_ports::EngineError::spec_construction(
1106 "missing power-type power_default for type_id 1",
1107 )
1108 })?,
1109 )
1110 .aura("enrage", AURA::ENRAGE, |a| aura_enrage(a, ¶ms.game_data))
1111 .aura(
1112 "recklessness",
1113 AURA::RECKLESSNESS,
1114 |a| aura_recklessness(a, ¶ms.game_data),
1115 )
1116 .aura("whirlwind", AURA::WHIRLWIND, |a| aura_whirlwind(a, ¶ms.game_data))
1117 .aura("avatar", AURA::AVATAR, |a| aura_avatar(a, ¶ms.game_data))
1118 .aura("frenzy", AURA::FRENZY, |a| aura_frenzy(a, ¶ms.game_data))
1119 .aura(
1120 "sudden_death",
1121 AURA::SUDDEN_DEATH,
1122 |a| aura_sudden_death(a, ¶ms.game_data),
1123 )
1124 .aura("rend", AURA::REND, |a| aura_rend(a, ¶ms.game_data))
1125 .aura(
1126 "bloodbath_dot",
1127 AURA::BLOODBATH_DOT,
1128 |a| aura_bloodbath_dot(a, ¶ms.game_data),
1129 )
1130 .aura(
1131 "gushing_wound",
1132 AURA::GUSHING_WOUND,
1133 |a| aura_gushing_wound(a, ¶ms.game_data),
1134 )
1135 .aura(
1136 "battle_shout",
1137 AURA::BATTLE_SHOUT,
1138 |a| aura_battle_shout(a, ¶ms.game_data),
1139 )
1140 .aura(
1141 "battle_shout_highlight",
1142 AURA::BATTLE_SHOUT_HIGHLIGHT,
1143 |a| aura_battle_shout_highlight(a, ¶ms.game_data),
1144 )
1145 .aura("rampage", AURA::RAMPAGE, |a| aura_rampage(a, ¶ms.game_data))
1146 .aura(
1147 "deep_wounds",
1148 AURA::DEEP_WOUNDS,
1149 |a| aura_deep_wounds(a, ¶ms.game_data),
1150 )
1151 .aura(
1152 "wild_strikes",
1153 AURA::WILD_STRIKES,
1154 |a| aura_wild_strikes(a, ¶ms.game_data),
1155 )
1156 .aura(
1157 "surge_of_adrenaline",
1158 AURA::SURGE_OF_ADRENALINE,
1159 |a| aura_surge_of_adrenaline(a, ¶ms.game_data),
1160 )
1161 .aura("bloodborne", AURA::BLOODBORNE, |a| aura_bloodborne(a, ¶ms.game_data))
1162 .aura(
1163 "berserker_stance",
1164 AURA::BERSERKER_STANCE,
1165 |a| aura_berserker_stance(a, ¶ms.game_data),
1166 )
1167 .aura("bladestorm", AURA::BLADESTORM, |a| aura_bladestorm(a, ¶ms.game_data))
1168 .aura(
1169 "odyns_fury_dot",
1170 AURA::ODYNS_FURY_DOT,
1171 |a| aura_odyns_fury_dot(a, ¶ms.game_data),
1172 )
1173 .aura("ravager", AURA::RAVAGER, |a| aura_ravager(a, ¶ms.game_data))
1174 .aura(
1175 "executioner",
1176 AURA::EXECUTIONER,
1177 |a| aura_executioner(a, ¶ms.game_data),
1178 )
1179 .aura(
1180 "overwhelmed",
1181 AURA::OVERWHELMED,
1182 |a| aura_overwhelmed(a, ¶ms.game_data),
1183 )
1184 .aura(
1185 "imminent_demise",
1186 AURA::IMMINENT_DEMISE,
1187 |a| aura_imminent_demise(a, ¶ms.game_data),
1188 )
1189 .aura(
1190 "executioners_wrath",
1191 AURA::EXECUTIONERS_WRATH,
1192 |a| aura_executioners_wrath(a, ¶ms.game_data),
1193 )
1194 .aura(
1195 "thunder_blast",
1196 AURA::THUNDER_BLAST,
1197 |a| aura_thunder_blast(a, ¶ms.game_data),
1198 )
1199 .aura(
1200 "crashing_thunder",
1201 AURA::CRASHING_THUNDER,
1202 |a| aura_crashing_thunder(a, ¶ms.game_data),
1203 )
1204 .spell(
1205 "bloodthirst",
1206 SPELL::BLOODTHIRST,
1207 |s| spell_bloodthirst(s, ¶ms.game_data),
1208 )
1209 .spell(
1210 "raging_blow",
1211 SPELL::RAGING_BLOW,
1212 |s| spell_raging_blow(s, ¶ms.game_data),
1213 )
1214 .spell("rampage", SPELL::RAMPAGE, |s| spell_rampage(s, ¶ms.game_data))
1215 .spell("execute", SPELL::EXECUTE, |s| spell_execute(s, ¶ms.game_data))
1216 .spell("whirlwind", SPELL::WHIRLWIND, |s| spell_whirlwind(s, ¶ms.game_data))
1217 .spell(
1218 "recklessness",
1219 SPELL::RECKLESSNESS,
1220 |s| spell_recklessness(s, ¶ms.game_data),
1221 )
1222 .spell("avatar", SPELL::AVATAR, |s| spell_avatar(s, ¶ms.game_data))
1223 .spell("bloodbath", SPELL::BLOODBATH, |s| spell_bloodbath(s, ¶ms.game_data))
1224 .spell(
1225 "crushing_blow",
1226 SPELL::CRUSHING_BLOW,
1227 |s| spell_crushing_blow(s, ¶ms.game_data),
1228 )
1229 .spell(
1230 "thunder_clap",
1231 SPELL::THUNDER_CLAP,
1232 |s| spell_thunder_clap(s, ¶ms.game_data),
1233 )
1234 .spell("rend", SPELL::REND, |s| spell_rend(s, ¶ms.game_data))
1235 .spell(
1236 "battle_shout",
1237 SPELL::BATTLE_SHOUT,
1238 |s| spell_battle_shout(s, ¶ms.game_data),
1239 )
1240 .spell("slam", SPELL::SLAM, |s| spell_slam(s, ¶ms.game_data))
1241 .spell(
1242 "heroic_throw",
1243 SPELL::HEROIC_THROW,
1244 |s| spell_heroic_throw(s, ¶ms.game_data),
1245 )
1246 .spell(
1247 "bladestorm",
1248 SPELL::BLADESTORM,
1249 |s| spell_bladestorm(s, ¶ms.game_data),
1250 )
1251 .spell(
1252 "odyns_fury",
1253 SPELL::ODYNS_FURY,
1254 |s| spell_odyns_fury(s, ¶ms.game_data),
1255 )
1256 .spell("ravager", SPELL::RAVAGER, |s| spell_ravager(s, ¶ms.game_data))
1257 .spell(
1258 "slayers_strike",
1259 SPELL::SLAYERS_STRIKE,
1260 |s| spell_slayers_strike(s, ¶ms.game_data),
1261 )
1262 .spell(
1263 "reap_the_storm_execute",
1264 SPELL::REAP_THE_STORM_EXECUTE,
1265 |s| spell_reap_the_storm_execute(s, ¶ms.game_data),
1266 )
1267 .auto_attack(|a| {
1268 a
1269 .spell_id(6603)
1270 .swing_ms(3600)
1271 .apply_base_from_data(¶ms.game_data)
1272 .on_swing(crate::hooks::fury_warrior::swing_hook)
1273 })
1274 .auto_attack(|a| {
1275 a
1276 .spell_id(6603)
1277 .swing_ms(3600)
1278 .apply_base_from_data(¶ms.game_data)
1279 .on_swing(crate::hooks::fury_warrior::swing_hook)
1280 })
1281 .game_data(params.game_data.clone())
1282 .talent_spell_ids(TALENTS)
1283 .talent_selections(params.talent_selections)
1284 .set_bonus_auras(params.set_bonus_auras)
1285 .encounter(params.encounter.clone());
1286 let builder = crate::generated::items::register_equipped(
1287 builder,
1288 ¶ms.game_data,
1289 params.equipped_items,
1290 )?;
1291
1292 builder
1293 .build(params.rotation)
1294 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1295}
1296fn new_handler(
1297 params: wowlab_engine_ports::HandlerParams<'_>,
1298) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1299 let handler = crate::composition::compose_handler(
1300 build_combat_system,
1301 ¶ms,
1302 crate::hooks::fury_warrior::FuryHandler::try_new,
1303 )?;
1304
1305 Ok(Box::new(handler))
1306}
1307static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1308 primary_resource: ResourceType::Rage,
1309 secondary_resource: None,
1310 spell_ids: DECLARED_SPELL_IDS,
1311 aura_ids: DECLARED_AURA_IDS,
1312 server_proc_entries: &[
1313 DeclaredServerProcEntry {
1314 spell_id: 85739,
1315 attributes: ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1316 },
1317 DeclaredServerProcEntry {
1318 spell_id: 52437,
1319 attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
1320 | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1321 },
1322 DeclaredServerProcEntry {
1323 spell_id: 435_615,
1324 attributes: ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1325 },
1326 ],
1327 talents: TALENTS,
1328 rotation_field_schema: &[],
1329 metrics_plugin_id: None,
1330 hero_talent_trees: &[
1331 HeroTalentTreeDesc {
1332 name: "Slayer",
1333 spells: HERO_TREE_SLAYER_SPELLS,
1334 auras: HERO_TREE_SLAYER_AURAS,
1335 },
1336 HeroTalentTreeDesc {
1337 name: "Mountain Thane",
1338 spells: HERO_TREE_MOUNTAIN_THANE_SPELLS,
1339 auras: HERO_TREE_MOUNTAIN_THANE_AURAS,
1340 },
1341 ],
1342 reported_spells: REPORTED_SPELLS,
1343 masked_passive_effects: &[],
1344 passive_effect_overrides: &[],
1345};
1346pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1347 spec_id: SpecId::Fury,
1348 display_name: "Fury Warrior",
1349 metadata: DECLARED_METADATA,
1350 handler_factory: new_handler,
1351};
1352wowlab_engine_combat::smoke_test!(build_combat_system);