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 BACKSTAB: u32 = 53;
16 pub(crate) const SHADOWSTRIKE: u32 = 185_438;
18 pub(crate) const SHURIKEN_STORM: u32 = 197_835;
20 pub(crate) const SHURIKEN_TOSS: u32 = 114_014;
22 pub(crate) const EVISCERATE: u32 = 196_819;
24 pub(crate) const BLACK_POWDER: u32 = 319_175;
26 pub(crate) const SECRET_TECHNIQUE: u32 = 280_719;
28 pub(crate) const GOREMAW_S_BITE: u32 = 426_591;
30 pub(crate) const SLICE_AND_DICE: u32 = 315_496;
32 pub(crate) const INSTANT_POISON: u32 = 315_584;
34 pub(crate) const WOUND_POISON: u32 = 8679;
36 pub(crate) const ATROPHIC_POISON: u32 = 381_637;
38 pub(crate) const NUMBING_POISON: u32 = 5761;
40 pub(crate) const CRIPPLING_POISON: u32 = 3408;
42 pub(crate) const INSTANT_POISON_DAMAGE: u32 = 315_585;
44 pub(crate) const EVISCERATE_BONUS: u32 = 328_082;
46 pub(crate) const BLACK_POWDER_BONUS: u32 = 319_190;
48 pub(crate) const SECRET_TECHNIQUE_PLAYER: u32 = 280_720;
50 pub(crate) const SECRET_TECHNIQUE_CLONES: u32 = 282_449;
52 pub(crate) const LASHE_MACABRE: u32 = 1_264_397;
54 pub(crate) const KICK: u32 = 1766;
56 pub(crate) const SHADOW_DANCE: u32 = 185_313;
58 pub(crate) const SHADOW_BLADES: u32 = 121_471;
60 pub(crate) const SHADOW_BLADES_ATTACK: u32 = 279_043;
62 pub(crate) const BACKSTAB_SHADOW_CLONE: u32 = 1_269_209;
64 pub(crate) const SHADOWSTRIKE_SHADOW_CLONE: u32 = 1_269_336;
66 pub(crate) const EVISCERATE_SHADOW_CLONE: u32 = 1_269_205;
68 pub(crate) const SHURIKEN_STORM_SHADOW_CLONE: u32 = 1_269_340;
70 pub(crate) const SECRET_TECHNIQUE_SHADOW_CLONE: u32 = 1_269_560;
72 pub(crate) const BLACK_POWDER_SHADOW_CLONE: u32 = 1_269_565;
74 pub(crate) const THISTLE_TEA: u32 = 381_623;
76 pub(crate) const VANISH: u32 = 1856;
78}
79pub(crate) mod AURA {
80 pub(crate) const FIND_WEAKNESS: u32 = 1_264_521;
82 pub(crate) const SLICE_AND_DICE: u32 = 315_496;
84 pub(crate) const STEALTH: u32 = 1784;
86 pub(crate) const VANISH: u32 = 1856;
88 pub(crate) const SUBTERFUGE: u32 = 115_192;
90 pub(crate) const SHADOW_TECHNIQUES: u32 = 196_911;
92 pub(crate) const MASTER_OF_SHADOWS: u32 = 196_980;
94 pub(crate) const ALACRITY: u32 = 193_538;
96 pub(crate) const INSTANT_POISON: u32 = 315_584;
98 pub(crate) const WOUND_POISON: u32 = 8679;
100 pub(crate) const ATROPHIC_POISON: u32 = 381_637;
102 pub(crate) const NUMBING_POISON: u32 = 5761;
104 pub(crate) const CRIPPLING_POISON: u32 = 3408;
106 pub(crate) const DEEPER_STRATAGEM: u32 = 193_531;
108 pub(crate) const SECRET_STRATAGEM: u32 = 394_320;
110 pub(crate) const DARKEST_NIGHT: u32 = 457_280;
112 pub(crate) const SHADOW_DANCE: u32 = 185_313;
114 pub(crate) const PREMEDITATION: u32 = 343_173;
116 pub(crate) const SHADOW_BLADES: u32 = 121_471;
118 pub(crate) const ANCIENT_ARTS: u32 = 1_269_163;
120 pub(crate) const ESCALATING_BLADE: u32 = 441_786;
122 pub(crate) const COUP_DE_GRACE: u32 = 441_519;
124 pub(crate) const UNSEEN_BLADE_CD: u32 = 459_485;
126 pub(crate) const FLAWLESS_FORM: u32 = 441_326;
128 pub(crate) const DISORIENTING_STRIKES: u32 = 441_274;
130 pub(crate) const FAZED: u32 = 441_224;
132 pub(crate) const PVP_RULES_ENABLED_HARDCODED: u32 = 134_735;
134}
135pub(crate) mod TALENT {
136 pub(crate) const ALACRITY: u32 = 193_539;
138 pub(crate) const ANCIENT_ARTS_1: u32 = 1_268_932;
140 pub(crate) const ANCIENT_ARTS_2: u32 = 1_268_936;
142 pub(crate) const ANCIENT_ARTS_3: u32 = 1_268_939;
144 pub(crate) const DANSE_MACABRE: u32 = 382_528;
146 pub(crate) const DARK_SHADOW: u32 = 245_687;
148 pub(crate) const DEATH_PERCEPTION: u32 = 469_642;
150 pub(crate) const DEEPENING_SHADOWS: u32 = 185_314;
152 pub(crate) const DEEPER_DAGGERS: u32 = 382_517;
154 pub(crate) const DEEPER_STRATAGEM: u32 = 193_531;
156 pub(crate) const DOUBLE_DANCE: u32 = 394_930;
158 pub(crate) const FINALITY: u32 = 382_525;
160 pub(crate) const FIND_WEAKNESS: u32 = 91023;
162 pub(crate) const FORCED_INDUCTION: u32 = 470_668;
164 pub(crate) const GLOOMBLADE: u32 = 200_758;
166 pub(crate) const GOREMAWS_BITE: u32 = 426_591;
168 pub(crate) const IMPROVED_BACKSTAB: u32 = 319_949;
170 pub(crate) const IMPROVED_SECRET_TECHNIQUE: u32 = 1_279_444;
172 pub(crate) const LETHALITY: u32 = 382_238;
174 pub(crate) const LINGERING_SHADOW: u32 = 382_524;
176 pub(crate) const MASTER_OF_SHADOWS: u32 = 196_976;
178 pub(crate) const PERFORATED_VEINS: u32 = 382_518;
180 pub(crate) const POTENT_POWDER: u32 = 381_634;
182 pub(crate) const PREMEDITATION: u32 = 343_160;
184 pub(crate) const RELENTLESS_STRIKES: u32 = 58423;
186 pub(crate) const REPLICATING_SHADOWS: u32 = 382_506;
188 pub(crate) const SECRET_STRATAGEM: u32 = 394_320;
190 pub(crate) const SHADOWCRAFT: u32 = 426_594;
192 pub(crate) const SHADOWED_FINISHERS: u32 = 382_511;
194 pub(crate) const SHADOW_BLADES: u32 = 121_471;
196 pub(crate) const SILENT_STORM: u32 = 385_722;
198 pub(crate) const SUPERCHARGER: u32 = 470_347;
200 pub(crate) const THE_ROTTEN: u32 = 382_015;
202 pub(crate) const THISTLE_TEA: u32 = 469_779;
204 pub(crate) const UMBRAL_EDGE: u32 = 1_281_468;
206 pub(crate) const VEILTOUCHED: u32 = 382_017;
208 pub(crate) const WEAPONMASTER: u32 = 193_537;
210}
211pub(crate) mod REPORTED_SPELL {
212 pub(crate) const CDG_BONUS_1: u32 = 462_244;
214 pub(crate) const CDG_BONUS_2: u32 = 462_247;
216 pub(crate) const CDG_BONUS_3: u32 = 462_248;
218 pub(crate) const MELEE: u32 = 6603;
220}
221pub(crate) mod HERO {
222 pub(crate) mod TRICKSTER {
223 pub(crate) mod SPELL {
224 pub(crate) const CLEVER_COMBATANT: u32 = 1_276_679;
226 pub(crate) const COUP_DE_GRACE: u32 = 441_423;
228 pub(crate) const COUP_DE_GRACE_DAMAGE_1: u32 = 462_241;
230 pub(crate) const COUP_DE_GRACE_DAMAGE_2: u32 = 462_242;
232 pub(crate) const COUP_DE_GRACE_DAMAGE_3: u32 = 462_243;
234 pub(crate) const DEVIOUS_DISTRACTIONS: u32 = 441_263;
236 pub(crate) const DISORIENTING_STRIKES: u32 = 441_274;
238 pub(crate) const FLASHING_STEEL: u32 = 1_276_630;
240 pub(crate) const FLAWLESS_FORM: u32 = 441_321;
242 pub(crate) const NIMBLE_FLURRY: u32 = 441_367;
244 pub(crate) const SURPRISING_STRIKES: u32 = 441_273;
246 pub(crate) const UNSEEN_BLADE: u32 = 441_144;
248 pub(crate) const UNSEEN_BLADE_TALENT: u32 = 441_146;
250 }
251 }
252 pub(crate) mod DEATHSTALKER {
253 pub(crate) mod SPELL {
254 pub(crate) const DEATHSTALKERS_MARK_DAMAGE: u32 = 457_157;
256 pub(crate) const HUNT_THEM_DOWN: u32 = 457_193;
258 }
259 pub(crate) mod AURA {
260 pub(crate) const DEATHSTALKERS_MARK: u32 = 457_052;
262 pub(crate) const FOLLOW_THE_BLOOD: u32 = 457_068;
264 pub(crate) const LINGERING_DARKNESS: u32 = 457_273;
266 pub(crate) const MOMENTUM_OF_DESPAIR: u32 = 457_284;
268 pub(crate) const SYMBOLIC_VICTORY: u32 = 457_167;
270 pub(crate) const UNSHAKEABLE_DRIVE: u32 = 1_248_774;
272 }
273 }
274}
275static HERO_TREE_TRICKSTER_SPELLS: &[(&str, u32)] = &[
276 ("CLEVER_COMBATANT", 1_276_679),
277 ("COUP_DE_GRACE", 441_423),
278 ("COUP_DE_GRACE_DAMAGE_1", 462_241),
279 ("COUP_DE_GRACE_DAMAGE_2", 462_242),
280 ("COUP_DE_GRACE_DAMAGE_3", 462_243),
281 ("DEVIOUS_DISTRACTIONS", 441_263),
282 ("DISORIENTING_STRIKES", 441_274),
283 ("FLASHING_STEEL", 1_276_630),
284 ("FLAWLESS_FORM", 441_321),
285 ("NIMBLE_FLURRY", 441_367),
286 ("SURPRISING_STRIKES", 441_273),
287 ("UNSEEN_BLADE", 441_144),
288 ("UNSEEN_BLADE_TALENT", 441_146),
289];
290static HERO_TREE_TRICKSTER_AURAS: &[(&str, u32)] = &[];
291static HERO_TREE_DEATHSTALKER_SPELLS: &[(&str, u32)] = &[
292 ("DEATHSTALKERS_MARK_DAMAGE", 457_157),
293 ("HUNT_THEM_DOWN", 457_193),
294];
295static HERO_TREE_DEATHSTALKER_AURAS: &[(&str, u32)] = &[
296 ("DEATHSTALKERS_MARK", 457_052),
297 ("FOLLOW_THE_BLOOD", 457_068),
298 ("LINGERING_DARKNESS", 457_273),
299 ("MOMENTUM_OF_DESPAIR", 457_284),
300 ("SYMBOLIC_VICTORY", 457_167),
301 ("UNSHAKEABLE_DRIVE", 1_248_774),
302];
303pub(crate) const AURA_FIND_WEAKNESS: LocalAuraIdx = LocalAuraIdx::new(0);
304pub(crate) const AURA_SLICE_AND_DICE: LocalAuraIdx = LocalAuraIdx::new(1);
305pub(crate) const AURA_STEALTH: LocalAuraIdx = LocalAuraIdx::new(2);
306pub(crate) const AURA_VANISH: LocalAuraIdx = LocalAuraIdx::new(3);
307pub(crate) const AURA_SUBTERFUGE: LocalAuraIdx = LocalAuraIdx::new(4);
308pub(crate) const AURA_SHADOW_TECHNIQUES: LocalAuraIdx = LocalAuraIdx::new(5);
309pub(crate) const AURA_MASTER_OF_SHADOWS: LocalAuraIdx = LocalAuraIdx::new(6);
310pub(crate) const AURA_ALACRITY: LocalAuraIdx = LocalAuraIdx::new(7);
311pub(crate) const AURA_INSTANT_POISON: LocalAuraIdx = LocalAuraIdx::new(8);
312pub(crate) const AURA_WOUND_POISON: LocalAuraIdx = LocalAuraIdx::new(9);
313pub(crate) const AURA_ATROPHIC_POISON: LocalAuraIdx = LocalAuraIdx::new(10);
314pub(crate) const AURA_NUMBING_POISON: LocalAuraIdx = LocalAuraIdx::new(11);
315pub(crate) const AURA_CRIPPLING_POISON: LocalAuraIdx = LocalAuraIdx::new(12);
316pub(crate) const AURA_DEEPER_STRATAGEM: LocalAuraIdx = LocalAuraIdx::new(13);
317pub(crate) const AURA_SECRET_STRATAGEM: LocalAuraIdx = LocalAuraIdx::new(14);
318pub(crate) const AURA_DARKEST_NIGHT: LocalAuraIdx = LocalAuraIdx::new(15);
319pub(crate) const AURA_SHADOW_DANCE: LocalAuraIdx = LocalAuraIdx::new(16);
320pub(crate) const AURA_PREMEDITATION: LocalAuraIdx = LocalAuraIdx::new(17);
321pub(crate) const AURA_SHADOW_BLADES: LocalAuraIdx = LocalAuraIdx::new(18);
322pub(crate) const AURA_ANCIENT_ARTS: LocalAuraIdx = LocalAuraIdx::new(19);
323pub(crate) const AURA_ESCALATING_BLADE: LocalAuraIdx = LocalAuraIdx::new(20);
324pub(crate) const AURA_COUP_DE_GRACE: LocalAuraIdx = LocalAuraIdx::new(21);
325pub(crate) const AURA_UNSEEN_BLADE_CD: LocalAuraIdx = LocalAuraIdx::new(22);
326pub(crate) const AURA_FLAWLESS_FORM: LocalAuraIdx = LocalAuraIdx::new(23);
327pub(crate) const AURA_DISORIENTING_STRIKES: LocalAuraIdx = LocalAuraIdx::new(24);
328pub(crate) const AURA_FAZED: LocalAuraIdx = LocalAuraIdx::new(25);
329pub(crate) const AURA_PVP_RULES_ENABLED_HARDCODED: LocalAuraIdx = LocalAuraIdx::new(26);
330pub(crate) const AURA_COUNT: usize = 27;
331const _: () = assert!(
332 AURA_COUNT == 27, "AURA index ABI: count changed -- update positional hook consumers"
333);
334pub(crate) const SPELL_BACKSTAB: LocalSpellIdx = LocalSpellIdx::new(0);
335pub(crate) const SPELL_SHADOWSTRIKE: LocalSpellIdx = LocalSpellIdx::new(1);
336pub(crate) const SPELL_SHURIKEN_STORM: LocalSpellIdx = LocalSpellIdx::new(2);
337pub(crate) const SPELL_SHURIKEN_TOSS: LocalSpellIdx = LocalSpellIdx::new(3);
338pub(crate) const SPELL_EVISCERATE: LocalSpellIdx = LocalSpellIdx::new(4);
339pub(crate) const SPELL_BLACK_POWDER: LocalSpellIdx = LocalSpellIdx::new(5);
340pub(crate) const SPELL_SECRET_TECHNIQUE: LocalSpellIdx = LocalSpellIdx::new(6);
341pub(crate) const SPELL_GOREMAW_S_BITE: LocalSpellIdx = LocalSpellIdx::new(7);
342pub(crate) const SPELL_SLICE_AND_DICE: LocalSpellIdx = LocalSpellIdx::new(8);
343pub(crate) const SPELL_INSTANT_POISON: LocalSpellIdx = LocalSpellIdx::new(9);
344pub(crate) const SPELL_WOUND_POISON: LocalSpellIdx = LocalSpellIdx::new(10);
345pub(crate) const SPELL_ATROPHIC_POISON: LocalSpellIdx = LocalSpellIdx::new(11);
346pub(crate) const SPELL_NUMBING_POISON: LocalSpellIdx = LocalSpellIdx::new(12);
347pub(crate) const SPELL_CRIPPLING_POISON: LocalSpellIdx = LocalSpellIdx::new(13);
348pub(crate) const SPELL_INSTANT_POISON_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(14);
349pub(crate) const SPELL_EVISCERATE_BONUS: LocalSpellIdx = LocalSpellIdx::new(15);
350pub(crate) const SPELL_BLACK_POWDER_BONUS: LocalSpellIdx = LocalSpellIdx::new(16);
351pub(crate) const SPELL_SECRET_TECHNIQUE_PLAYER: LocalSpellIdx = LocalSpellIdx::new(17);
352pub(crate) const SPELL_SECRET_TECHNIQUE_CLONES: LocalSpellIdx = LocalSpellIdx::new(18);
353pub(crate) const SPELL_LASHE_MACABRE: LocalSpellIdx = LocalSpellIdx::new(19);
354pub(crate) const SPELL_KICK: LocalSpellIdx = LocalSpellIdx::new(20);
355pub(crate) const SPELL_SHADOW_DANCE: LocalSpellIdx = LocalSpellIdx::new(21);
356pub(crate) const SPELL_SHADOW_BLADES: LocalSpellIdx = LocalSpellIdx::new(22);
357pub(crate) const SPELL_SHADOW_BLADES_ATTACK: LocalSpellIdx = LocalSpellIdx::new(23);
358pub(crate) const SPELL_BACKSTAB_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(24);
359pub(crate) const SPELL_SHADOWSTRIKE_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(25);
360pub(crate) const SPELL_EVISCERATE_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(26);
361pub(crate) const SPELL_SHURIKEN_STORM_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(
362 27,
363);
364pub(crate) const SPELL_SECRET_TECHNIQUE_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(
365 28,
366);
367pub(crate) const SPELL_BLACK_POWDER_SHADOW_CLONE: LocalSpellIdx = LocalSpellIdx::new(29);
368pub(crate) const SPELL_THISTLE_TEA: LocalSpellIdx = LocalSpellIdx::new(30);
369pub(crate) const SPELL_VANISH: LocalSpellIdx = LocalSpellIdx::new(31);
370pub(crate) const SPELL_COUNT: usize = 32;
371const _: () = assert!(
372 SPELL_COUNT == 32,
373 "SPELL index ABI: count changed -- update positional hook consumers"
374);
375pub(crate) mod EFFECT {
376 pub(crate) const ALACRITY_CHANCE_PER_CP: (u32, u8) = (193_539, 2);
378 pub(crate) const ANCIENT_ARTS_1_CLONE: (u32, u8) = (1_268_932, 1);
380 pub(crate) const ANCIENT_ARTS_2_SHT: (u32, u8) = (1_268_936, 1);
382 pub(crate) const BLACK_POWDER_BONUS_COEF: (u32, u8) = (319_190, 1);
384 pub(crate) const CDG_BONUS_1: (u32, u8) = (462_244, 1);
386 pub(crate) const CDG_BONUS_2: (u32, u8) = (462_247, 1);
388 pub(crate) const CDG_BONUS_3: (u32, u8) = (462_248, 1);
390 pub(crate) const CDG_DAMAGE_1: (u32, u8) = (462_241, 1);
392 pub(crate) const CDG_DAMAGE_2: (u32, u8) = (462_242, 1);
394 pub(crate) const CDG_DAMAGE_3: (u32, u8) = (462_243, 1);
396 pub(crate) const CLONE_BACKSTAB: (u32, u8) = (1_269_209, 1);
398 pub(crate) const CLONE_BLACK_POWDER: (u32, u8) = (1_269_565, 1);
400 pub(crate) const CLONE_EVISCERATE: (u32, u8) = (1_269_205, 1);
402 pub(crate) const CLONE_SECRET_TECHNIQUE: (u32, u8) = (1_269_560, 1);
404 pub(crate) const CLONE_SHADOWSTRIKE: (u32, u8) = (1_269_336, 1);
406 pub(crate) const CLONE_SHURIKEN_STORM: (u32, u8) = (1_269_340, 1);
408 pub(crate) const COUP_DE_GRACE_BONUS_CP: (u32, u8) = (441_423, 3);
410 pub(crate) const COUP_DE_GRACE_FLAWLESS: (u32, u8) = (441_423, 2);
412 pub(crate) const DEEPENING_SHADOWS_DURATION: (u32, u8) = (1_271_702, 3);
414 pub(crate) const DISORIENTING_FREE_BLADES: (u32, u8) = (441_274, 2);
416 pub(crate) const DISORIENTING_ST_CDR: (u32, u8) = (441_274, 1);
418 pub(crate) const EVISCERATE_BONUS_COEF: (u32, u8) = (328_082, 1);
420 pub(crate) const EVISCERATE_COEF: (u32, u8) = (196_819, 1);
422 pub(crate) const EXECUTIONER_DIRECT: (u32, u8) = (76808, 1);
424 pub(crate) const EXECUTIONER_PERIODIC: (u32, u8) = (76808, 2);
426 pub(crate) const FIND_WEAKNESS_ARMOR_PEN: (u32, u8) = (1_264_521, 1);
428 pub(crate) const FLASHING_STEEL_CHANCE: (u32, u8) = (1_276_630, 2);
430 pub(crate) const FLASHING_STEEL_WINDOW: (u32, u8) = (1_276_630, 1);
432 pub(crate) const FORCED_INDUCTION_BONUS: (u32, u8) = (470_668, 1);
434 pub(crate) const IMPROVED_SECRET_TECHNIQUE_DMG: (u32, u8) = (1_279_444, 1);
436 pub(crate) const INSTANT_POISON_DAMAGE: (u32, u8) = (315_585, 1);
438 pub(crate) const LASHE_MACABRE_COEF: (u32, u8) = (1_264_397, 1);
440 pub(crate) const PREMEDITATION_CP: (u32, u8) = (343_160, 1);
442 pub(crate) const RELENTLESS_STRIKES_ENERGY: (u32, u8) = (98440, 1);
444 pub(crate) const REPLICATING_SHADOWS_CLONE: (u32, u8) = (382_506, 2);
446 pub(crate) const SECRET_TECHNIQUE_CLONE: (u32, u8) = (282_449, 1);
448 pub(crate) const SECRET_TECHNIQUE_PLAYER: (u32, u8) = (280_720, 1);
450 pub(crate) const SHADOWED_FINISHERS_PCT: (u32, u8) = (382_511, 1);
452 pub(crate) const SHADOW_BLADES_ATTACK: (u32, u8) = (279_043, 1);
454 pub(crate) const SHADOW_BLADES_CP: (u32, u8) = (121_471, 2);
456 pub(crate) const SHADOW_BLADES_ECHO: (u32, u8) = (121_471, 1);
458 pub(crate) const SHT_ENERGIZE: (u32, u8) = (196_911, 2);
460 pub(crate) const SPEC_AURA_PET_DMG: (u32, u8) = (137_035, 3);
462 pub(crate) const SUPERCHARGER_BONUS_CP: (u32, u8) = (470_347, 2);
464 pub(crate) const SUPERCHARGER_CHARGES: (u32, u8) = (470_347, 1);
466 pub(crate) const SURPRISING_STRIKES_CRIT_DMG: (u32, u8) = (441_273, 1);
468 pub(crate) const UMBRAL_EDGE_DMG: (u32, u8) = (1_281_468, 1);
470 pub(crate) const UNSEEN_BLADE_COEF: (u32, u8) = (441_144, 1);
472}
473static REPORTED_SPELLS: &[(&str, u32)] = &[
474 ("cdg_bonus_1", 462_244),
475 ("cdg_bonus_2", 462_247),
476 ("cdg_bonus_3", 462_248),
477 ("melee", 6603),
478];
479static DECLARED_SPELL_IDS: &[u32] = &[
480 53, 185_438, 197_835, 114_014, 196_819, 319_175, 280_719, 426_591, 315_496, 315_584,
481 8679, 381_637, 5761, 3408, 315_585, 328_082, 319_190, 280_720, 282_449, 1_264_397,
482 1766, 185_313, 121_471, 279_043, 1_269_209, 1_269_336, 1_269_205, 1_269_340,
483 1_269_560, 1_269_565, 381_623, 1856, 1_264_521, 315_496, 1784, 1856, 115_192,
484 196_911, 196_980, 193_538, 315_584, 8679, 381_637, 5761, 3408, 193_531, 394_320,
485 457_280, 185_313, 343_173, 121_471, 1_269_163, 441_786, 441_519, 459_485, 441_326,
486 441_274, 441_224, 134_735, 6603, 6603, 76808, 98440, 121_471, 137_035, 193_538,
487 193_539, 196_819, 196_911, 279_043, 280_720, 282_449, 315_585, 319_190, 328_082,
488 343_160, 382_506, 382_511, 441_144, 441_273, 441_274, 441_423, 459_485, 462_241,
489 462_242, 462_243, 462_244, 462_247, 462_248, 470_347, 470_668, 1_264_397, 1_264_521,
490 1_268_932, 1_268_936, 1_269_205, 1_269_209, 1_269_336, 1_269_340, 1_269_560,
491 1_269_565, 1_271_702, 1_276_630, 1_279_444, 1_281_468, 462_244, 462_247, 462_248,
492 6603, 1_276_679, 441_423, 462_241, 462_242, 462_243, 441_263, 441_274, 1_276_630,
493 441_321, 441_367, 441_273, 441_144, 441_146, 457_157, 457_193, 457_052, 457_068,
494 457_273, 457_284, 457_167, 1_248_774,
495];
496static DECLARED_AURA_IDS: &[u32] = &[
497 1_264_521, 315_496, 1784, 1856, 115_192, 196_911, 196_980, 193_538, 315_584, 8679,
498 381_637, 5761, 3408, 193_531, 394_320, 457_280, 185_313, 343_173, 121_471, 1_269_163,
499 441_786, 441_519, 459_485, 441_326, 441_274, 441_224, 134_735, 457_052, 457_068,
500 457_273, 457_284, 457_167, 1_248_774,
501];
502static TALENTS: &[(&str, u32)] = &[
503 ("ALACRITY", TALENT::ALACRITY),
504 ("ANCIENT_ARTS_1", TALENT::ANCIENT_ARTS_1),
505 ("ANCIENT_ARTS_2", TALENT::ANCIENT_ARTS_2),
506 ("ANCIENT_ARTS_3", TALENT::ANCIENT_ARTS_3),
507 ("DANSE_MACABRE", TALENT::DANSE_MACABRE),
508 ("DARK_SHADOW", TALENT::DARK_SHADOW),
509 ("DEATH_PERCEPTION", TALENT::DEATH_PERCEPTION),
510 ("DEEPENING_SHADOWS", TALENT::DEEPENING_SHADOWS),
511 ("DEEPER_DAGGERS", TALENT::DEEPER_DAGGERS),
512 ("DEEPER_STRATAGEM", TALENT::DEEPER_STRATAGEM),
513 ("DOUBLE_DANCE", TALENT::DOUBLE_DANCE),
514 ("FINALITY", TALENT::FINALITY),
515 ("FIND_WEAKNESS", TALENT::FIND_WEAKNESS),
516 ("FORCED_INDUCTION", TALENT::FORCED_INDUCTION),
517 ("GLOOMBLADE", TALENT::GLOOMBLADE),
518 ("GOREMAWS_BITE", TALENT::GOREMAWS_BITE),
519 ("IMPROVED_BACKSTAB", TALENT::IMPROVED_BACKSTAB),
520 ("IMPROVED_SECRET_TECHNIQUE", TALENT::IMPROVED_SECRET_TECHNIQUE),
521 ("LETHALITY", TALENT::LETHALITY),
522 ("LINGERING_SHADOW", TALENT::LINGERING_SHADOW),
523 ("MASTER_OF_SHADOWS", TALENT::MASTER_OF_SHADOWS),
524 ("PERFORATED_VEINS", TALENT::PERFORATED_VEINS),
525 ("POTENT_POWDER", TALENT::POTENT_POWDER),
526 ("PREMEDITATION", TALENT::PREMEDITATION),
527 ("RELENTLESS_STRIKES", TALENT::RELENTLESS_STRIKES),
528 ("REPLICATING_SHADOWS", TALENT::REPLICATING_SHADOWS),
529 ("SECRET_STRATAGEM", TALENT::SECRET_STRATAGEM),
530 ("SHADOWCRAFT", TALENT::SHADOWCRAFT),
531 ("SHADOWED_FINISHERS", TALENT::SHADOWED_FINISHERS),
532 ("SHADOW_BLADES", TALENT::SHADOW_BLADES),
533 ("SILENT_STORM", TALENT::SILENT_STORM),
534 ("SUPERCHARGER", TALENT::SUPERCHARGER),
535 ("THE_ROTTEN", TALENT::THE_ROTTEN),
536 ("THISTLE_TEA", TALENT::THISTLE_TEA),
537 ("UMBRAL_EDGE", TALENT::UMBRAL_EDGE),
538 ("VEILTOUCHED", TALENT::VEILTOUCHED),
539 ("WEAPONMASTER", TALENT::WEAPONMASTER),
540];
541pub(crate) mod SUBTLETY_ROGUE {
542 pub(crate) const BACKSTAB_CASTS: u32 = 0;
543 pub(crate) const SHADOWSTRIKE_CASTS: u32 = 1;
544 pub(crate) const EVISCERATE_CASTS: u32 = 2;
545 pub(crate) const BLACK_POWDER_CASTS: u32 = 3;
546 pub(crate) const SECRET_TECHNIQUE_CASTS: u32 = 4;
547 pub(crate) const SHADOW_BLADES_CASTS: u32 = 5;
548 pub(crate) const SHADOW_DANCE_CASTS: u32 = 6;
549 pub(crate) const GOREMAWS_BITE_CASTS: u32 = 7;
550 pub(crate) const SHADOW_DANCE_UPTIME_MS: u32 = 8;
551 pub(crate) const SHADOW_BLADES_UPTIME_MS: u32 = 9;
552 pub(crate) const FIND_WEAKNESS_UPTIME_MS: u32 = 10;
553}
554fn aura_find_weakness(
555 a: AuraDefinitionDraft,
556 data: &ResolvedGameData,
557) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
558 Ok(
559 a
560 .on_player()
561 .apply_base_from_data(data, 1_264_521)?
562 .max_stacks(
563 data
564 .require_aura_max_stacks(
565 wowlab_types::sim::SpellIdx::from_raw(1_264_521),
566 )?,
567 ),
568 )
569}
570fn aura_slice_and_dice(
571 a: AuraDefinitionDraft,
572 data: &ResolvedGameData,
573) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
574 Ok(
575 a
576 .on_player()
577 .apply_base_from_data(data, 315_496)?
578 .max_stacks(
579 data
580 .require_aura_max_stacks(
581 wowlab_types::sim::SpellIdx::from_raw(315_496),
582 )?,
583 ),
584 )
585}
586fn aura_stealth(
587 a: AuraDefinitionDraft,
588 data: &ResolvedGameData,
589) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
590 Ok(
591 a
592 .on_player()
593 .apply_base_from_data(data, 1784)?
594 .max_stacks(
595 data
596 .require_aura_max_stacks(
597 wowlab_types::sim::SpellIdx::from_raw(1784),
598 )?,
599 ),
600 )
601}
602fn aura_vanish(
603 a: AuraDefinitionDraft,
604 data: &ResolvedGameData,
605) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
606 Ok(
607 a
608 .on_player()
609 .apply_base_from_data(data, 1856)?
610 .max_stacks(
611 data
612 .require_aura_max_stacks(
613 wowlab_types::sim::SpellIdx::from_raw(1856),
614 )?,
615 ),
616 )
617}
618fn aura_subterfuge(
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, 115_192)?
626 .max_stacks(
627 data
628 .require_aura_max_stacks(
629 wowlab_types::sim::SpellIdx::from_raw(115_192),
630 )?,
631 ),
632 )
633}
634fn aura_shadow_techniques(
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, 196_911)?
642 .max_stacks(
643 data
644 .require_aura_max_stacks(
645 wowlab_types::sim::SpellIdx::from_raw(196_911),
646 )?,
647 ),
648 )
649}
650fn aura_master_of_shadows(
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, 196_980)?
658 .max_stacks(
659 data
660 .require_aura_max_stacks(
661 wowlab_types::sim::SpellIdx::from_raw(196_980),
662 )?,
663 ),
664 )
665}
666fn aura_alacrity(
667 a: AuraDefinitionDraft,
668 data: &ResolvedGameData,
669) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
670 a.on_player()
671 .apply_base_from_data(data, 193_538)?
672 .max_stacks(
673 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(193_538))?,
674 )
675 .haste_per_stack(
676 data.base_points(wowlab_types::sim::SpellIdx::from_raw(193_538), 1),
677 )
678}
679fn aura_instant_poison(
680 a: AuraDefinitionDraft,
681 data: &ResolvedGameData,
682) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
683 Ok(
684 a
685 .on_player()
686 .apply_base_from_data(data, 315_584)?
687 .max_stacks(
688 data
689 .require_aura_max_stacks(
690 wowlab_types::sim::SpellIdx::from_raw(315_584),
691 )?,
692 )
693 .spell_group(0, wowlab_types::combat::SpellGroupRule::Exclusive),
694 )
695}
696fn aura_wound_poison(
697 a: AuraDefinitionDraft,
698 data: &ResolvedGameData,
699) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
700 Ok(
701 a
702 .on_player()
703 .apply_base_from_data(data, 8679)?
704 .max_stacks(
705 data
706 .require_aura_max_stacks(
707 wowlab_types::sim::SpellIdx::from_raw(8679),
708 )?,
709 )
710 .spell_group(0, wowlab_types::combat::SpellGroupRule::Exclusive),
711 )
712}
713fn aura_atrophic_poison(
714 a: AuraDefinitionDraft,
715 data: &ResolvedGameData,
716) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
717 Ok(
718 a
719 .on_player()
720 .apply_base_from_data(data, 381_637)?
721 .max_stacks(
722 data
723 .require_aura_max_stacks(
724 wowlab_types::sim::SpellIdx::from_raw(381_637),
725 )?,
726 )
727 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
728 )
729}
730fn aura_numbing_poison(
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, 5761)?
738 .max_stacks(
739 data
740 .require_aura_max_stacks(
741 wowlab_types::sim::SpellIdx::from_raw(5761),
742 )?,
743 )
744 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
745 )
746}
747fn aura_crippling_poison(
748 a: AuraDefinitionDraft,
749 data: &ResolvedGameData,
750) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
751 Ok(
752 a
753 .on_player()
754 .apply_base_from_data(data, 3408)?
755 .max_stacks(
756 data
757 .require_aura_max_stacks(
758 wowlab_types::sim::SpellIdx::from_raw(3408),
759 )?,
760 )
761 .spell_group(1, wowlab_types::combat::SpellGroupRule::Exclusive),
762 )
763}
764fn aura_deeper_stratagem(
765 a: AuraDefinitionDraft,
766 data: &ResolvedGameData,
767) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
768 Ok(
769 a
770 .on_player()
771 .apply_base_from_data(data, 193_531)?
772 .max_stacks(
773 data
774 .require_aura_max_stacks(
775 wowlab_types::sim::SpellIdx::from_raw(193_531),
776 )?,
777 ),
778 )
779}
780fn aura_secret_stratagem(
781 a: AuraDefinitionDraft,
782 data: &ResolvedGameData,
783) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
784 Ok(
785 a
786 .on_player()
787 .apply_base_from_data(data, 394_320)?
788 .max_stacks(
789 data
790 .require_aura_max_stacks(
791 wowlab_types::sim::SpellIdx::from_raw(394_320),
792 )?,
793 ),
794 )
795}
796fn aura_darkest_night(
797 a: AuraDefinitionDraft,
798 data: &ResolvedGameData,
799) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
800 Ok(
801 a
802 .on_player()
803 .apply_base_from_data(data, 457_280)?
804 .max_stacks(
805 data
806 .require_aura_max_stacks(
807 wowlab_types::sim::SpellIdx::from_raw(457_280),
808 )?,
809 ),
810 )
811}
812fn aura_shadow_dance(
813 a: AuraDefinitionDraft,
814 data: &ResolvedGameData,
815) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
816 Ok(
817 a
818 .on_player()
819 .apply_base_from_data(data, 185_313)?
820 .max_stacks(
821 data
822 .require_aura_max_stacks(
823 wowlab_types::sim::SpellIdx::from_raw(185_313),
824 )?,
825 ),
826 )
827}
828fn aura_premeditation(
829 a: AuraDefinitionDraft,
830 data: &ResolvedGameData,
831) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
832 Ok(
833 a
834 .on_player()
835 .apply_base_from_data(data, 343_173)?
836 .max_stacks(
837 data
838 .require_aura_max_stacks(
839 wowlab_types::sim::SpellIdx::from_raw(343_173),
840 )?,
841 ),
842 )
843}
844fn aura_shadow_blades(
845 a: AuraDefinitionDraft,
846 data: &ResolvedGameData,
847) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
848 Ok(
849 a
850 .on_player()
851 .apply_base_from_data(data, 121_471)?
852 .max_stacks(
853 data
854 .require_aura_max_stacks(
855 wowlab_types::sim::SpellIdx::from_raw(121_471),
856 )?,
857 ),
858 )
859}
860fn aura_ancient_arts(
861 a: AuraDefinitionDraft,
862 data: &ResolvedGameData,
863) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
864 Ok(
865 a
866 .on_player()
867 .apply_base_from_data(data, 1_269_163)?
868 .max_stacks(
869 data
870 .require_aura_max_stacks(
871 wowlab_types::sim::SpellIdx::from_raw(1_269_163),
872 )?,
873 ),
874 )
875}
876fn aura_escalating_blade(
877 a: AuraDefinitionDraft,
878 data: &ResolvedGameData,
879) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
880 Ok(
881 a
882 .on_player()
883 .apply_base_from_data(data, 441_786)?
884 .max_stacks(
885 data
886 .require_aura_max_stacks(
887 wowlab_types::sim::SpellIdx::from_raw(441_786),
888 )?,
889 ),
890 )
891}
892fn aura_coup_de_grace(
893 a: AuraDefinitionDraft,
894 data: &ResolvedGameData,
895) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
896 Ok(
897 a
898 .on_player()
899 .apply_base_from_data(data, 441_519)?
900 .max_stacks(
901 data
902 .require_aura_max_stacks(
903 wowlab_types::sim::SpellIdx::from_raw(441_519),
904 )?,
905 ),
906 )
907}
908fn aura_unseen_blade_cd(
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, 459_485)?
916 .max_stacks(
917 data
918 .require_aura_max_stacks(
919 wowlab_types::sim::SpellIdx::from_raw(459_485),
920 )?,
921 ),
922 )
923}
924fn aura_flawless_form(
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, 441_326)?
932 .max_stacks(
933 data
934 .require_aura_max_stacks(
935 wowlab_types::sim::SpellIdx::from_raw(441_326),
936 )?,
937 ),
938 )
939}
940fn aura_disorienting_strikes(
941 a: AuraDefinitionDraft,
942 data: &ResolvedGameData,
943) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
944 a.on_player()
945 .duration_ms(
946 wowlab_engine_combat::validated_milliseconds(
947 (((f64::from(
948 data
949 .require_aura_duration_ms(
950 wowlab_types::sim::SpellIdx::from_raw(459_485),
951 )?,
952 )) * 1.333_333_333_333_333_3) * 1.0)
953 .round() / 1.0,
954 441_274,
955 "aura.duration_ms",
956 )?,
957 )
958 .apply_periodic_effect_from_data(data, 441_274)?
959 .apply_duration_behavior_from_data(data, 459_485)?
960 .apply_timing_modifiers_from_data(data, 441_274)?
961 .max_stacks(
962 wowlab_engine_combat::validated_max_stacks(2.0, 441_274, "aura.max_stacks")?,
963 )
964 .apply_periodic_behavior_from_data(data, 459_485)
965}
966fn aura_fazed(
967 a: AuraDefinitionDraft,
968 data: &ResolvedGameData,
969) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
970 Ok(
971 a
972 .on_target()
973 .apply_base_from_data(data, 441_224)?
974 .max_stacks(
975 data
976 .require_aura_max_stacks(
977 wowlab_types::sim::SpellIdx::from_raw(441_224),
978 )?,
979 ),
980 )
981}
982fn aura_pvp_rules_enabled_hardcoded(
983 a: AuraDefinitionDraft,
984 data: &ResolvedGameData,
985) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
986 Ok(
987 a
988 .on_player()
989 .apply_base_from_data(data, 134_735)?
990 .max_stacks(
991 data
992 .require_aura_max_stacks(
993 wowlab_types::sim::SpellIdx::from_raw(134_735),
994 )?,
995 ),
996 )
997}
998fn spell_backstab(
999 s: SpellDefinitionDraft,
1000 data: &ResolvedGameData,
1001) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1002 Ok(
1003 s
1004 .apply_base_from_data(data, 53)?
1005 .apply_aoe_from_data(data)
1006 .on_cast(crate::hooks::subtlety_rogue::backstab_hook),
1007 )
1008}
1009fn spell_shadowstrike(
1010 s: SpellDefinitionDraft,
1011 data: &ResolvedGameData,
1012) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1013 Ok(
1014 s
1015 .apply_base_from_data(data, 185_438)?
1016 .no_stealth_break()
1017 .apply_aoe_from_data(data)
1018 .on_cast(crate::hooks::subtlety_rogue::shadowstrike_hook),
1019 )
1020}
1021fn spell_shuriken_storm(
1022 s: SpellDefinitionDraft,
1023 data: &ResolvedGameData,
1024) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1025 Ok(
1026 s
1027 .apply_base_from_data(data, 197_835)?
1028 .apply_aoe_from_data(data)
1029 .on_cast(crate::hooks::subtlety_rogue::shuriken_storm_hook),
1030 )
1031}
1032fn spell_shuriken_toss(
1033 s: SpellDefinitionDraft,
1034 data: &ResolvedGameData,
1035) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1036 Ok(s.apply_base_from_data(data, 114_014)?.apply_aoe_from_data(data))
1037}
1038fn spell_eviscerate(
1039 s: SpellDefinitionDraft,
1040 data: &ResolvedGameData,
1041) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1042 Ok(
1043 s
1044 .apply_base_from_data(data, 196_819)?
1045 .apply_aoe_from_data(data)
1046 .on_cast(crate::hooks::subtlety_rogue::eviscerate_hook),
1047 )
1048}
1049fn spell_black_powder(
1050 s: SpellDefinitionDraft,
1051 data: &ResolvedGameData,
1052) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1053 Ok(
1054 s
1055 .apply_base_from_data(data, 319_175)?
1056 .apply_aoe_from_data(data)
1057 .on_cast(crate::hooks::subtlety_rogue::black_powder_hook),
1058 )
1059}
1060fn spell_secret_technique(
1061 s: SpellDefinitionDraft,
1062 data: &ResolvedGameData,
1063) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1064 Ok(
1065 s
1066 .apply_base_from_data(data, 280_719)?
1067 .apply_aoe_from_data(data)
1068 .on_cast(crate::hooks::subtlety_rogue::secret_technique_hook),
1069 )
1070}
1071fn spell_goremaw_s_bite(
1072 s: SpellDefinitionDraft,
1073 data: &ResolvedGameData,
1074) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1075 Ok(s.apply_base_from_data(data, 426_591)?.apply_aoe_from_data(data))
1076}
1077fn spell_slice_and_dice(
1078 s: SpellDefinitionDraft,
1079 data: &ResolvedGameData,
1080) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1081 Ok(
1082 s
1083 .apply_base_from_data(data, 315_496)?
1084 .applies_inferred_aura(AURA_SLICE_AND_DICE, 315_496)
1085 .apply_aoe_from_data(data),
1086 )
1087}
1088fn spell_instant_poison(
1089 s: SpellDefinitionDraft,
1090 data: &ResolvedGameData,
1091) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1092 Ok(
1093 s
1094 .apply_base_from_data(data, 315_584)?
1095 .applies_inferred_aura(AURA_INSTANT_POISON, 315_584)
1096 .apply_aoe_from_data(data),
1097 )
1098}
1099fn spell_wound_poison(
1100 s: SpellDefinitionDraft,
1101 data: &ResolvedGameData,
1102) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1103 Ok(
1104 s
1105 .apply_base_from_data(data, 8679)?
1106 .applies_inferred_aura(AURA_WOUND_POISON, 8679)
1107 .apply_aoe_from_data(data),
1108 )
1109}
1110fn spell_atrophic_poison(
1111 s: SpellDefinitionDraft,
1112 data: &ResolvedGameData,
1113) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1114 Ok(
1115 s
1116 .apply_base_from_data(data, 381_637)?
1117 .applies_inferred_aura(AURA_ATROPHIC_POISON, 381_637)
1118 .apply_aoe_from_data(data),
1119 )
1120}
1121fn spell_numbing_poison(
1122 s: SpellDefinitionDraft,
1123 data: &ResolvedGameData,
1124) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1125 Ok(
1126 s
1127 .apply_base_from_data(data, 5761)?
1128 .applies_inferred_aura(AURA_NUMBING_POISON, 5761)
1129 .apply_aoe_from_data(data),
1130 )
1131}
1132fn spell_crippling_poison(
1133 s: SpellDefinitionDraft,
1134 data: &ResolvedGameData,
1135) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1136 Ok(
1137 s
1138 .apply_base_from_data(data, 3408)?
1139 .applies_inferred_aura(AURA_CRIPPLING_POISON, 3408)
1140 .apply_aoe_from_data(data),
1141 )
1142}
1143fn spell_instant_poison_damage(
1144 s: SpellDefinitionDraft,
1145 data: &ResolvedGameData,
1146) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1147 Ok(s.apply_base_from_data(data, 315_585)?.apply_aoe_from_data(data))
1148}
1149fn spell_eviscerate_bonus(
1150 s: SpellDefinitionDraft,
1151 data: &ResolvedGameData,
1152) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1153 Ok(s.apply_base_from_data(data, 328_082)?.apply_aoe_from_data(data))
1154}
1155fn spell_black_powder_bonus(
1156 s: SpellDefinitionDraft,
1157 data: &ResolvedGameData,
1158) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1159 Ok(s.apply_base_from_data(data, 319_190)?.apply_aoe_from_data(data))
1160}
1161fn spell_secret_technique_player(
1162 s: SpellDefinitionDraft,
1163 data: &ResolvedGameData,
1164) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1165 Ok(s.apply_base_from_data(data, 280_720)?.apply_aoe_from_data(data))
1166}
1167fn spell_secret_technique_clones(
1168 s: SpellDefinitionDraft,
1169 data: &ResolvedGameData,
1170) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1171 Ok(s.apply_base_from_data(data, 282_449)?.apply_aoe_from_data(data))
1172}
1173fn spell_lashe_macabre(
1174 s: SpellDefinitionDraft,
1175 data: &ResolvedGameData,
1176) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1177 Ok(s.apply_base_from_data(data, 1_264_397)?.apply_aoe_from_data(data))
1178}
1179fn spell_kick(
1180 s: SpellDefinitionDraft,
1181 data: &ResolvedGameData,
1182) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1183 Ok(s.apply_base_from_data(data, 1766)?.apply_aoe_from_data(data))
1184}
1185fn spell_shadow_dance(
1186 s: SpellDefinitionDraft,
1187 data: &ResolvedGameData,
1188) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1189 Ok(
1190 s
1191 .apply_base_from_data(data, 185_313)?
1192 .applies_aura(AURA_SHADOW_DANCE)
1193 .no_stealth_break()
1194 .apply_aoe_from_data(data)
1195 .on_cast(crate::hooks::subtlety_rogue::shadow_dance_hook),
1196 )
1197}
1198fn spell_shadow_blades(
1199 s: SpellDefinitionDraft,
1200 data: &ResolvedGameData,
1201) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1202 Ok(
1203 s
1204 .apply_base_from_data(data, 121_471)?
1205 .applies_inferred_aura(AURA_SHADOW_BLADES, 121_471)
1206 .no_stealth_break()
1207 .apply_aoe_from_data(data)
1208 .on_cast(crate::hooks::subtlety_rogue::shadow_blades_hook),
1209 )
1210}
1211fn spell_shadow_blades_attack(
1212 s: SpellDefinitionDraft,
1213 data: &ResolvedGameData,
1214) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1215 Ok(s.apply_base_from_data(data, 279_043)?.apply_aoe_from_data(data))
1216}
1217fn spell_backstab_shadow_clone(
1218 s: SpellDefinitionDraft,
1219 data: &ResolvedGameData,
1220) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1221 Ok(s.apply_base_from_data(data, 1_269_209)?.apply_aoe_from_data(data))
1222}
1223fn spell_shadowstrike_shadow_clone(
1224 s: SpellDefinitionDraft,
1225 data: &ResolvedGameData,
1226) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1227 Ok(s.apply_base_from_data(data, 1_269_336)?.apply_aoe_from_data(data))
1228}
1229fn spell_eviscerate_shadow_clone(
1230 s: SpellDefinitionDraft,
1231 data: &ResolvedGameData,
1232) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1233 Ok(s.apply_base_from_data(data, 1_269_205)?.apply_aoe_from_data(data))
1234}
1235fn spell_shuriken_storm_shadow_clone(
1236 s: SpellDefinitionDraft,
1237 data: &ResolvedGameData,
1238) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1239 Ok(s.apply_base_from_data(data, 1_269_340)?.apply_aoe_from_data(data))
1240}
1241fn spell_secret_technique_shadow_clone(
1242 s: SpellDefinitionDraft,
1243 data: &ResolvedGameData,
1244) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1245 Ok(s.apply_base_from_data(data, 1_269_560)?.apply_aoe_from_data(data))
1246}
1247fn spell_black_powder_shadow_clone(
1248 s: SpellDefinitionDraft,
1249 data: &ResolvedGameData,
1250) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1251 Ok(s.apply_base_from_data(data, 1_269_565)?.apply_aoe_from_data(data))
1252}
1253fn spell_thistle_tea(
1254 s: SpellDefinitionDraft,
1255 data: &ResolvedGameData,
1256) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1257 Ok(
1258 s
1259 .apply_base_from_data(data, 381_623)?
1260 .no_stealth_break()
1261 .apply_aoe_from_data(data),
1262 )
1263}
1264fn spell_vanish(
1265 s: SpellDefinitionDraft,
1266 data: &ResolvedGameData,
1267) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1268 Ok(
1269 s
1270 .apply_base_from_data(data, 1856)?
1271 .applies_aura(AURA_STEALTH)
1272 .no_stealth_break()
1273 .apply_aoe_from_data(data),
1274 )
1275}
1276pub(crate) fn build_combat_system(
1277 params: &wowlab_engine_ports::HandlerParams<'_>,
1278) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1279 let builder = BuiltCombatSystem::builder(params.stats.clone())
1280 .spec_id(SpecId::Subtlety)
1281 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1282 .mastery_spell(76808)
1283 .mastery_hook(crate::hooks::subtlety_rogue::mastery)
1284 .resource(
1285 "energy",
1286 params
1287 .game_data
1288 .power_max(3)
1289 .ok_or_else(|| {
1290 wowlab_engine_ports::EngineError::spec_construction(
1291 "missing power-type power_max for type_id 3",
1292 )
1293 })?,
1294 params
1295 .game_data
1296 .power_regen_for_max(
1297 3,
1298 params
1299 .game_data
1300 .power_max(3)
1301 .ok_or_else(|| {
1302 wowlab_engine_ports::EngineError::spec_construction(
1303 "missing power-type power_max for type_id 3",
1304 )
1305 })?,
1306 )
1307 .ok_or_else(|| {
1308 wowlab_engine_ports::EngineError::spec_construction(
1309 "missing power-type power_regen_for_max for type_id 3",
1310 )
1311 })?,
1312 )
1313 .resource_type_id(3)
1314 .resource_start(
1315 params
1316 .game_data
1317 .power_default(3)
1318 .ok_or_else(|| {
1319 wowlab_engine_ports::EngineError::spec_construction(
1320 "missing power-type power_default for type_id 3",
1321 )
1322 })?,
1323 )
1324 .mastery_crit_damage_hook(crate::hooks::subtlety_rogue::crit_damage)
1325 .secondary_resource(
1326 "combo_points",
1327 params
1328 .game_data
1329 .power_max(4)
1330 .ok_or_else(|| {
1331 wowlab_engine_ports::EngineError::spec_construction(
1332 "missing power-type power_max for type_id 4",
1333 )
1334 })?,
1335 )
1336 .secondary_resource_type_id(4)
1337 .precombat_aura(AURA_STEALTH)
1338 .precombat_aura(AURA_INSTANT_POISON)
1339 .precombat_aura(AURA_ATROPHIC_POISON)
1340 .stealth_aura(AURA::STEALTH)
1341 .aura(
1342 "find_weakness",
1343 AURA::FIND_WEAKNESS,
1344 |a| aura_find_weakness(a, ¶ms.game_data),
1345 )
1346 .aura(
1347 "slice_and_dice",
1348 AURA::SLICE_AND_DICE,
1349 |a| aura_slice_and_dice(a, ¶ms.game_data),
1350 )
1351 .aura("stealth", AURA::STEALTH, |a| aura_stealth(a, ¶ms.game_data))
1352 .aura("vanish", AURA::VANISH, |a| aura_vanish(a, ¶ms.game_data))
1353 .aura("subterfuge", AURA::SUBTERFUGE, |a| aura_subterfuge(a, ¶ms.game_data))
1354 .aura(
1355 "shadow_techniques",
1356 AURA::SHADOW_TECHNIQUES,
1357 |a| aura_shadow_techniques(a, ¶ms.game_data),
1358 )
1359 .aura(
1360 "master_of_shadows",
1361 AURA::MASTER_OF_SHADOWS,
1362 |a| aura_master_of_shadows(a, ¶ms.game_data),
1363 )
1364 .aura("alacrity", AURA::ALACRITY, |a| aura_alacrity(a, ¶ms.game_data))
1365 .aura(
1366 "instant_poison",
1367 AURA::INSTANT_POISON,
1368 |a| aura_instant_poison(a, ¶ms.game_data),
1369 )
1370 .aura(
1371 "wound_poison",
1372 AURA::WOUND_POISON,
1373 |a| aura_wound_poison(a, ¶ms.game_data),
1374 )
1375 .aura(
1376 "atrophic_poison",
1377 AURA::ATROPHIC_POISON,
1378 |a| aura_atrophic_poison(a, ¶ms.game_data),
1379 )
1380 .aura(
1381 "numbing_poison",
1382 AURA::NUMBING_POISON,
1383 |a| aura_numbing_poison(a, ¶ms.game_data),
1384 )
1385 .aura(
1386 "crippling_poison",
1387 AURA::CRIPPLING_POISON,
1388 |a| aura_crippling_poison(a, ¶ms.game_data),
1389 )
1390 .aura(
1391 "deeper_stratagem",
1392 AURA::DEEPER_STRATAGEM,
1393 |a| aura_deeper_stratagem(a, ¶ms.game_data),
1394 )
1395 .aura(
1396 "secret_stratagem",
1397 AURA::SECRET_STRATAGEM,
1398 |a| aura_secret_stratagem(a, ¶ms.game_data),
1399 )
1400 .aura(
1401 "darkest_night",
1402 AURA::DARKEST_NIGHT,
1403 |a| aura_darkest_night(a, ¶ms.game_data),
1404 )
1405 .aura(
1406 "shadow_dance",
1407 AURA::SHADOW_DANCE,
1408 |a| aura_shadow_dance(a, ¶ms.game_data),
1409 )
1410 .aura(
1411 "premeditation",
1412 AURA::PREMEDITATION,
1413 |a| aura_premeditation(a, ¶ms.game_data),
1414 )
1415 .aura(
1416 "shadow_blades",
1417 AURA::SHADOW_BLADES,
1418 |a| aura_shadow_blades(a, ¶ms.game_data),
1419 )
1420 .aura(
1421 "ancient_arts",
1422 AURA::ANCIENT_ARTS,
1423 |a| aura_ancient_arts(a, ¶ms.game_data),
1424 )
1425 .aura(
1426 "escalating_blade",
1427 AURA::ESCALATING_BLADE,
1428 |a| aura_escalating_blade(a, ¶ms.game_data),
1429 )
1430 .aura(
1431 "coup_de_grace",
1432 AURA::COUP_DE_GRACE,
1433 |a| aura_coup_de_grace(a, ¶ms.game_data),
1434 )
1435 .aura(
1436 "unseen_blade_cd",
1437 AURA::UNSEEN_BLADE_CD,
1438 |a| aura_unseen_blade_cd(a, ¶ms.game_data),
1439 )
1440 .aura(
1441 "flawless_form",
1442 AURA::FLAWLESS_FORM,
1443 |a| aura_flawless_form(a, ¶ms.game_data),
1444 )
1445 .aura(
1446 "disorienting_strikes",
1447 AURA::DISORIENTING_STRIKES,
1448 |a| aura_disorienting_strikes(a, ¶ms.game_data),
1449 )
1450 .aura("fazed", AURA::FAZED, |a| aura_fazed(a, ¶ms.game_data))
1451 .aura(
1452 "pvp_rules_enabled_hardcoded",
1453 AURA::PVP_RULES_ENABLED_HARDCODED,
1454 |a| aura_pvp_rules_enabled_hardcoded(a, ¶ms.game_data),
1455 )
1456 .spell("backstab", SPELL::BACKSTAB, |s| spell_backstab(s, ¶ms.game_data))
1457 .spell(
1458 "shadowstrike",
1459 SPELL::SHADOWSTRIKE,
1460 |s| spell_shadowstrike(s, ¶ms.game_data),
1461 )
1462 .spell(
1463 "shuriken_storm",
1464 SPELL::SHURIKEN_STORM,
1465 |s| spell_shuriken_storm(s, ¶ms.game_data),
1466 )
1467 .spell(
1468 "shuriken_toss",
1469 SPELL::SHURIKEN_TOSS,
1470 |s| spell_shuriken_toss(s, ¶ms.game_data),
1471 )
1472 .spell(
1473 "eviscerate",
1474 SPELL::EVISCERATE,
1475 |s| spell_eviscerate(s, ¶ms.game_data),
1476 )
1477 .spell(
1478 "black_powder",
1479 SPELL::BLACK_POWDER,
1480 |s| spell_black_powder(s, ¶ms.game_data),
1481 )
1482 .spell(
1483 "secret_technique",
1484 SPELL::SECRET_TECHNIQUE,
1485 |s| spell_secret_technique(s, ¶ms.game_data),
1486 )
1487 .spell(
1488 "goremaws_bite",
1489 SPELL::GOREMAW_S_BITE,
1490 |s| spell_goremaw_s_bite(s, ¶ms.game_data),
1491 )
1492 .spell(
1493 "slice_and_dice",
1494 SPELL::SLICE_AND_DICE,
1495 |s| spell_slice_and_dice(s, ¶ms.game_data),
1496 )
1497 .spell(
1498 "instant_poison",
1499 SPELL::INSTANT_POISON,
1500 |s| spell_instant_poison(s, ¶ms.game_data),
1501 )
1502 .spell(
1503 "wound_poison",
1504 SPELL::WOUND_POISON,
1505 |s| spell_wound_poison(s, ¶ms.game_data),
1506 )
1507 .spell(
1508 "atrophic_poison",
1509 SPELL::ATROPHIC_POISON,
1510 |s| spell_atrophic_poison(s, ¶ms.game_data),
1511 )
1512 .spell(
1513 "numbing_poison",
1514 SPELL::NUMBING_POISON,
1515 |s| spell_numbing_poison(s, ¶ms.game_data),
1516 )
1517 .spell(
1518 "crippling_poison",
1519 SPELL::CRIPPLING_POISON,
1520 |s| spell_crippling_poison(s, ¶ms.game_data),
1521 )
1522 .spell(
1523 "instant_poison_damage",
1524 SPELL::INSTANT_POISON_DAMAGE,
1525 |s| spell_instant_poison_damage(s, ¶ms.game_data),
1526 )
1527 .spell(
1528 "eviscerate_bonus",
1529 SPELL::EVISCERATE_BONUS,
1530 |s| spell_eviscerate_bonus(s, ¶ms.game_data),
1531 )
1532 .spell(
1533 "black_powder_bonus",
1534 SPELL::BLACK_POWDER_BONUS,
1535 |s| spell_black_powder_bonus(s, ¶ms.game_data),
1536 )
1537 .spell(
1538 "secret_technique_player",
1539 SPELL::SECRET_TECHNIQUE_PLAYER,
1540 |s| spell_secret_technique_player(s, ¶ms.game_data),
1541 )
1542 .spell(
1543 "secret_technique_clones",
1544 SPELL::SECRET_TECHNIQUE_CLONES,
1545 |s| spell_secret_technique_clones(s, ¶ms.game_data),
1546 )
1547 .spell(
1548 "lashe_macabre",
1549 SPELL::LASHE_MACABRE,
1550 |s| spell_lashe_macabre(s, ¶ms.game_data),
1551 )
1552 .spell("kick", SPELL::KICK, |s| spell_kick(s, ¶ms.game_data))
1553 .spell(
1554 "shadow_dance",
1555 SPELL::SHADOW_DANCE,
1556 |s| spell_shadow_dance(s, ¶ms.game_data),
1557 )
1558 .spell(
1559 "shadow_blades",
1560 SPELL::SHADOW_BLADES,
1561 |s| spell_shadow_blades(s, ¶ms.game_data),
1562 )
1563 .spell(
1564 "shadow_blades_attack",
1565 SPELL::SHADOW_BLADES_ATTACK,
1566 |s| spell_shadow_blades_attack(s, ¶ms.game_data),
1567 )
1568 .spell(
1569 "backstab_shadow_clone",
1570 SPELL::BACKSTAB_SHADOW_CLONE,
1571 |s| spell_backstab_shadow_clone(s, ¶ms.game_data),
1572 )
1573 .spell(
1574 "shadowstrike_shadow_clone",
1575 SPELL::SHADOWSTRIKE_SHADOW_CLONE,
1576 |s| spell_shadowstrike_shadow_clone(s, ¶ms.game_data),
1577 )
1578 .spell(
1579 "eviscerate_shadow_clone",
1580 SPELL::EVISCERATE_SHADOW_CLONE,
1581 |s| spell_eviscerate_shadow_clone(s, ¶ms.game_data),
1582 )
1583 .spell(
1584 "shuriken_storm_shadow_clone",
1585 SPELL::SHURIKEN_STORM_SHADOW_CLONE,
1586 |s| spell_shuriken_storm_shadow_clone(s, ¶ms.game_data),
1587 )
1588 .spell(
1589 "secret_technique_shadow_clone",
1590 SPELL::SECRET_TECHNIQUE_SHADOW_CLONE,
1591 |s| spell_secret_technique_shadow_clone(s, ¶ms.game_data),
1592 )
1593 .spell(
1594 "black_powder_shadow_clone",
1595 SPELL::BLACK_POWDER_SHADOW_CLONE,
1596 |s| spell_black_powder_shadow_clone(s, ¶ms.game_data),
1597 )
1598 .spell(
1599 "thistle_tea",
1600 SPELL::THISTLE_TEA,
1601 |s| spell_thistle_tea(s, ¶ms.game_data),
1602 )
1603 .spell("vanish", SPELL::VANISH, |s| spell_vanish(s, ¶ms.game_data))
1604 .auto_attack(|a| {
1605 a
1606 .spell_id(6603)
1607 .swing_ms(1800)
1608 .apply_base_from_data(¶ms.game_data)
1609 .on_swing(crate::hooks::subtlety_rogue::swing_hook)
1610 })
1611 .game_data(params.game_data.clone())
1612 .talent_spell_ids(TALENTS)
1613 .talent_selections(params.talent_selections)
1614 .set_bonus_auras(params.set_bonus_auras)
1615 .encounter(params.encounter.clone());
1616 let builder = crate::generated::items::register_equipped(
1617 builder,
1618 ¶ms.game_data,
1619 params.equipped_items,
1620 )?;
1621
1622 builder
1623 .build(params.rotation)
1624 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1625}
1626fn new_handler(
1627 params: wowlab_engine_ports::HandlerParams<'_>,
1628) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1629 let handler = crate::composition::compose_handler(
1630 build_combat_system,
1631 ¶ms,
1632 crate::hooks::subtlety_rogue::SubtletyHandler::try_new,
1633 )?;
1634
1635 Ok(Box::new(handler))
1636}
1637static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1638 primary_resource: ResourceType::Energy,
1639 secondary_resource: Some(ResourceType::ComboPoints),
1640 spell_ids: DECLARED_SPELL_IDS,
1641 aura_ids: DECLARED_AURA_IDS,
1642 server_proc_entries: &[],
1643 talents: TALENTS,
1644 rotation_field_schema: &[],
1645 metrics_plugin_id: None,
1646 hero_talent_trees: &[
1647 HeroTalentTreeDesc {
1648 name: "Trickster",
1649 spells: HERO_TREE_TRICKSTER_SPELLS,
1650 auras: HERO_TREE_TRICKSTER_AURAS,
1651 },
1652 HeroTalentTreeDesc {
1653 name: "Deathstalker",
1654 spells: HERO_TREE_DEATHSTALKER_SPELLS,
1655 auras: HERO_TREE_DEATHSTALKER_AURAS,
1656 },
1657 ],
1658 reported_spells: REPORTED_SPELLS,
1659 masked_passive_effects: &[],
1660 passive_effect_overrides: &[],
1661};
1662pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1663 spec_id: SpecId::Subtlety,
1664 display_name: "Subtlety Rogue",
1665 metadata: DECLARED_METADATA,
1666 handler_factory: new_handler,
1667};
1668wowlab_engine_combat::smoke_test!(build_combat_system);