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 THISTLE_TEA: u32 = 381_623;
16 pub(crate) const VANISH: u32 = 1856;
18 pub(crate) const SINISTER_STRIKE: u32 = 193_315;
20 pub(crate) const SINISTER_STRIKE_EXTRA_ATTACK: u32 = 197_834;
22 pub(crate) const PISTOL_SHOT: u32 = 185_763;
24 pub(crate) const AMBUSH: u32 = 8676;
26 pub(crate) const DISPATCH: u32 = 2098;
28 pub(crate) const BETWEEN_THE_EYES: u32 = 315_341;
30 pub(crate) const EVISCERATE: u32 = 196_819;
32 pub(crate) const SLICE_AND_DICE: u32 = 315_496;
34 pub(crate) const INSTANT_POISON: u32 = 315_584;
36 pub(crate) const WOUND_POISON: u32 = 8679;
38 pub(crate) const ATROPHIC_POISON: u32 = 381_637;
40 pub(crate) const NUMBING_POISON: u32 = 5761;
42 pub(crate) const CRIPPLING_POISON: u32 = 3408;
44 pub(crate) const MAIN_GAUCHE: u32 = 86392;
46 pub(crate) const SCOUNDREL_STRIKE: u32 = 1_265_918;
48 pub(crate) const INSTANT_POISON_DAMAGE: u32 = 315_585;
50 pub(crate) const KICK: u32 = 1766;
52 pub(crate) const ROLL_THE_BONES: u32 = 315_508;
54 pub(crate) const ADRENALINE_RUSH: u32 = 13750;
56 pub(crate) const BLADE_FLURRY: u32 = 13877;
58 pub(crate) const BLADE_FLURRY_INSTANT_ATTACK: u32 = 429_951;
60 pub(crate) const BLADE_RUSH: u32 = 271_877;
62 pub(crate) const KILLING_SPREE: u32 = 51690;
64 pub(crate) const KEEP_IT_ROLLING: u32 = 381_989;
66 pub(crate) const PREPARATION: u32 = 1_277_933;
68 pub(crate) const BLADE_RUSH_ATTACK: u32 = 271_881;
70}
71pub(crate) mod AURA {
72 pub(crate) const SLICE_AND_DICE: u32 = 315_496;
74 pub(crate) const OPPORTUNITY: u32 = 195_627;
76 pub(crate) const AUDACITY: u32 = 386_270;
78 pub(crate) const BETWEEN_THE_EYES: u32 = 315_341;
80 pub(crate) const STEALTH: u32 = 1784;
82 pub(crate) const VANISH: u32 = 1856;
84 pub(crate) const SUBTERFUGE: u32 = 115_192;
86 pub(crate) const HIDDEN_OPPORTUNITY: u32 = 383_281;
88 pub(crate) const DEFT_MANEUVERS: u32 = 381_878;
90 pub(crate) const VIGOR: u32 = 14983;
92 pub(crate) const ONE_OF_A_KIND: u32 = 1_214_933;
94 pub(crate) const DOUBLE_TROUBLE: u32 = 1_214_934;
96 pub(crate) const TRIPLE_THREAT: u32 = 1_214_935;
98 pub(crate) const JACKPOT: u32 = 1_214_937;
100 pub(crate) const LOADED_DICE: u32 = 256_171;
102 pub(crate) const ADRENALINE_RUSH: u32 = 13750;
104 pub(crate) const BLADE_FLURRY: u32 = 13877;
106 pub(crate) const INSTANT_POISON: u32 = 315_584;
108 pub(crate) const WOUND_POISON: u32 = 8679;
110 pub(crate) const ATROPHIC_POISON: u32 = 381_637;
112 pub(crate) const NUMBING_POISON: u32 = 5761;
114 pub(crate) const CRIPPLING_POISON: u32 = 3408;
116 pub(crate) const IMPROVED_ADRENALINE_RUSH: u32 = 395_422;
118 pub(crate) const BLADE_RUSH_ENERGIZE: u32 = 271_896;
120 pub(crate) const PALMED_BULLETS: u32 = 1_265_931;
122 pub(crate) const GRAVEDIGGER: u32 = 1_265_935;
124 pub(crate) const DEADLY_PURSUIT_WAIT: u32 = 1_259_613;
126 pub(crate) const DEADLY_PURSUIT_CDR: u32 = 1_259_614;
128 pub(crate) const PVP_RULES_ENABLED_HARDCODED: u32 = 134_735;
130 pub(crate) const FATEBOUND_COIN_HEADS: u32 = 452_923;
132 pub(crate) const FATEBOUND_COIN_TAILS: u32 = 452_917;
134 pub(crate) const FATEBOUND_LUCKY_COIN: u32 = 1_248_971;
136 pub(crate) const LUCKY_COIN_COUNTER: u32 = 1_249_093;
138}
139pub(crate) mod TALENT {
140 pub(crate) const ACE_UP_YOUR_SLEEVE: u32 = 381_828;
142 pub(crate) const ADRENALINE_RUSH: u32 = 13750;
144 pub(crate) const AUDACITY: u32 = 386_270;
146 pub(crate) const BLADE_FLURRY: u32 = 13877;
148 pub(crate) const BLADE_RUSH: u32 = 271_877;
150 pub(crate) const DEADLY_PURSUIT: u32 = 1_259_612;
152 pub(crate) const DEFT_MANEUVERS: u32 = 381_878;
154 pub(crate) const DEVIOUS_STRATAGEM: u32 = 394_321;
156 pub(crate) const FAN_THE_HAMMER: u32 = 381_846;
158 pub(crate) const FATAL_FLOURISH: u32 = 35551;
160 pub(crate) const GRAVEDIGGER_1: u32 = 1_265_861;
162 pub(crate) const GRAVEDIGGER_2: u32 = 1_265_862;
164 pub(crate) const GRAVEDIGGER_3: u32 = 1_265_863;
166 pub(crate) const HIDDEN_OPPORTUNITY: u32 = 383_281;
168 pub(crate) const IMPROVED_ADRENALINE_RUSH: u32 = 395_422;
170 pub(crate) const KEEP_IT_ROLLING: u32 = 381_989;
172 pub(crate) const KILLING_SPREE: u32 = 51690;
174 pub(crate) const LOADED_DICE: u32 = 256_170;
176 pub(crate) const MENACING_RUSH: u32 = 1_256_630;
178 pub(crate) const OPPORTUNITY: u32 = 279_876;
180 pub(crate) const PREPARATION: u32 = 1_277_933;
182 pub(crate) const QUICK_DRAW: u32 = 196_938;
184 pub(crate) const RESTLESS_BLADES: u32 = 79096;
186 pub(crate) const RUTHLESSNESS: u32 = 14161;
188 pub(crate) const SLEIGHT_OF_HAND: u32 = 381_839;
190 pub(crate) const SUMMARILY_DISPATCHED: u32 = 381_990;
192 pub(crate) const THISTLE_TEA: u32 = 469_779;
194 pub(crate) const ZERO_IN: u32 = 1_259_485;
196}
197pub(crate) mod REPORTED_SPELL {
198 pub(crate) const BLADE_RUSH_ATTACK: u32 = 271_881;
200 pub(crate) const FATEBOUND_COIN_TAILS: u32 = 452_538;
202 pub(crate) const INSTANT_POISON_DAMAGE: u32 = 315_585;
204 pub(crate) const KILLING_SPREE_MH: u32 = 57841;
206 pub(crate) const KILLING_SPREE_OH: u32 = 57842;
208 pub(crate) const MAIN_GAUCHE: u32 = 86392;
210 pub(crate) const SCOUNDREL_STRIKE: u32 = 1_265_918;
212 pub(crate) const SINISTER_STRIKE_EXTRA_ATTACK: u32 = 197_834;
214}
215pub(crate) mod HERO {
216 pub(crate) mod FATEBOUND {
217 pub(crate) mod SPELL {
218 pub(crate) const CONTROLLED_CHAOS: u32 = 1_276_816;
220 pub(crate) const DEAL_FATE: u32 = 454_419;
222 pub(crate) const DELIVERED_DOOM: u32 = 1_249_194;
224 pub(crate) const DESTINY_DEFINED: u32 = 454_435;
226 pub(crate) const EDGE_CASE: u32 = 453_457;
228 pub(crate) const FATEBOUND_COIN_TAILS: u32 = 452_538;
230 pub(crate) const HAND_OF_FATE: u32 = 452_536;
232 pub(crate) const LUCKY_COIN: u32 = 1_248_970;
234 pub(crate) const MEAN_STREAK: u32 = 453_428;
236 pub(crate) const RAVENHOLDT_MINT: u32 = 1_276_809;
238 pub(crate) const RUSH_TO_THE_INEVITABLE: u32 = 1_249_204;
240 }
241 pub(crate) mod AURA {
242 pub(crate) const FATEBOUND_COIN_HEADS: u32 = 452_923;
244 pub(crate) const FATEBOUND_COIN_TAILS: u32 = 452_917;
246 pub(crate) const FATEBOUND_LUCKY_COIN: u32 = 1_248_971;
248 }
249 }
250 pub(crate) mod TRICKSTER {
251 pub(crate) mod SPELL {
252 pub(crate) const COUP_DE_GRACE: u32 = 441_519;
254 pub(crate) const COUP_DE_GRACE_DAMAGE_1: u32 = 462_127;
256 pub(crate) const COUP_DE_GRACE_DAMAGE_2: u32 = 462_128;
258 pub(crate) const COUP_DE_GRACE_DAMAGE_3: u32 = 462_129;
260 pub(crate) const UNSEEN_BLADE: u32 = 459_485;
262 }
263 pub(crate) mod AURA {
264 pub(crate) const DISORIENTING_STRIKES: u32 = 441_274;
266 pub(crate) const ESCALATING_BLADE: u32 = 441_786;
268 pub(crate) const FAZED: u32 = 441_224;
270 pub(crate) const FLAWLESS_FORM: u32 = 441_326;
272 pub(crate) const UNSEEN_BLADE_CD: u32 = 459_485;
274 }
275 }
276}
277static HERO_TREE_FATEBOUND_SPELLS: &[(&str, u32)] = &[
278 ("CONTROLLED_CHAOS", 1_276_816),
279 ("DEAL_FATE", 454_419),
280 ("DELIVERED_DOOM", 1_249_194),
281 ("DESTINY_DEFINED", 454_435),
282 ("EDGE_CASE", 453_457),
283 ("FATEBOUND_COIN_TAILS", 452_538),
284 ("HAND_OF_FATE", 452_536),
285 ("LUCKY_COIN", 1_248_970),
286 ("MEAN_STREAK", 453_428),
287 ("RAVENHOLDT_MINT", 1_276_809),
288 ("RUSH_TO_THE_INEVITABLE", 1_249_204),
289];
290static HERO_TREE_FATEBOUND_AURAS: &[(&str, u32)] = &[
291 ("FATEBOUND_COIN_HEADS", 452_923),
292 ("FATEBOUND_COIN_TAILS", 452_917),
293 ("FATEBOUND_LUCKY_COIN", 1_248_971),
294];
295static HERO_TREE_TRICKSTER_SPELLS: &[(&str, u32)] = &[
296 ("COUP_DE_GRACE", 441_519),
297 ("COUP_DE_GRACE_DAMAGE_1", 462_127),
298 ("COUP_DE_GRACE_DAMAGE_2", 462_128),
299 ("COUP_DE_GRACE_DAMAGE_3", 462_129),
300 ("UNSEEN_BLADE", 459_485),
301];
302static HERO_TREE_TRICKSTER_AURAS: &[(&str, u32)] = &[
303 ("DISORIENTING_STRIKES", 441_274),
304 ("ESCALATING_BLADE", 441_786),
305 ("FAZED", 441_224),
306 ("FLAWLESS_FORM", 441_326),
307 ("UNSEEN_BLADE_CD", 459_485),
308];
309pub(crate) const AURA_SLICE_AND_DICE: LocalAuraIdx = LocalAuraIdx::new(0);
310pub(crate) const AURA_OPPORTUNITY: LocalAuraIdx = LocalAuraIdx::new(1);
311pub(crate) const AURA_AUDACITY: LocalAuraIdx = LocalAuraIdx::new(2);
312pub(crate) const AURA_BETWEEN_THE_EYES: LocalAuraIdx = LocalAuraIdx::new(3);
313pub(crate) const AURA_STEALTH: LocalAuraIdx = LocalAuraIdx::new(4);
314pub(crate) const AURA_VANISH: LocalAuraIdx = LocalAuraIdx::new(5);
315pub(crate) const AURA_SUBTERFUGE: LocalAuraIdx = LocalAuraIdx::new(6);
316pub(crate) const AURA_HIDDEN_OPPORTUNITY: LocalAuraIdx = LocalAuraIdx::new(7);
317pub(crate) const AURA_DEFT_MANEUVERS: LocalAuraIdx = LocalAuraIdx::new(8);
318pub(crate) const AURA_VIGOR: LocalAuraIdx = LocalAuraIdx::new(9);
319pub(crate) const AURA_ONE_OF_A_KIND: LocalAuraIdx = LocalAuraIdx::new(10);
320pub(crate) const AURA_DOUBLE_TROUBLE: LocalAuraIdx = LocalAuraIdx::new(11);
321pub(crate) const AURA_TRIPLE_THREAT: LocalAuraIdx = LocalAuraIdx::new(12);
322pub(crate) const AURA_JACKPOT: LocalAuraIdx = LocalAuraIdx::new(13);
323pub(crate) const AURA_LOADED_DICE: LocalAuraIdx = LocalAuraIdx::new(14);
324pub(crate) const AURA_ADRENALINE_RUSH: LocalAuraIdx = LocalAuraIdx::new(15);
325pub(crate) const AURA_BLADE_FLURRY: LocalAuraIdx = LocalAuraIdx::new(16);
326pub(crate) const AURA_INSTANT_POISON: LocalAuraIdx = LocalAuraIdx::new(17);
327pub(crate) const AURA_WOUND_POISON: LocalAuraIdx = LocalAuraIdx::new(18);
328pub(crate) const AURA_ATROPHIC_POISON: LocalAuraIdx = LocalAuraIdx::new(19);
329pub(crate) const AURA_NUMBING_POISON: LocalAuraIdx = LocalAuraIdx::new(20);
330pub(crate) const AURA_CRIPPLING_POISON: LocalAuraIdx = LocalAuraIdx::new(21);
331pub(crate) const AURA_IMPROVED_ADRENALINE_RUSH: LocalAuraIdx = LocalAuraIdx::new(22);
332pub(crate) const AURA_BLADE_RUSH_ENERGIZE: LocalAuraIdx = LocalAuraIdx::new(23);
333pub(crate) const AURA_PALMED_BULLETS: LocalAuraIdx = LocalAuraIdx::new(24);
334pub(crate) const AURA_GRAVEDIGGER: LocalAuraIdx = LocalAuraIdx::new(25);
335pub(crate) const AURA_DEADLY_PURSUIT_WAIT: LocalAuraIdx = LocalAuraIdx::new(26);
336pub(crate) const AURA_DEADLY_PURSUIT_CDR: LocalAuraIdx = LocalAuraIdx::new(27);
337pub(crate) const AURA_PVP_RULES_ENABLED_HARDCODED: LocalAuraIdx = LocalAuraIdx::new(28);
338pub(crate) const AURA_FATEBOUND_COIN_HEADS: LocalAuraIdx = LocalAuraIdx::new(29);
339pub(crate) const AURA_FATEBOUND_COIN_TAILS: LocalAuraIdx = LocalAuraIdx::new(30);
340pub(crate) const AURA_FATEBOUND_LUCKY_COIN: LocalAuraIdx = LocalAuraIdx::new(31);
341pub(crate) const AURA_LUCKY_COIN_COUNTER: LocalAuraIdx = LocalAuraIdx::new(32);
342pub(crate) const AURA_COUNT: usize = 33;
343const _: () = assert!(
344 AURA_COUNT == 33, "AURA index ABI: count changed -- update positional hook consumers"
345);
346pub(crate) const SPELL_THISTLE_TEA: LocalSpellIdx = LocalSpellIdx::new(0);
347pub(crate) const SPELL_VANISH: LocalSpellIdx = LocalSpellIdx::new(1);
348pub(crate) const SPELL_SINISTER_STRIKE: LocalSpellIdx = LocalSpellIdx::new(2);
349pub(crate) const SPELL_SINISTER_STRIKE_EXTRA_ATTACK: LocalSpellIdx = LocalSpellIdx::new(
350 3,
351);
352pub(crate) const SPELL_PISTOL_SHOT: LocalSpellIdx = LocalSpellIdx::new(4);
353pub(crate) const SPELL_AMBUSH: LocalSpellIdx = LocalSpellIdx::new(5);
354pub(crate) const SPELL_DISPATCH: LocalSpellIdx = LocalSpellIdx::new(6);
355pub(crate) const SPELL_BETWEEN_THE_EYES: LocalSpellIdx = LocalSpellIdx::new(7);
356pub(crate) const SPELL_EVISCERATE: LocalSpellIdx = LocalSpellIdx::new(8);
357pub(crate) const SPELL_SLICE_AND_DICE: LocalSpellIdx = LocalSpellIdx::new(9);
358pub(crate) const SPELL_INSTANT_POISON: LocalSpellIdx = LocalSpellIdx::new(10);
359pub(crate) const SPELL_WOUND_POISON: LocalSpellIdx = LocalSpellIdx::new(11);
360pub(crate) const SPELL_ATROPHIC_POISON: LocalSpellIdx = LocalSpellIdx::new(12);
361pub(crate) const SPELL_NUMBING_POISON: LocalSpellIdx = LocalSpellIdx::new(13);
362pub(crate) const SPELL_CRIPPLING_POISON: LocalSpellIdx = LocalSpellIdx::new(14);
363pub(crate) const SPELL_MAIN_GAUCHE: LocalSpellIdx = LocalSpellIdx::new(15);
364pub(crate) const SPELL_SCOUNDREL_STRIKE: LocalSpellIdx = LocalSpellIdx::new(16);
365pub(crate) const SPELL_INSTANT_POISON_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(17);
366pub(crate) const SPELL_KICK: LocalSpellIdx = LocalSpellIdx::new(18);
367pub(crate) const SPELL_ROLL_THE_BONES: LocalSpellIdx = LocalSpellIdx::new(19);
368pub(crate) const SPELL_ADRENALINE_RUSH: LocalSpellIdx = LocalSpellIdx::new(20);
369pub(crate) const SPELL_BLADE_FLURRY: LocalSpellIdx = LocalSpellIdx::new(21);
370pub(crate) const SPELL_BLADE_FLURRY_INSTANT_ATTACK: LocalSpellIdx = LocalSpellIdx::new(
371 22,
372);
373pub(crate) const SPELL_BLADE_RUSH: LocalSpellIdx = LocalSpellIdx::new(23);
374pub(crate) const SPELL_KILLING_SPREE: LocalSpellIdx = LocalSpellIdx::new(24);
375pub(crate) const SPELL_KEEP_IT_ROLLING: LocalSpellIdx = LocalSpellIdx::new(25);
376pub(crate) const SPELL_PREPARATION: LocalSpellIdx = LocalSpellIdx::new(26);
377pub(crate) const SPELL_BLADE_RUSH_ATTACK: LocalSpellIdx = LocalSpellIdx::new(27);
378pub(crate) const SPELL_COUNT: usize = 28;
379const _: () = assert!(
380 SPELL_COUNT == 28,
381 "SPELL index ABI: count changed -- update positional hook consumers"
382);
383pub(crate) mod EFFECT {
384 pub(crate) const ACE_UP_CHANCE: (u32, u8) = (381_828, 1);
386 pub(crate) const ACE_UP_ENERGIZE: (u32, u8) = (394_120, 1);
388 pub(crate) const BLADE_FLURRY_CLEAVE: (u32, u8) = (13877, 2);
390 pub(crate) const BLADE_FLURRY_DAMAGE: (u32, u8) = (22482, 1);
392 pub(crate) const BLADE_FLURRY_TARGETS: (u32, u8) = (13877, 3);
394 pub(crate) const BLADE_RUSH_ATTACK_DAMAGE: (u32, u8) = (271_881, 1);
396 pub(crate) const COIN_HEADS_INITIAL: (u32, u8) = (452_923, 4);
398 pub(crate) const BETWEEN_THE_EYES_SUMMARILY_DISPATCHED: (u32, u8) = (315_341, 4);
400 pub(crate) const COIN_HEADS_PER_STACK: (u32, u8) = (452_923, 1);
402 pub(crate) const COIN_HEADS_PER_STACK_PERIODIC: (u32, u8) = (452_923, 2);
404 pub(crate) const DEAL_FATE_CP: (u32, u8) = (454_419, 1);
406 pub(crate) const DELIVERED_DOOM_DMG: (u32, u8) = (1_249_194, 1);
408 pub(crate) const DELIVERED_DOOM_CP: (u32, u8) = (1_249_194, 2);
410 pub(crate) const DESTINY_DEFINED_ODDS: (u32, u8) = (454_435, 3);
412 pub(crate) const FAN_THE_HAMMER_EXTRA: (u32, u8) = (381_846, 1);
414 pub(crate) const FAN_THE_HAMMER_REDUCTION: (u32, u8) = (381_846, 3);
416 pub(crate) const FATEBOUND_COIN_TAILS_DAMAGE: (u32, u8) = (452_538, 1);
418 pub(crate) const GRAVEDIGGER_ENERGIZE: (u32, u8) = (1_279_356, 1);
420 pub(crate) const HAND_OF_FATE_CP: (u32, u8) = (452_536, 1);
422 pub(crate) const HIDDEN_OPPORTUNITY_DAMAGE: (u32, u8) = (383_281, 1);
424 pub(crate) const INSTANT_POISON_DAMAGE: (u32, u8) = (315_585, 1);
426 pub(crate) const JACKPOT_RB: (u32, u8) = (1_214_937, 4);
428 pub(crate) const KILLING_SPREE_MH_DAMAGE: (u32, u8) = (57841, 1);
430 pub(crate) const KILLING_SPREE_OH_DAMAGE: (u32, u8) = (57842, 1);
432 pub(crate) const LUCKY_COIN_FLIPS: (u32, u8) = (1_248_970, 1);
434 pub(crate) const LUCKY_COIN_ODDS: (u32, u8) = (1_248_971, 5);
436 pub(crate) const MAIN_GAUCHE_DAMAGE: (u32, u8) = (86392, 1);
438 pub(crate) const MAIN_GAUCHE_MASTERY_COEF: (u32, u8) = (76806, 2);
440 pub(crate) const MEAN_STREAK_ODDS: (u32, u8) = (453_428, 1);
442 pub(crate) const PALMED_BULLETS_CHANCE: (u32, u8) = (1_265_863, 1);
444 pub(crate) const PISTOL_SHOT_DAMAGE: (u32, u8) = (185_763, 1);
446 pub(crate) const QUICK_DRAW_ENERGIZE: (u32, u8) = (1_254_567, 1);
448 pub(crate) const RAVENHOLDT_MINT_HEADS: (u32, u8) = (1_276_809, 1);
450 pub(crate) const RESTLESS_BLADES_CDR: (u32, u8) = (79096, 1);
452 pub(crate) const RUTHLESSNESS_CP: (u32, u8) = (14161, 1);
454 pub(crate) const SUMMARILY_DISPATCHED_DMG: (u32, u8) = (381_990, 2);
456 pub(crate) const SCOUNDREL_CP_THRESHOLD: (u32, u8) = (1_265_862, 1);
458 pub(crate) const SCOUNDREL_STRIKE_DAMAGE: (u32, u8) = (1_265_918, 1);
460 pub(crate) const SINISTER_STRIKE_EXTRA_ATTACK_DAMAGE: (u32, u8) = (197_834, 1);
462 pub(crate) const SLEIGHT_OF_HAND_CHANCE: (u32, u8) = (381_839, 1);
464 pub(crate) const BLADE_RUSH_PRIMARY_MULT: (u32, u8) = (271_881, 2);
466 pub(crate) const CONTROLLED_CHAOS_STREAK: (u32, u8) = (1_276_816, 1);
468 pub(crate) const RUSH_ENERGY: (u32, u8) = (1_249_204, 2);
470 pub(crate) const RUSH_ENERGY_EDGE: (u32, u8) = (1_249_204, 4);
472 pub(crate) const BLADE_FLURRY_INSTANT_ATTACK_DAMAGE: (u32, u8) = (429_951, 1);
474}
475static REPORTED_SPELLS: &[(&str, u32)] = &[
476 ("blade_rush_attack", 271_881),
477 ("fatebound_coin_tails", 452_538),
478 ("instant_poison_damage", 315_585),
479 ("killing_spree_mh", 57841),
480 ("killing_spree_oh", 57842),
481 ("main_gauche", 86392),
482 ("scoundrel_strike", 1_265_918),
483 ("sinister_strike_extra_attack", 197_834),
484];
485static DECLARED_SPELL_IDS: &[u32] = &[
486 381_623, 1856, 193_315, 197_834, 185_763, 8676, 2098, 315_341, 196_819, 315_496,
487 315_584, 8679, 381_637, 5761, 3408, 86392, 1_265_918, 315_585, 1766, 315_508, 13750,
488 13877, 429_951, 271_877, 51690, 381_989, 1_277_933, 271_881, 315_496, 195_627,
489 386_270, 315_341, 1784, 1856, 115_192, 383_281, 381_878, 14983, 1_214_933, 1_214_934,
490 1_214_935, 1_214_937, 256_171, 13750, 13877, 315_584, 8679, 381_637, 5761, 3408,
491 395_422, 271_896, 1_265_931, 1_265_935, 1_259_613, 1_259_614, 134_735, 452_923,
492 452_917, 1_248_971, 1_249_093, 6603, 13750, 13877, 14161, 22482, 35546, 35551, 57841,
493 57842, 76806, 79096, 86392, 185_763, 197_834, 271_881, 315_341, 315_585, 381_828,
494 381_839, 381_846, 381_990, 383_281, 394_120, 429_951, 452_536, 452_538, 452_923,
495 453_428, 454_419, 454_435, 1_214_937, 1_248_970, 1_248_971, 1_249_194, 1_249_204,
496 1_254_567, 1_265_862, 1_265_863, 1_265_918, 1_276_809, 1_276_816, 1_279_356, 271_881,
497 452_538, 315_585, 57841, 57842, 86392, 1_265_918, 197_834, 1_276_816, 454_419,
498 1_249_194, 454_435, 453_457, 452_538, 452_536, 1_248_970, 453_428, 1_276_809,
499 1_249_204, 452_923, 452_917, 1_248_971, 441_519, 462_127, 462_128, 462_129, 459_485,
500 441_274, 441_786, 441_224, 441_326, 459_485,
501];
502static DECLARED_AURA_IDS: &[u32] = &[
503 315_496, 195_627, 386_270, 315_341, 1784, 1856, 115_192, 383_281, 381_878, 14983,
504 1_214_933, 1_214_934, 1_214_935, 1_214_937, 256_171, 13750, 13877, 315_584, 8679,
505 381_637, 5761, 3408, 395_422, 271_896, 1_265_931, 1_265_935, 1_259_613, 1_259_614,
506 134_735, 452_923, 452_917, 1_248_971, 1_249_093, 452_923, 452_917, 1_248_971,
507 441_274, 441_786, 441_224, 441_326, 459_485,
508];
509static TALENTS: &[(&str, u32)] = &[
510 ("ACE_UP_YOUR_SLEEVE", TALENT::ACE_UP_YOUR_SLEEVE),
511 ("ADRENALINE_RUSH", TALENT::ADRENALINE_RUSH),
512 ("AUDACITY", TALENT::AUDACITY),
513 ("BLADE_FLURRY", TALENT::BLADE_FLURRY),
514 ("BLADE_RUSH", TALENT::BLADE_RUSH),
515 ("DEADLY_PURSUIT", TALENT::DEADLY_PURSUIT),
516 ("DEFT_MANEUVERS", TALENT::DEFT_MANEUVERS),
517 ("DEVIOUS_STRATAGEM", TALENT::DEVIOUS_STRATAGEM),
518 ("FAN_THE_HAMMER", TALENT::FAN_THE_HAMMER),
519 ("FATAL_FLOURISH", TALENT::FATAL_FLOURISH),
520 ("GRAVEDIGGER_1", TALENT::GRAVEDIGGER_1),
521 ("GRAVEDIGGER_2", TALENT::GRAVEDIGGER_2),
522 ("GRAVEDIGGER_3", TALENT::GRAVEDIGGER_3),
523 ("HIDDEN_OPPORTUNITY", TALENT::HIDDEN_OPPORTUNITY),
524 ("IMPROVED_ADRENALINE_RUSH", TALENT::IMPROVED_ADRENALINE_RUSH),
525 ("KEEP_IT_ROLLING", TALENT::KEEP_IT_ROLLING),
526 ("KILLING_SPREE", TALENT::KILLING_SPREE),
527 ("LOADED_DICE", TALENT::LOADED_DICE),
528 ("MENACING_RUSH", TALENT::MENACING_RUSH),
529 ("OPPORTUNITY", TALENT::OPPORTUNITY),
530 ("PREPARATION", TALENT::PREPARATION),
531 ("QUICK_DRAW", TALENT::QUICK_DRAW),
532 ("RESTLESS_BLADES", TALENT::RESTLESS_BLADES),
533 ("RUTHLESSNESS", TALENT::RUTHLESSNESS),
534 ("SLEIGHT_OF_HAND", TALENT::SLEIGHT_OF_HAND),
535 ("SUMMARILY_DISPATCHED", TALENT::SUMMARILY_DISPATCHED),
536 ("THISTLE_TEA", TALENT::THISTLE_TEA),
537 ("ZERO_IN", TALENT::ZERO_IN),
538];
539pub(crate) mod OUTLAW_ROGUE {
540 pub(crate) const SINISTER_STRIKE_CASTS: u32 = 0;
541 pub(crate) const PISTOL_SHOT_CASTS: u32 = 1;
542 pub(crate) const AMBUSH_CASTS: u32 = 2;
543 pub(crate) const DISPATCH_CASTS: u32 = 3;
544 pub(crate) const BETWEEN_THE_EYES_CASTS: u32 = 4;
545 pub(crate) const ROLL_THE_BONES_CASTS: u32 = 5;
546 pub(crate) const ADRENALINE_RUSH_CASTS: u32 = 6;
547 pub(crate) const BLADE_FLURRY_CASTS: u32 = 7;
548 pub(crate) const BLADE_RUSH_CASTS: u32 = 8;
549 pub(crate) const KILLING_SPREE_CASTS: u32 = 9;
550 pub(crate) const ADRENALINE_RUSH_UPTIME_MS: u32 = 10;
551 pub(crate) const BLADE_FLURRY_UPTIME_MS: u32 = 11;
552}
553fn aura_slice_and_dice(
554 a: AuraDefinitionDraft,
555 data: &ResolvedGameData,
556) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
557 Ok(
558 a
559 .on_player()
560 .apply_base_from_data(data, 315_496)?
561 .max_stacks(
562 data
563 .require_aura_max_stacks(
564 wowlab_types::sim::SpellIdx::from_raw(315_496),
565 )?,
566 ),
567 )
568}
569fn aura_opportunity(
570 a: AuraDefinitionDraft,
571 data: &ResolvedGameData,
572) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
573 Ok(
574 a
575 .on_player()
576 .apply_base_from_data(data, 195_627)?
577 .max_stacks(
578 data
579 .require_aura_max_stacks(
580 wowlab_types::sim::SpellIdx::from_raw(195_627),
581 )?,
582 ),
583 )
584}
585fn aura_audacity(
586 a: AuraDefinitionDraft,
587 data: &ResolvedGameData,
588) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
589 Ok(
590 a
591 .on_player()
592 .apply_base_from_data(data, 386_270)?
593 .max_stacks(
594 data
595 .require_aura_max_stacks(
596 wowlab_types::sim::SpellIdx::from_raw(386_270),
597 )?,
598 ),
599 )
600}
601fn aura_between_the_eyes(
602 a: AuraDefinitionDraft,
603 data: &ResolvedGameData,
604) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
605 Ok(
606 a
607 .on_player()
608 .apply_base_from_data(data, 315_341)?
609 .max_stacks(
610 data
611 .require_aura_max_stacks(
612 wowlab_types::sim::SpellIdx::from_raw(315_341),
613 )?,
614 )
615 .async_stacks(),
616 )
617}
618fn aura_stealth(
619 a: AuraDefinitionDraft,
620 data: &ResolvedGameData,
621) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
622 Ok(
623 a
624 .on_player()
625 .apply_base_from_data(data, 1784)?
626 .max_stacks(
627 data
628 .require_aura_max_stacks(
629 wowlab_types::sim::SpellIdx::from_raw(1784),
630 )?,
631 ),
632 )
633}
634fn aura_vanish(
635 a: AuraDefinitionDraft,
636 data: &ResolvedGameData,
637) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
638 Ok(
639 a
640 .on_player()
641 .apply_base_from_data(data, 1856)?
642 .max_stacks(
643 data
644 .require_aura_max_stacks(
645 wowlab_types::sim::SpellIdx::from_raw(1856),
646 )?,
647 ),
648 )
649}
650fn aura_subterfuge(
651 a: AuraDefinitionDraft,
652 data: &ResolvedGameData,
653) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
654 Ok(
655 a
656 .on_player()
657 .apply_base_from_data(data, 115_192)?
658 .max_stacks(
659 data
660 .require_aura_max_stacks(
661 wowlab_types::sim::SpellIdx::from_raw(115_192),
662 )?,
663 ),
664 )
665}
666fn aura_hidden_opportunity(
667 a: AuraDefinitionDraft,
668 data: &ResolvedGameData,
669) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
670 Ok(
671 a
672 .on_player()
673 .apply_base_from_data(data, 383_281)?
674 .max_stacks(
675 data
676 .require_aura_max_stacks(
677 wowlab_types::sim::SpellIdx::from_raw(383_281),
678 )?,
679 ),
680 )
681}
682fn aura_deft_maneuvers(
683 a: AuraDefinitionDraft,
684 data: &ResolvedGameData,
685) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
686 Ok(
687 a
688 .on_player()
689 .apply_base_from_data(data, 381_878)?
690 .max_stacks(
691 data
692 .require_aura_max_stacks(
693 wowlab_types::sim::SpellIdx::from_raw(381_878),
694 )?,
695 ),
696 )
697}
698fn aura_vigor(
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, 14983)?
706 .max_stacks(
707 data
708 .require_aura_max_stacks(
709 wowlab_types::sim::SpellIdx::from_raw(14983),
710 )?,
711 ),
712 )
713}
714fn aura_one_of_a_kind(
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_214_933)?
722 .max_stacks(
723 data
724 .require_aura_max_stacks(
725 wowlab_types::sim::SpellIdx::from_raw(1_214_933),
726 )?,
727 ),
728 )
729}
730fn aura_double_trouble(
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, 1_214_934)?
738 .max_stacks(
739 data
740 .require_aura_max_stacks(
741 wowlab_types::sim::SpellIdx::from_raw(1_214_934),
742 )?,
743 ),
744 )
745}
746fn aura_triple_threat(
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_214_935)?
754 .max_stacks(
755 data
756 .require_aura_max_stacks(
757 wowlab_types::sim::SpellIdx::from_raw(1_214_935),
758 )?,
759 ),
760 )
761}
762fn aura_jackpot(
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, 1_214_937)?
770 .max_stacks(
771 data
772 .require_aura_max_stacks(
773 wowlab_types::sim::SpellIdx::from_raw(1_214_937),
774 )?,
775 ),
776 )
777}
778fn aura_loaded_dice(
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, 256_171)?
786 .max_stacks(
787 data
788 .require_aura_max_stacks(
789 wowlab_types::sim::SpellIdx::from_raw(256_171),
790 )?,
791 ),
792 )
793}
794fn aura_adrenaline_rush(
795 a: AuraDefinitionDraft,
796 data: &ResolvedGameData,
797) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
798 a.on_player()
799 .apply_base_from_data(data, 13750)?
800 .max_stacks(
801 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(13750))?,
802 )
803 .max_resource_per_stack(
804 data.base_points(wowlab_types::sim::SpellIdx::from_raw(13750), 6),
805 )
806}
807fn aura_blade_flurry(
808 a: AuraDefinitionDraft,
809 data: &ResolvedGameData,
810) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
811 Ok(
812 a
813 .on_player()
814 .apply_base_from_data(data, 13877)?
815 .max_stacks(
816 data
817 .require_aura_max_stacks(
818 wowlab_types::sim::SpellIdx::from_raw(13877),
819 )?,
820 ),
821 )
822}
823fn aura_instant_poison(
824 a: AuraDefinitionDraft,
825 data: &ResolvedGameData,
826) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
827 Ok(
828 a
829 .on_player()
830 .apply_base_from_data(data, 315_584)?
831 .max_stacks(
832 data
833 .require_aura_max_stacks(
834 wowlab_types::sim::SpellIdx::from_raw(315_584),
835 )?,
836 )
837 .spell_group(0, wowlab_types::combat::SpellGroupRule::Exclusive),
838 )
839}
840fn aura_wound_poison(
841 a: AuraDefinitionDraft,
842 data: &ResolvedGameData,
843) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
844 Ok(
845 a
846 .on_player()
847 .apply_base_from_data(data, 8679)?
848 .max_stacks(
849 data
850 .require_aura_max_stacks(
851 wowlab_types::sim::SpellIdx::from_raw(8679),
852 )?,
853 )
854 .spell_group(0, wowlab_types::combat::SpellGroupRule::Exclusive),
855 )
856}
857fn aura_atrophic_poison(
858 a: AuraDefinitionDraft,
859 data: &ResolvedGameData,
860) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
861 Ok(
862 a
863 .on_player()
864 .apply_base_from_data(data, 381_637)?
865 .max_stacks(
866 data
867 .require_aura_max_stacks(
868 wowlab_types::sim::SpellIdx::from_raw(381_637),
869 )?,
870 )
871 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
872 )
873}
874fn aura_numbing_poison(
875 a: AuraDefinitionDraft,
876 data: &ResolvedGameData,
877) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
878 Ok(
879 a
880 .on_player()
881 .apply_base_from_data(data, 5761)?
882 .max_stacks(
883 data
884 .require_aura_max_stacks(
885 wowlab_types::sim::SpellIdx::from_raw(5761),
886 )?,
887 )
888 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
889 )
890}
891fn aura_crippling_poison(
892 a: AuraDefinitionDraft,
893 data: &ResolvedGameData,
894) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
895 Ok(
896 a
897 .on_player()
898 .apply_base_from_data(data, 3408)?
899 .max_stacks(
900 data
901 .require_aura_max_stacks(
902 wowlab_types::sim::SpellIdx::from_raw(3408),
903 )?,
904 )
905 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
906 )
907}
908fn aura_improved_adrenaline_rush(
909 a: AuraDefinitionDraft,
910 data: &ResolvedGameData,
911) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
912 Ok(
913 a
914 .on_player()
915 .apply_base_from_data(data, 395_422)?
916 .max_stacks(
917 data
918 .require_aura_max_stacks(
919 wowlab_types::sim::SpellIdx::from_raw(395_422),
920 )?,
921 ),
922 )
923}
924fn aura_blade_rush_energize(
925 a: AuraDefinitionDraft,
926 data: &ResolvedGameData,
927) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
928 Ok(
929 a
930 .on_player()
931 .apply_base_from_data(data, 271_896)?
932 .max_stacks(
933 data
934 .require_aura_max_stacks(
935 wowlab_types::sim::SpellIdx::from_raw(271_896),
936 )?,
937 ),
938 )
939}
940fn aura_palmed_bullets(
941 a: AuraDefinitionDraft,
942 data: &ResolvedGameData,
943) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
944 Ok(
945 a
946 .on_player()
947 .apply_base_from_data(data, 1_265_931)?
948 .max_stacks(
949 data
950 .require_aura_max_stacks(
951 wowlab_types::sim::SpellIdx::from_raw(1_265_931),
952 )?,
953 ),
954 )
955}
956fn aura_gravedigger(
957 a: AuraDefinitionDraft,
958 data: &ResolvedGameData,
959) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
960 Ok(
961 a
962 .on_player()
963 .apply_base_from_data(data, 1_265_935)?
964 .max_stacks(
965 data
966 .require_aura_max_stacks(
967 wowlab_types::sim::SpellIdx::from_raw(1_265_935),
968 )?,
969 ),
970 )
971}
972fn aura_deadly_pursuit_wait(
973 a: AuraDefinitionDraft,
974 data: &ResolvedGameData,
975) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
976 Ok(
977 a
978 .on_player()
979 .apply_base_from_data(data, 1_259_613)?
980 .max_stacks(
981 data
982 .require_aura_max_stacks(
983 wowlab_types::sim::SpellIdx::from_raw(1_259_613),
984 )?,
985 )
986 .on_expire(crate::hooks::outlaw_rogue::deadly_pursuit_wait_expire_hook),
987 )
988}
989fn aura_deadly_pursuit_cdr(
990 a: AuraDefinitionDraft,
991 data: &ResolvedGameData,
992) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
993 Ok(
994 a
995 .on_player()
996 .apply_base_from_data(data, 1_259_614)?
997 .max_stacks(
998 data
999 .require_aura_max_stacks(
1000 wowlab_types::sim::SpellIdx::from_raw(1_259_614),
1001 )?,
1002 ),
1003 )
1004}
1005fn aura_pvp_rules_enabled_hardcoded(
1006 a: AuraDefinitionDraft,
1007 data: &ResolvedGameData,
1008) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1009 Ok(
1010 a
1011 .on_player()
1012 .apply_base_from_data(data, 134_735)?
1013 .max_stacks(
1014 data
1015 .require_aura_max_stacks(
1016 wowlab_types::sim::SpellIdx::from_raw(134_735),
1017 )?,
1018 ),
1019 )
1020}
1021fn aura_fatebound_coin_heads(
1022 a: AuraDefinitionDraft,
1023 data: &ResolvedGameData,
1024) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1025 Ok(
1026 a
1027 .on_player()
1028 .apply_base_from_data(data, 452_923)?
1029 .max_stacks(
1030 data
1031 .require_aura_max_stacks(
1032 wowlab_types::sim::SpellIdx::from_raw(452_923),
1033 )?,
1034 ),
1035 )
1036}
1037fn aura_fatebound_coin_tails(
1038 a: AuraDefinitionDraft,
1039 data: &ResolvedGameData,
1040) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1041 Ok(
1042 a
1043 .on_player()
1044 .apply_base_from_data(data, 452_917)?
1045 .max_stacks(
1046 data
1047 .require_aura_max_stacks(
1048 wowlab_types::sim::SpellIdx::from_raw(452_917),
1049 )?,
1050 ),
1051 )
1052}
1053fn aura_fatebound_lucky_coin(
1054 a: AuraDefinitionDraft,
1055 data: &ResolvedGameData,
1056) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1057 a.on_player()
1058 .apply_base_from_data(data, 1_248_971)?
1059 .max_stacks(
1060 data
1061 .require_aura_max_stacks(
1062 wowlab_types::sim::SpellIdx::from_raw(1_248_971),
1063 )?,
1064 )
1065 .primary_pct_per_stack(
1066 data.base_points(wowlab_types::sim::SpellIdx::from_raw(1_248_971), 1),
1067 )
1068}
1069fn aura_lucky_coin_counter(
1070 a: AuraDefinitionDraft,
1071 data: &ResolvedGameData,
1072) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1073 Ok(
1074 a
1075 .on_player()
1076 .apply_base_from_data(data, 1_249_093)?
1077 .max_stacks(
1078 data
1079 .require_aura_max_stacks(
1080 wowlab_types::sim::SpellIdx::from_raw(1_249_093),
1081 )?,
1082 ),
1083 )
1084}
1085fn spell_thistle_tea(
1086 s: SpellDefinitionDraft,
1087 data: &ResolvedGameData,
1088) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1089 Ok(
1090 s
1091 .apply_base_from_data(data, 381_623)?
1092 .no_stealth_break()
1093 .apply_aoe_from_data(data),
1094 )
1095}
1096fn spell_vanish(
1097 s: SpellDefinitionDraft,
1098 data: &ResolvedGameData,
1099) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1100 Ok(
1101 s
1102 .apply_base_from_data(data, 1856)?
1103 .applies_aura(AURA_STEALTH)
1104 .no_stealth_break()
1105 .apply_aoe_from_data(data),
1106 )
1107}
1108fn spell_sinister_strike(
1109 s: SpellDefinitionDraft,
1110 data: &ResolvedGameData,
1111) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1112 Ok(
1113 s
1114 .apply_base_from_data(data, 193_315)?
1115 .apply_aoe_from_data(data)
1116 .on_cast(crate::hooks::outlaw_rogue::sinister_strike_hook),
1117 )
1118}
1119fn spell_sinister_strike_extra_attack(
1120 s: SpellDefinitionDraft,
1121 data: &ResolvedGameData,
1122) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1123 Ok(s.apply_base_from_data(data, 197_834)?.apply_aoe_from_data(data))
1124}
1125fn spell_pistol_shot(
1126 s: SpellDefinitionDraft,
1127 data: &ResolvedGameData,
1128) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1129 Ok(
1130 s
1131 .apply_base_from_data(data, 185_763)?
1132 .damage_ap_from_data_typed(
1133 wowlab_engine_domain::dbc::EffectLookup::new(
1134 data,
1135 wowlab_types::sim::EffectRef::new(
1136 wowlab_types::sim::SpellIdx::from_raw(185_763),
1137 1,
1138 ),
1139 ),
1140 wowlab_engine_combat::WeaponApType::Both,
1141 )?
1142 .apply_aoe_from_data(data)
1143 .on_cast(crate::hooks::outlaw_rogue::pistol_shot_hook),
1144 )
1145}
1146fn spell_ambush(
1147 s: SpellDefinitionDraft,
1148 data: &ResolvedGameData,
1149) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1150 Ok(
1151 s
1152 .apply_base_from_data(data, 8676)?
1153 .no_stealth_break()
1154 .apply_aoe_from_data(data)
1155 .on_cast(crate::hooks::outlaw_rogue::ambush_hook),
1156 )
1157}
1158fn spell_dispatch(
1159 s: SpellDefinitionDraft,
1160 data: &ResolvedGameData,
1161) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1162 Ok(
1163 s
1164 .apply_base_from_data(data, 2098)?
1165 .apply_aoe_from_data(data)
1166 .on_cast(crate::hooks::outlaw_rogue::dispatch_hook),
1167 )
1168}
1169fn spell_between_the_eyes(
1170 s: SpellDefinitionDraft,
1171 data: &ResolvedGameData,
1172) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1173 Ok(
1174 s
1175 .apply_base_from_data(data, 315_341)?
1176 .damage_ap_from_data_typed(
1177 wowlab_engine_domain::dbc::EffectLookup::new(
1178 data,
1179 wowlab_types::sim::EffectRef::new(
1180 wowlab_types::sim::SpellIdx::from_raw(315_341),
1181 1,
1182 ),
1183 ),
1184 wowlab_engine_combat::WeaponApType::Both,
1185 )?
1186 .applies_inferred_aura(AURA_BETWEEN_THE_EYES, 315_341)
1187 .apply_aoe_from_data(data)
1188 .on_cast(crate::hooks::outlaw_rogue::between_the_eyes_hook),
1189 )
1190}
1191fn spell_eviscerate(
1192 s: SpellDefinitionDraft,
1193 data: &ResolvedGameData,
1194) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1195 Ok(s.apply_base_from_data(data, 196_819)?.apply_aoe_from_data(data))
1196}
1197fn spell_slice_and_dice(
1198 s: SpellDefinitionDraft,
1199 data: &ResolvedGameData,
1200) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1201 Ok(
1202 s
1203 .apply_base_from_data(data, 315_496)?
1204 .applies_inferred_aura(AURA_SLICE_AND_DICE, 315_496)
1205 .apply_aoe_from_data(data)
1206 .on_cast(crate::hooks::outlaw_rogue::slice_and_dice_hook),
1207 )
1208}
1209fn spell_instant_poison(
1210 s: SpellDefinitionDraft,
1211 data: &ResolvedGameData,
1212) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1213 Ok(
1214 s
1215 .apply_base_from_data(data, 315_584)?
1216 .applies_inferred_aura(AURA_INSTANT_POISON, 315_584)
1217 .apply_aoe_from_data(data),
1218 )
1219}
1220fn spell_wound_poison(
1221 s: SpellDefinitionDraft,
1222 data: &ResolvedGameData,
1223) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1224 Ok(
1225 s
1226 .apply_base_from_data(data, 8679)?
1227 .applies_inferred_aura(AURA_WOUND_POISON, 8679)
1228 .apply_aoe_from_data(data),
1229 )
1230}
1231fn spell_atrophic_poison(
1232 s: SpellDefinitionDraft,
1233 data: &ResolvedGameData,
1234) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1235 Ok(
1236 s
1237 .apply_base_from_data(data, 381_637)?
1238 .applies_inferred_aura(AURA_ATROPHIC_POISON, 381_637)
1239 .apply_aoe_from_data(data),
1240 )
1241}
1242fn spell_numbing_poison(
1243 s: SpellDefinitionDraft,
1244 data: &ResolvedGameData,
1245) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1246 Ok(
1247 s
1248 .apply_base_from_data(data, 5761)?
1249 .applies_inferred_aura(AURA_NUMBING_POISON, 5761)
1250 .apply_aoe_from_data(data),
1251 )
1252}
1253fn spell_crippling_poison(
1254 s: SpellDefinitionDraft,
1255 data: &ResolvedGameData,
1256) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1257 Ok(
1258 s
1259 .apply_base_from_data(data, 3408)?
1260 .applies_inferred_aura(AURA_CRIPPLING_POISON, 3408)
1261 .apply_aoe_from_data(data),
1262 )
1263}
1264fn spell_main_gauche(
1265 s: SpellDefinitionDraft,
1266 data: &ResolvedGameData,
1267) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1268 Ok(s.apply_base_from_data(data, 86392)?.apply_aoe_from_data(data))
1269}
1270fn spell_scoundrel_strike(
1271 s: SpellDefinitionDraft,
1272 data: &ResolvedGameData,
1273) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1274 Ok(s.apply_base_from_data(data, 1_265_918)?.apply_aoe_from_data(data))
1275}
1276fn spell_instant_poison_damage(
1277 s: SpellDefinitionDraft,
1278 data: &ResolvedGameData,
1279) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1280 Ok(s.apply_base_from_data(data, 315_585)?.apply_aoe_from_data(data))
1281}
1282fn spell_kick(
1283 s: SpellDefinitionDraft,
1284 data: &ResolvedGameData,
1285) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1286 Ok(s.apply_base_from_data(data, 1766)?.apply_aoe_from_data(data))
1287}
1288fn spell_roll_the_bones(
1289 s: SpellDefinitionDraft,
1290 data: &ResolvedGameData,
1291) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1292 Ok(
1293 s
1294 .apply_base_from_data(data, 315_508)?
1295 .no_stealth_break()
1296 .apply_aoe_from_data(data)
1297 .on_cast(crate::hooks::outlaw_rogue::roll_the_bones_hook),
1298 )
1299}
1300fn spell_adrenaline_rush(
1301 s: SpellDefinitionDraft,
1302 data: &ResolvedGameData,
1303) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1304 Ok(
1305 s
1306 .apply_base_from_data(data, 13750)?
1307 .applies_inferred_aura(AURA_ADRENALINE_RUSH, 13750)
1308 .apply_aoe_from_data(data)
1309 .on_cast(crate::hooks::outlaw_rogue::adrenaline_rush_hook),
1310 )
1311}
1312fn spell_blade_flurry(
1313 s: SpellDefinitionDraft,
1314 data: &ResolvedGameData,
1315) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1316 Ok(
1317 s
1318 .apply_base_from_data(data, 13877)?
1319 .applies_inferred_aura(AURA_BLADE_FLURRY, 13877)
1320 .apply_aoe_from_data(data)
1321 .on_cast(crate::hooks::outlaw_rogue::blade_flurry_hook),
1322 )
1323}
1324fn spell_blade_flurry_instant_attack(
1325 s: SpellDefinitionDraft,
1326 data: &ResolvedGameData,
1327) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1328 Ok(s.apply_base_from_data(data, 429_951)?.apply_aoe_from_data(data))
1329}
1330fn spell_blade_rush(
1331 s: SpellDefinitionDraft,
1332 data: &ResolvedGameData,
1333) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1334 Ok(
1335 s
1336 .apply_base_from_data(data, 271_877)?
1337 .applies_aura(AURA_BLADE_RUSH_ENERGIZE)
1338 .apply_aoe_from_data(data)
1339 .on_cast(crate::hooks::outlaw_rogue::blade_rush_hook),
1340 )
1341}
1342fn spell_killing_spree(
1343 s: SpellDefinitionDraft,
1344 data: &ResolvedGameData,
1345) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1346 Ok(
1347 s
1348 .apply_base_from_data(data, 51690)?
1349 .apply_aoe_from_data(data)
1350 .on_cast(crate::hooks::outlaw_rogue::killing_spree_hook),
1351 )
1352}
1353fn spell_keep_it_rolling(
1354 s: SpellDefinitionDraft,
1355 data: &ResolvedGameData,
1356) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1357 Ok(
1358 s
1359 .apply_base_from_data(data, 381_989)?
1360 .apply_aoe_from_data(data)
1361 .on_cast(crate::hooks::outlaw_rogue::keep_it_rolling_hook),
1362 )
1363}
1364fn spell_preparation(
1365 s: SpellDefinitionDraft,
1366 data: &ResolvedGameData,
1367) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1368 Ok(
1369 s
1370 .apply_base_from_data(data, 1_277_933)?
1371 .apply_aoe_from_data(data)
1372 .on_cast(crate::hooks::outlaw_rogue::preparation_hook),
1373 )
1374}
1375fn spell_blade_rush_attack(
1376 s: SpellDefinitionDraft,
1377 data: &ResolvedGameData,
1378) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1379 Ok(s.apply_base_from_data(data, 271_881)?.apply_aoe_from_data(data))
1380}
1381pub(crate) fn build_combat_system(
1382 params: &wowlab_engine_ports::HandlerParams<'_>,
1383) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1384 let builder = BuiltCombatSystem::builder(params.stats.clone())
1385 .spec_id(SpecId::Outlaw)
1386 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1387 .mastery_spell(76806)
1388 .mastery_hook(crate::hooks::outlaw_rogue::mastery)
1389 .resource(
1390 "energy",
1391 params
1392 .game_data
1393 .power_max(3)
1394 .ok_or_else(|| {
1395 wowlab_engine_ports::EngineError::spec_construction(
1396 "missing power-type power_max for type_id 3",
1397 )
1398 })?,
1399 params
1400 .game_data
1401 .power_regen_for_max(
1402 3,
1403 params
1404 .game_data
1405 .power_max(3)
1406 .ok_or_else(|| {
1407 wowlab_engine_ports::EngineError::spec_construction(
1408 "missing power-type power_max for type_id 3",
1409 )
1410 })?,
1411 )
1412 .ok_or_else(|| {
1413 wowlab_engine_ports::EngineError::spec_construction(
1414 "missing power-type power_regen_for_max for type_id 3",
1415 )
1416 })?,
1417 )
1418 .resource_type_id(3)
1419 .resource_start(
1420 params
1421 .game_data
1422 .power_default(3)
1423 .ok_or_else(|| {
1424 wowlab_engine_ports::EngineError::spec_construction(
1425 "missing power-type power_default for type_id 3",
1426 )
1427 })?,
1428 )
1429 .secondary_resource(
1430 "combo_points",
1431 params
1432 .game_data
1433 .power_max(4)
1434 .ok_or_else(|| {
1435 wowlab_engine_ports::EngineError::spec_construction(
1436 "missing power-type power_max for type_id 4",
1437 )
1438 })?,
1439 )
1440 .secondary_resource_type_id(4)
1441 .precombat_aura(AURA_STEALTH)
1442 .precombat_aura(AURA_INSTANT_POISON)
1443 .precombat_aura(AURA_ATROPHIC_POISON)
1444 .stealth_aura(AURA::STEALTH)
1445 .aura(
1446 "slice_and_dice",
1447 AURA::SLICE_AND_DICE,
1448 |a| aura_slice_and_dice(a, ¶ms.game_data),
1449 )
1450 .aura(
1451 "opportunity",
1452 AURA::OPPORTUNITY,
1453 |a| aura_opportunity(a, ¶ms.game_data),
1454 )
1455 .aura("audacity", AURA::AUDACITY, |a| aura_audacity(a, ¶ms.game_data))
1456 .aura(
1457 "between_the_eyes",
1458 AURA::BETWEEN_THE_EYES,
1459 |a| aura_between_the_eyes(a, ¶ms.game_data),
1460 )
1461 .aura("stealth", AURA::STEALTH, |a| aura_stealth(a, ¶ms.game_data))
1462 .aura("vanish", AURA::VANISH, |a| aura_vanish(a, ¶ms.game_data))
1463 .aura("subterfuge", AURA::SUBTERFUGE, |a| aura_subterfuge(a, ¶ms.game_data))
1464 .aura(
1465 "hidden_opportunity",
1466 AURA::HIDDEN_OPPORTUNITY,
1467 |a| aura_hidden_opportunity(a, ¶ms.game_data),
1468 )
1469 .aura(
1470 "deft_maneuvers",
1471 AURA::DEFT_MANEUVERS,
1472 |a| aura_deft_maneuvers(a, ¶ms.game_data),
1473 )
1474 .aura("vigor", AURA::VIGOR, |a| aura_vigor(a, ¶ms.game_data))
1475 .aura(
1476 "one_of_a_kind",
1477 AURA::ONE_OF_A_KIND,
1478 |a| aura_one_of_a_kind(a, ¶ms.game_data),
1479 )
1480 .aura(
1481 "double_trouble",
1482 AURA::DOUBLE_TROUBLE,
1483 |a| aura_double_trouble(a, ¶ms.game_data),
1484 )
1485 .aura(
1486 "triple_threat",
1487 AURA::TRIPLE_THREAT,
1488 |a| aura_triple_threat(a, ¶ms.game_data),
1489 )
1490 .aura("jackpot", AURA::JACKPOT, |a| aura_jackpot(a, ¶ms.game_data))
1491 .aura(
1492 "loaded_dice",
1493 AURA::LOADED_DICE,
1494 |a| aura_loaded_dice(a, ¶ms.game_data),
1495 )
1496 .aura(
1497 "adrenaline_rush",
1498 AURA::ADRENALINE_RUSH,
1499 |a| aura_adrenaline_rush(a, ¶ms.game_data),
1500 )
1501 .aura(
1502 "blade_flurry",
1503 AURA::BLADE_FLURRY,
1504 |a| aura_blade_flurry(a, ¶ms.game_data),
1505 )
1506 .aura(
1507 "instant_poison",
1508 AURA::INSTANT_POISON,
1509 |a| aura_instant_poison(a, ¶ms.game_data),
1510 )
1511 .aura(
1512 "wound_poison",
1513 AURA::WOUND_POISON,
1514 |a| aura_wound_poison(a, ¶ms.game_data),
1515 )
1516 .aura(
1517 "atrophic_poison",
1518 AURA::ATROPHIC_POISON,
1519 |a| aura_atrophic_poison(a, ¶ms.game_data),
1520 )
1521 .aura(
1522 "numbing_poison",
1523 AURA::NUMBING_POISON,
1524 |a| aura_numbing_poison(a, ¶ms.game_data),
1525 )
1526 .aura(
1527 "crippling_poison",
1528 AURA::CRIPPLING_POISON,
1529 |a| aura_crippling_poison(a, ¶ms.game_data),
1530 )
1531 .aura(
1532 "improved_adrenaline_rush",
1533 AURA::IMPROVED_ADRENALINE_RUSH,
1534 |a| aura_improved_adrenaline_rush(a, ¶ms.game_data),
1535 )
1536 .aura(
1537 "blade_rush_energize",
1538 AURA::BLADE_RUSH_ENERGIZE,
1539 |a| aura_blade_rush_energize(a, ¶ms.game_data),
1540 )
1541 .aura(
1542 "palmed_bullets",
1543 AURA::PALMED_BULLETS,
1544 |a| aura_palmed_bullets(a, ¶ms.game_data),
1545 )
1546 .aura(
1547 "gravedigger",
1548 AURA::GRAVEDIGGER,
1549 |a| aura_gravedigger(a, ¶ms.game_data),
1550 )
1551 .aura(
1552 "deadly_pursuit_wait",
1553 AURA::DEADLY_PURSUIT_WAIT,
1554 |a| aura_deadly_pursuit_wait(a, ¶ms.game_data),
1555 )
1556 .aura(
1557 "deadly_pursuit_cdr",
1558 AURA::DEADLY_PURSUIT_CDR,
1559 |a| aura_deadly_pursuit_cdr(a, ¶ms.game_data),
1560 )
1561 .aura(
1562 "pvp_rules_enabled_hardcoded",
1563 AURA::PVP_RULES_ENABLED_HARDCODED,
1564 |a| aura_pvp_rules_enabled_hardcoded(a, ¶ms.game_data),
1565 )
1566 .aura(
1567 "fatebound_coin_heads",
1568 AURA::FATEBOUND_COIN_HEADS,
1569 |a| aura_fatebound_coin_heads(a, ¶ms.game_data),
1570 )
1571 .aura(
1572 "fatebound_coin_tails",
1573 AURA::FATEBOUND_COIN_TAILS,
1574 |a| aura_fatebound_coin_tails(a, ¶ms.game_data),
1575 )
1576 .aura(
1577 "fatebound_lucky_coin",
1578 AURA::FATEBOUND_LUCKY_COIN,
1579 |a| aura_fatebound_lucky_coin(a, ¶ms.game_data),
1580 )
1581 .aura(
1582 "lucky_coin_counter",
1583 AURA::LUCKY_COIN_COUNTER,
1584 |a| aura_lucky_coin_counter(a, ¶ms.game_data),
1585 )
1586 .spell(
1587 "thistle_tea",
1588 SPELL::THISTLE_TEA,
1589 |s| spell_thistle_tea(s, ¶ms.game_data),
1590 )
1591 .spell("vanish", SPELL::VANISH, |s| spell_vanish(s, ¶ms.game_data))
1592 .spell(
1593 "sinister_strike",
1594 SPELL::SINISTER_STRIKE,
1595 |s| spell_sinister_strike(s, ¶ms.game_data),
1596 )
1597 .spell(
1598 "sinister_strike_extra_attack",
1599 SPELL::SINISTER_STRIKE_EXTRA_ATTACK,
1600 |s| spell_sinister_strike_extra_attack(s, ¶ms.game_data),
1601 )
1602 .spell(
1603 "pistol_shot",
1604 SPELL::PISTOL_SHOT,
1605 |s| spell_pistol_shot(s, ¶ms.game_data),
1606 )
1607 .spell("ambush", SPELL::AMBUSH, |s| spell_ambush(s, ¶ms.game_data))
1608 .spell("dispatch", SPELL::DISPATCH, |s| spell_dispatch(s, ¶ms.game_data))
1609 .spell(
1610 "between_the_eyes",
1611 SPELL::BETWEEN_THE_EYES,
1612 |s| spell_between_the_eyes(s, ¶ms.game_data),
1613 )
1614 .spell(
1615 "eviscerate",
1616 SPELL::EVISCERATE,
1617 |s| spell_eviscerate(s, ¶ms.game_data),
1618 )
1619 .spell(
1620 "slice_and_dice",
1621 SPELL::SLICE_AND_DICE,
1622 |s| spell_slice_and_dice(s, ¶ms.game_data),
1623 )
1624 .spell(
1625 "instant_poison",
1626 SPELL::INSTANT_POISON,
1627 |s| spell_instant_poison(s, ¶ms.game_data),
1628 )
1629 .spell(
1630 "wound_poison",
1631 SPELL::WOUND_POISON,
1632 |s| spell_wound_poison(s, ¶ms.game_data),
1633 )
1634 .spell(
1635 "atrophic_poison",
1636 SPELL::ATROPHIC_POISON,
1637 |s| spell_atrophic_poison(s, ¶ms.game_data),
1638 )
1639 .spell(
1640 "numbing_poison",
1641 SPELL::NUMBING_POISON,
1642 |s| spell_numbing_poison(s, ¶ms.game_data),
1643 )
1644 .spell(
1645 "crippling_poison",
1646 SPELL::CRIPPLING_POISON,
1647 |s| spell_crippling_poison(s, ¶ms.game_data),
1648 )
1649 .spell(
1650 "main_gauche",
1651 SPELL::MAIN_GAUCHE,
1652 |s| spell_main_gauche(s, ¶ms.game_data),
1653 )
1654 .spell(
1655 "scoundrel_strike",
1656 SPELL::SCOUNDREL_STRIKE,
1657 |s| spell_scoundrel_strike(s, ¶ms.game_data),
1658 )
1659 .spell(
1660 "instant_poison_damage",
1661 SPELL::INSTANT_POISON_DAMAGE,
1662 |s| spell_instant_poison_damage(s, ¶ms.game_data),
1663 )
1664 .spell("kick", SPELL::KICK, |s| spell_kick(s, ¶ms.game_data))
1665 .spell(
1666 "roll_the_bones",
1667 SPELL::ROLL_THE_BONES,
1668 |s| spell_roll_the_bones(s, ¶ms.game_data),
1669 )
1670 .spell(
1671 "adrenaline_rush",
1672 SPELL::ADRENALINE_RUSH,
1673 |s| spell_adrenaline_rush(s, ¶ms.game_data),
1674 )
1675 .spell(
1676 "blade_flurry",
1677 SPELL::BLADE_FLURRY,
1678 |s| spell_blade_flurry(s, ¶ms.game_data),
1679 )
1680 .spell(
1681 "blade_flurry_instant_attack",
1682 SPELL::BLADE_FLURRY_INSTANT_ATTACK,
1683 |s| spell_blade_flurry_instant_attack(s, ¶ms.game_data),
1684 )
1685 .spell(
1686 "blade_rush",
1687 SPELL::BLADE_RUSH,
1688 |s| spell_blade_rush(s, ¶ms.game_data),
1689 )
1690 .spell(
1691 "killing_spree",
1692 SPELL::KILLING_SPREE,
1693 |s| spell_killing_spree(s, ¶ms.game_data),
1694 )
1695 .spell(
1696 "keep_it_rolling",
1697 SPELL::KEEP_IT_ROLLING,
1698 |s| spell_keep_it_rolling(s, ¶ms.game_data),
1699 )
1700 .spell(
1701 "preparation",
1702 SPELL::PREPARATION,
1703 |s| spell_preparation(s, ¶ms.game_data),
1704 )
1705 .spell(
1706 "blade_rush_attack",
1707 SPELL::BLADE_RUSH_ATTACK,
1708 |s| spell_blade_rush_attack(s, ¶ms.game_data),
1709 )
1710 .auto_attack(|a| {
1711 a
1712 .spell_id(6603)
1713 .swing_ms(2600)
1714 .apply_base_from_data(¶ms.game_data)
1715 .on_swing(crate::hooks::outlaw_rogue::swing_hook)
1716 })
1717 .game_data(params.game_data.clone())
1718 .talent_spell_ids(TALENTS)
1719 .talent_selections(params.talent_selections)
1720 .register_impact_effect_proc_if_talent(
1721 TALENT::FATAL_FLOURISH,
1722 wowlab_engine_combat::ImpactEffectProcDefinition::new(
1723 wowlab_engine_combat::ImpactSource::AutoAttack(
1724 wowlab_engine_combat::SwingHand::OffHand,
1725 ),
1726 )
1727 .chance(
1728 (params
1729 .game_data
1730 .base_points(wowlab_types::sim::SpellIdx::from_raw(35551), 1))
1731 / 100.0,
1732 )
1733 .weapon_speed_scaled(2600)
1734 .gain(
1735 params
1736 .game_data
1737 .base_points(wowlab_types::sim::SpellIdx::from_raw(35546), 1),
1738 ),
1739 )
1740 .register_impact_effect_proc_if_talent(
1741 TALENT::FATAL_FLOURISH,
1742 wowlab_engine_combat::ImpactEffectProcDefinition::new(
1743 wowlab_engine_combat::ImpactSource::Spell(SPELL::MAIN_GAUCHE),
1744 )
1745 .chance(
1746 (params
1747 .game_data
1748 .base_points(wowlab_types::sim::SpellIdx::from_raw(35551), 1))
1749 / 100.0,
1750 )
1751 .gain(
1752 params
1753 .game_data
1754 .base_points(wowlab_types::sim::SpellIdx::from_raw(35546), 1),
1755 ),
1756 )
1757 .register_impact_effect_proc_if_talent(
1758 TALENT::FATAL_FLOURISH,
1759 wowlab_engine_combat::ImpactEffectProcDefinition::new(
1760 wowlab_engine_combat::ImpactSource::Spell(SPELL::PISTOL_SHOT),
1761 )
1762 .chance(
1763 (params
1764 .game_data
1765 .base_points(wowlab_types::sim::SpellIdx::from_raw(35551), 1))
1766 / 100.0,
1767 )
1768 .gain(
1769 params
1770 .game_data
1771 .base_points(wowlab_types::sim::SpellIdx::from_raw(35546), 1),
1772 ),
1773 )
1774 .set_bonus_auras(params.set_bonus_auras)
1775 .encounter(params.encounter.clone());
1776 let builder = crate::generated::items::register_equipped(
1777 builder,
1778 ¶ms.game_data,
1779 params.equipped_items,
1780 )?;
1781
1782 builder
1783 .build(params.rotation)
1784 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1785}
1786fn new_handler(
1787 params: wowlab_engine_ports::HandlerParams<'_>,
1788) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1789 let handler = crate::composition::compose_handler(
1790 build_combat_system,
1791 ¶ms,
1792 crate::hooks::outlaw_rogue::OutlawHandler::try_new,
1793 )?;
1794
1795 Ok(Box::new(handler))
1796}
1797static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1798 primary_resource: ResourceType::Energy,
1799 secondary_resource: Some(ResourceType::ComboPoints),
1800 spell_ids: DECLARED_SPELL_IDS,
1801 aura_ids: DECLARED_AURA_IDS,
1802 server_proc_entries: &[],
1803 talents: TALENTS,
1804 rotation_field_schema: &[],
1805 metrics_plugin_id: None,
1806 hero_talent_trees: &[
1807 HeroTalentTreeDesc {
1808 name: "Fatebound",
1809 spells: HERO_TREE_FATEBOUND_SPELLS,
1810 auras: HERO_TREE_FATEBOUND_AURAS,
1811 },
1812 HeroTalentTreeDesc {
1813 name: "Trickster",
1814 spells: HERO_TREE_TRICKSTER_SPELLS,
1815 auras: HERO_TREE_TRICKSTER_AURAS,
1816 },
1817 ],
1818 reported_spells: REPORTED_SPELLS,
1819 masked_passive_effects: &[(452_536, 5), (381_990, 2)],
1820 passive_effect_overrides: &[],
1821};
1822pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1823 spec_id: SpecId::Outlaw,
1824 display_name: "Outlaw Rogue",
1825 metadata: DECLARED_METADATA,
1826 handler_factory: new_handler,
1827};
1828wowlab_engine_combat::smoke_test!(build_combat_system);