1#![allow(non_snake_case, dead_code)]
4use wowlab_types::{combat::ResourceType, game::SpecId};
5use wowlab_engine_domain::dbc::ProcAttributes;
6use wowlab_engine_combat::{
7 BuiltCombatSystem, AuraDefinitionDraft, LocalAuraIdx, LocalSpellIdx,
8 SpellDefinitionDraft,
9};
10use wowlab_engine_ports::{
11 DeclaredSpecMetadata, SpecDescriptor, SpecHandler, HeroTalentTreeDesc,
12 DeclaredServerProcEntry,
13};
14use wowlab_engine_gamedata::ResolvedGameData;
15pub(crate) mod SPELL {
16 pub(crate) const TIGER_PALM: u32 = 100_780;
18 pub(crate) const BLACKOUT_KICK: u32 = 100_784;
20 pub(crate) const RISING_SUN_KICK: u32 = 107_428;
22 pub(crate) const WHIRLING_DRAGON_PUNCH: u32 = 152_175;
24 pub(crate) const STRIKE_OF_THE_WINDLORD: u32 = 392_983;
26 pub(crate) const TOUCH_OF_DEATH: u32 = 322_109;
28 pub(crate) const FLYING_SERPENT_KICK: u32 = 101_545;
30 pub(crate) const CRACKLING_JADE_LIGHTNING: u32 = 117_952;
32 pub(crate) const CHI_BURST: u32 = 123_986;
34 pub(crate) const JADEFIRE_STOMP: u32 = 1_248_815;
36 pub(crate) const ZENITH: u32 = 1_249_625;
38 pub(crate) const CELESTIAL_CONDUIT: u32 = 443_028;
40 pub(crate) const FISTS_OF_FURY: u32 = 113_656;
42 pub(crate) const SPINNING_CRANE_KICK: u32 = 101_546;
44}
45pub(crate) mod AURA {
46 pub(crate) const WHIRLING_DRAGON_PUNCH: u32 = 196_742;
48 pub(crate) const BLACKOUT_KICK: u32 = 116_768;
50 pub(crate) const ZENITH: u32 = 1_249_625;
52 pub(crate) const HEART_OF_THE_JADE_SERPENT: u32 = 443_421;
54 pub(crate) const THE_EMPEROR_S_CAPACITOR: u32 = 337_291;
56 pub(crate) const RUSHING_WIND_KICK: u32 = 1_250_554;
58 pub(crate) const COMBO_STRIKES: u32 = 115_636;
60 pub(crate) const HIT_COMBO: u32 = 196_741;
62 pub(crate) const HARMONIC_COMBO: u32 = 1_250_041;
64 pub(crate) const COMBO_STRIKES_TIGER_PALM: u32 = 1_249_756;
66 pub(crate) const COMBO_STRIKES_BLACKOUT_KICK: u32 = 1_249_757;
68 pub(crate) const COMBO_STRIKES_RISING_SUN_KICK: u32 = 1_249_753;
70 pub(crate) const COMBO_STRIKES_FISTS_OF_FURY: u32 = 1_249_758;
72 pub(crate) const COMBO_STRIKES_SPINNING_CRANE_KICK: u32 = 1_249_754;
74 pub(crate) const COMBO_STRIKES_WHIRLING_DRAGON_PUNCH: u32 = 1_249_765;
76 pub(crate) const COMBO_STRIKES_STRIKE_OF_THE_WINDLORD: u32 = 1_249_766;
78 pub(crate) const COMBO_STRIKES_CRACKLING_JADE_LIGHTNING: u32 = 1_249_764;
80 pub(crate) const DANCE_OF_CHI_JI: u32 = 325_202;
82 pub(crate) const TEACHINGS_OF_THE_MONASTERY: u32 = 202_090;
84 pub(crate) const SPINNING_CRANE_KICK: u32 = 101_546;
86 pub(crate) const MOMENTUM_BOOST: u32 = 451_297;
88 pub(crate) const FLURRY_CHARGE: u32 = 451_021;
90 pub(crate) const STAND_READY: u32 = 1_237_196;
92 pub(crate) const COMBAT_WISDOM: u32 = 129_914;
94 pub(crate) const COMBAT_WISDOM_CYCLE: u32 = 121_817;
96}
97pub(crate) mod TALENT {
98 pub(crate) const ASCENSION: u32 = 115_396;
100 pub(crate) const BRAWLERS_INTENSITY: u32 = 451_485;
102 pub(crate) const CELESTIAL_CONDUIT: u32 = 443_028;
104 pub(crate) const CHI_BURST: u32 = 123_986;
106 pub(crate) const COMBAT_WISDOM: u32 = 121_817;
108 pub(crate) const COMBO_BREAKER: u32 = 137_384;
110 pub(crate) const DANCE_OF_CHI_JI: u32 = 325_201;
112 pub(crate) const DUAL_THREAT: u32 = 451_823;
114 pub(crate) const FISTS_OF_FURY: u32 = 113_656;
116 pub(crate) const FLURRY_STRIKES: u32 = 450_615;
118 pub(crate) const GLORY_OF_THE_DAWN: u32 = 392_958;
120 pub(crate) const HARMONIC_COMBO: u32 = 1_250_041;
122 pub(crate) const HIT_COMBO: u32 = 196_740;
124 pub(crate) const JADEFIRE_STOMP: u32 = 457_974;
126 pub(crate) const JADEFIRE_STOMP_DAMAGE: u32 = 1_248_815;
128 pub(crate) const MOMENTUM_BOOST: u32 = 451_294;
130 pub(crate) const ONE_VERSUS_MANY: u32 = 450_988;
132 pub(crate) const RUSHING_WIND_KICK: u32 = 1_250_566;
134 pub(crate) const SEQUENCED_STRIKES: u32 = 451_515;
136 pub(crate) const SHADOWBOXING_TREADS: u32 = 392_982;
138 pub(crate) const SLICING_WINDS: u32 = 1_217_413;
140 pub(crate) const STAND_READY: u32 = 1_262_603;
142 pub(crate) const STRIKE_OF_THE_WINDLORD: u32 = 392_983;
144 pub(crate) const SUNFIRE_SPIRAL: u32 = 1_272_415;
146 pub(crate) const TEACHINGS_OF_THE_MONASTERY: u32 = 116_645;
148 pub(crate) const THUNDERFIST: u32 = 392_985;
150 pub(crate) const WHIRLING_DRAGON_PUNCH: u32 = 152_175;
152 pub(crate) const WISDOM_OF_THE_WALL: u32 = 1_272_821;
154 pub(crate) const ZENITH: u32 = 1_249_625;
156 pub(crate) const ZENITH_STOMP: u32 = 1_272_694;
158}
159pub(crate) mod REPORTED_SPELL {
160 pub(crate) const DUAL_THREAT: u32 = 451_839;
162 pub(crate) const GLORY_OF_THE_DAWN: u32 = 392_959;
164 pub(crate) const MELEE: u32 = 6603;
166 pub(crate) const TEACHINGS_BLACKOUT_KICK: u32 = 228_649;
168}
169pub(crate) mod HERO {
170 pub(crate) mod SHADO_PAN {
171 pub(crate) mod SPELL {
172 pub(crate) const FLURRY_STRIKE: u32 = 450_617;
174 pub(crate) const SHADO_OVER_THE_BATTLEFIELD: u32 = 451_250;
176 }
177 pub(crate) mod AURA {
178 pub(crate) const FLURRY_CHARGE: u32 = 451_021;
180 pub(crate) const HIGH_IMPACT: u32 = 451_037;
182 pub(crate) const STAND_READY: u32 = 1_237_196;
184 pub(crate) const WHIRLING_STEEL: u32 = 451_214;
186 }
187 }
188 pub(crate) mod CONDUIT_OF_THE_CELESTIALS {
189 pub(crate) mod SPELL {
190 pub(crate) const CELESTIAL_CONDUIT: u32 = 443_028;
192 pub(crate) const CELESTIAL_CONDUIT_DAMAGE: u32 = 443_038;
194 pub(crate) const COURAGE_OF_THE_WHITE_TIGER_DAMAGE: u32 = 457_917;
196 pub(crate) const INVOKE_XUEN: u32 = 123_904;
198 pub(crate) const STRENGTH_OF_THE_BLACK_OX_DAMAGE: u32 = 443_127;
200 }
201 pub(crate) mod AURA {
202 pub(crate) const CELESTIAL_CONDUIT: u32 = 443_028;
204 pub(crate) const COURAGE_OF_THE_WHITE_TIGER: u32 = 460_127;
206 pub(crate) const HEART_OF_THE_JADE_SERPENT: u32 = 443_421;
208 pub(crate) const INVOKE_XUEN: u32 = 123_904;
210 pub(crate) const JADE_SANCTUARY: u32 = 448_508;
212 pub(crate) const UNITY_WITHIN: u32 = 443_592;
214 pub(crate) const YULONS_AVATAR: u32 = 1_238_904;
216 }
217 }
218 pub(crate) mod MASTER_OF_HARMONY {
219 pub(crate) mod SPELL {
220 pub(crate) const ASPECT_OF_HARMONY_DAMAGE: u32 = 450_763;
222 pub(crate) const ASPECT_OF_HARMONY_HEAL: u32 = 450_769;
224 pub(crate) const HARMONIC_SURGE_DAMAGE: u32 = 1_271_011;
226 pub(crate) const OVERWHELMING_FORCE_DAMAGE: u32 = 452_333;
228 pub(crate) const PURIFIED_SPIRIT_DAMAGE: u32 = 450_820;
230 }
231 pub(crate) mod AURA {
232 pub(crate) const ASPECT_OF_HARMONY: u32 = 450_521;
234 pub(crate) const BALANCED_STRATAGEM_MAGIC: u32 = 451_508;
236 pub(crate) const BALANCED_STRATAGEM_PHYSICAL: u32 = 451_514;
238 pub(crate) const HARMONIC_SURGE: u32 = 1_270_990;
240 }
241 }
242}
243static HERO_TREE_SHADO_PAN_SPELLS: &[(&str, u32)] = &[
244 ("FLURRY_STRIKE", 450_617),
245 ("SHADO_OVER_THE_BATTLEFIELD", 451_250),
246];
247static HERO_TREE_SHADO_PAN_AURAS: &[(&str, u32)] = &[
248 ("FLURRY_CHARGE", 451_021),
249 ("HIGH_IMPACT", 451_037),
250 ("STAND_READY", 1_237_196),
251 ("WHIRLING_STEEL", 451_214),
252];
253static HERO_TREE_CONDUIT_OF_THE_CELESTIALS_SPELLS: &[(&str, u32)] = &[
254 ("CELESTIAL_CONDUIT", 443_028),
255 ("CELESTIAL_CONDUIT_DAMAGE", 443_038),
256 ("COURAGE_OF_THE_WHITE_TIGER_DAMAGE", 457_917),
257 ("INVOKE_XUEN", 123_904),
258 ("STRENGTH_OF_THE_BLACK_OX_DAMAGE", 443_127),
259];
260static HERO_TREE_CONDUIT_OF_THE_CELESTIALS_AURAS: &[(&str, u32)] = &[
261 ("CELESTIAL_CONDUIT", 443_028),
262 ("COURAGE_OF_THE_WHITE_TIGER", 460_127),
263 ("HEART_OF_THE_JADE_SERPENT", 443_421),
264 ("INVOKE_XUEN", 123_904),
265 ("JADE_SANCTUARY", 448_508),
266 ("UNITY_WITHIN", 443_592),
267 ("YULONS_AVATAR", 1_238_904),
268];
269static HERO_TREE_MASTER_OF_HARMONY_SPELLS: &[(&str, u32)] = &[
270 ("ASPECT_OF_HARMONY_DAMAGE", 450_763),
271 ("ASPECT_OF_HARMONY_HEAL", 450_769),
272 ("HARMONIC_SURGE_DAMAGE", 1_271_011),
273 ("OVERWHELMING_FORCE_DAMAGE", 452_333),
274 ("PURIFIED_SPIRIT_DAMAGE", 450_820),
275];
276static HERO_TREE_MASTER_OF_HARMONY_AURAS: &[(&str, u32)] = &[
277 ("ASPECT_OF_HARMONY", 450_521),
278 ("BALANCED_STRATAGEM_MAGIC", 451_508),
279 ("BALANCED_STRATAGEM_PHYSICAL", 451_514),
280 ("HARMONIC_SURGE", 1_270_990),
281];
282pub(crate) const AURA_WHIRLING_DRAGON_PUNCH: LocalAuraIdx = LocalAuraIdx::new(0);
283pub(crate) const AURA_BLACKOUT_KICK: LocalAuraIdx = LocalAuraIdx::new(1);
284pub(crate) const AURA_ZENITH: LocalAuraIdx = LocalAuraIdx::new(2);
285pub(crate) const AURA_HEART_OF_THE_JADE_SERPENT: LocalAuraIdx = LocalAuraIdx::new(3);
286pub(crate) const AURA_THE_EMPEROR_S_CAPACITOR: LocalAuraIdx = LocalAuraIdx::new(4);
287pub(crate) const AURA_RUSHING_WIND_KICK: LocalAuraIdx = LocalAuraIdx::new(5);
288pub(crate) const AURA_COMBO_STRIKES: LocalAuraIdx = LocalAuraIdx::new(6);
289pub(crate) const AURA_HIT_COMBO: LocalAuraIdx = LocalAuraIdx::new(7);
290pub(crate) const AURA_HARMONIC_COMBO: LocalAuraIdx = LocalAuraIdx::new(8);
291pub(crate) const AURA_COMBO_STRIKES_TIGER_PALM: LocalAuraIdx = LocalAuraIdx::new(9);
292pub(crate) const AURA_COMBO_STRIKES_BLACKOUT_KICK: LocalAuraIdx = LocalAuraIdx::new(10);
293pub(crate) const AURA_COMBO_STRIKES_RISING_SUN_KICK: LocalAuraIdx = LocalAuraIdx::new(
294 11,
295);
296pub(crate) const AURA_COMBO_STRIKES_FISTS_OF_FURY: LocalAuraIdx = LocalAuraIdx::new(12);
297pub(crate) const AURA_COMBO_STRIKES_SPINNING_CRANE_KICK: LocalAuraIdx = LocalAuraIdx::new(
298 13,
299);
300pub(crate) const AURA_COMBO_STRIKES_WHIRLING_DRAGON_PUNCH: LocalAuraIdx = LocalAuraIdx::new(
301 14,
302);
303pub(crate) const AURA_COMBO_STRIKES_STRIKE_OF_THE_WINDLORD: LocalAuraIdx = LocalAuraIdx::new(
304 15,
305);
306pub(crate) const AURA_COMBO_STRIKES_CRACKLING_JADE_LIGHTNING: LocalAuraIdx = LocalAuraIdx::new(
307 16,
308);
309pub(crate) const AURA_DANCE_OF_CHI_JI: LocalAuraIdx = LocalAuraIdx::new(17);
310pub(crate) const AURA_TEACHINGS_OF_THE_MONASTERY: LocalAuraIdx = LocalAuraIdx::new(18);
311pub(crate) const AURA_SPINNING_CRANE_KICK: LocalAuraIdx = LocalAuraIdx::new(19);
312pub(crate) const AURA_MOMENTUM_BOOST: LocalAuraIdx = LocalAuraIdx::new(20);
313pub(crate) const AURA_FLURRY_CHARGE: LocalAuraIdx = LocalAuraIdx::new(21);
314pub(crate) const AURA_STAND_READY: LocalAuraIdx = LocalAuraIdx::new(22);
315pub(crate) const AURA_COMBAT_WISDOM: LocalAuraIdx = LocalAuraIdx::new(23);
316pub(crate) const AURA_COMBAT_WISDOM_CYCLE: LocalAuraIdx = LocalAuraIdx::new(24);
317pub(crate) const AURA_COUNT: usize = 25;
318const _: () = assert!(
319 AURA_COUNT == 25, "AURA index ABI: count changed -- update positional hook consumers"
320);
321pub(crate) const SPELL_TIGER_PALM: LocalSpellIdx = LocalSpellIdx::new(0);
322pub(crate) const SPELL_BLACKOUT_KICK: LocalSpellIdx = LocalSpellIdx::new(1);
323pub(crate) const SPELL_RISING_SUN_KICK: LocalSpellIdx = LocalSpellIdx::new(2);
324pub(crate) const SPELL_WHIRLING_DRAGON_PUNCH: LocalSpellIdx = LocalSpellIdx::new(3);
325pub(crate) const SPELL_STRIKE_OF_THE_WINDLORD: LocalSpellIdx = LocalSpellIdx::new(4);
326pub(crate) const SPELL_TOUCH_OF_DEATH: LocalSpellIdx = LocalSpellIdx::new(5);
327pub(crate) const SPELL_FLYING_SERPENT_KICK: LocalSpellIdx = LocalSpellIdx::new(6);
328pub(crate) const SPELL_CRACKLING_JADE_LIGHTNING: LocalSpellIdx = LocalSpellIdx::new(7);
329pub(crate) const SPELL_CHI_BURST: LocalSpellIdx = LocalSpellIdx::new(8);
330pub(crate) const SPELL_JADEFIRE_STOMP: LocalSpellIdx = LocalSpellIdx::new(9);
331pub(crate) const SPELL_ZENITH: LocalSpellIdx = LocalSpellIdx::new(10);
332pub(crate) const SPELL_CELESTIAL_CONDUIT: LocalSpellIdx = LocalSpellIdx::new(11);
333pub(crate) const SPELL_FISTS_OF_FURY: LocalSpellIdx = LocalSpellIdx::new(12);
334pub(crate) const SPELL_SPINNING_CRANE_KICK: LocalSpellIdx = LocalSpellIdx::new(13);
335pub(crate) const SPELL_COUNT: usize = 14;
336const _: () = assert!(
337 SPELL_COUNT == 14,
338 "SPELL index ABI: count changed -- update positional hook consumers"
339);
340pub(crate) mod EFFECT {
341 pub(crate) const DUAL_THREAT_CHANCE: (u32, u8) = (451_823, 1);
343 pub(crate) const JADEFIRE_STOMP_DMG: (u32, u8) = (1_248_815, 1);
345 pub(crate) const WDP_AOE_TICK: (u32, u8) = (158_221, 1);
347 pub(crate) const FOF_TICK: (u32, u8) = (117_418, 1);
349 pub(crate) const TOTM_BOK_DMG: (u32, u8) = (228_649, 1);
351 pub(crate) const TOTM_RESET: (u32, u8) = (116_645, 1);
353 pub(crate) const COMBO_BREAKER_CHANCE: (u32, u8) = (137_384, 1);
355 pub(crate) const GOTD_CHANCE: (u32, u8) = (392_958, 2);
357 pub(crate) const GOTD_CHI: (u32, u8) = (392_959, 3);
359 pub(crate) const GOTD_DMG: (u32, u8) = (392_959, 1);
361 pub(crate) const MOMENTUM_HASTE: (u32, u8) = (451_294, 1);
363 pub(crate) const SEQUENCED_CHANCE: (u32, u8) = (451_515, 1);
365 pub(crate) const SUNFIRE_SPIRAL_PCT: (u32, u8) = (1_272_415, 1);
367 pub(crate) const FLURRY_CHARGES_2H: (u32, u8) = (450_615, 2);
369 pub(crate) const FLURRY_DMG: (u32, u8) = (450_617, 1);
371 pub(crate) const OVM_CHARGE_BONUS: (u32, u8) = (450_988, 1);
373 pub(crate) const SHADO_DMG: (u32, u8) = (451_250, 1);
375 pub(crate) const STAND_READY_COUNT: (u32, u8) = (1_262_603, 1);
377 pub(crate) const STAND_READY_MULT: (u32, u8) = (1_262_603, 2);
379 pub(crate) const WOTW_COUNT: (u32, u8) = (1_272_821, 1);
381 pub(crate) const ZENITH_STOMP_CHI: (u32, u8) = (1_272_696, 2);
383 pub(crate) const ZENITH_STOMP_DMG: (u32, u8) = (1_272_696, 1);
385 pub(crate) const BRAWLERS_RSK_CDR: (u32, u8) = (451_485, 1);
387 pub(crate) const COMBAT_WISDOM_CHI: (u32, u8) = (121_817, 1);
389 pub(crate) const EH_DMG: (u32, u8) = (115_129, 1);
391 pub(crate) const EH_DMG_PCT: (u32, u8) = (451_968, 2);
393 pub(crate) const EH_HEAL_SP: (u32, u8) = (451_968, 1);
395}
396static REPORTED_SPELLS: &[(&str, u32)] = &[
397 ("dual_threat", 451_839),
398 ("glory_of_the_dawn", 392_959),
399 ("melee", 6603),
400 ("teachings_blackout_kick", 228_649),
401];
402static DECLARED_SPELL_IDS: &[u32] = &[
403 100_780, 100_784, 107_428, 152_175, 392_983, 322_109, 101_545, 117_952, 123_986,
404 1_248_815, 1_249_625, 443_028, 113_656, 101_546, 196_742, 116_768, 1_249_625,
405 443_421, 337_291, 1_250_554, 115_636, 196_741, 1_250_041, 1_249_756, 1_249_757,
406 1_249_753, 1_249_758, 1_249_754, 1_249_765, 1_249_766, 1_249_764, 325_202, 202_090,
407 101_546, 451_297, 451_021, 1_237_196, 129_914, 121_817, 6603, 6603, 100_784, 107_270,
408 115_129, 115_636, 116_645, 116_768, 117_418, 121_817, 137_384, 148_135, 158_221,
409 228_649, 325_202, 392_958, 392_959, 450_615, 450_617, 450_988, 451_250, 451_294,
410 451_485, 451_515, 451_767, 451_823, 451_839, 451_968, 1_248_815, 1_250_041,
411 1_262_603, 1_272_415, 1_272_696, 1_272_821, 451_839, 392_959, 6603, 228_649, 450_617,
412 451_250, 451_021, 451_037, 1_237_196, 451_214, 443_028, 443_038, 457_917, 123_904,
413 443_127, 443_028, 460_127, 443_421, 123_904, 448_508, 443_592, 1_238_904, 450_763,
414 450_769, 1_271_011, 452_333, 450_820, 450_521, 451_508, 451_514, 1_270_990,
415];
416static DECLARED_AURA_IDS: &[u32] = &[
417 196_742, 116_768, 1_249_625, 443_421, 337_291, 1_250_554, 115_636, 196_741,
418 1_250_041, 1_249_756, 1_249_757, 1_249_753, 1_249_758, 1_249_754, 1_249_765,
419 1_249_766, 1_249_764, 325_202, 202_090, 101_546, 451_297, 451_021, 1_237_196,
420 129_914, 121_817, 451_021, 451_037, 1_237_196, 451_214, 443_028, 460_127, 443_421,
421 123_904, 448_508, 443_592, 1_238_904, 450_521, 451_508, 451_514, 1_270_990,
422];
423static TALENTS: &[(&str, u32)] = &[
424 ("ASCENSION", TALENT::ASCENSION),
425 ("BRAWLERS_INTENSITY", TALENT::BRAWLERS_INTENSITY),
426 ("CELESTIAL_CONDUIT", TALENT::CELESTIAL_CONDUIT),
427 ("CHI_BURST", TALENT::CHI_BURST),
428 ("COMBAT_WISDOM", TALENT::COMBAT_WISDOM),
429 ("COMBO_BREAKER", TALENT::COMBO_BREAKER),
430 ("DANCE_OF_CHI_JI", TALENT::DANCE_OF_CHI_JI),
431 ("DUAL_THREAT", TALENT::DUAL_THREAT),
432 ("FISTS_OF_FURY", TALENT::FISTS_OF_FURY),
433 ("FLURRY_STRIKES", TALENT::FLURRY_STRIKES),
434 ("GLORY_OF_THE_DAWN", TALENT::GLORY_OF_THE_DAWN),
435 ("HARMONIC_COMBO", TALENT::HARMONIC_COMBO),
436 ("HIT_COMBO", TALENT::HIT_COMBO),
437 ("JADEFIRE_STOMP", TALENT::JADEFIRE_STOMP),
438 ("JADEFIRE_STOMP_DAMAGE", TALENT::JADEFIRE_STOMP_DAMAGE),
439 ("MOMENTUM_BOOST", TALENT::MOMENTUM_BOOST),
440 ("ONE_VERSUS_MANY", TALENT::ONE_VERSUS_MANY),
441 ("RUSHING_WIND_KICK", TALENT::RUSHING_WIND_KICK),
442 ("SEQUENCED_STRIKES", TALENT::SEQUENCED_STRIKES),
443 ("SHADOWBOXING_TREADS", TALENT::SHADOWBOXING_TREADS),
444 ("SLICING_WINDS", TALENT::SLICING_WINDS),
445 ("STAND_READY", TALENT::STAND_READY),
446 ("STRIKE_OF_THE_WINDLORD", TALENT::STRIKE_OF_THE_WINDLORD),
447 ("SUNFIRE_SPIRAL", TALENT::SUNFIRE_SPIRAL),
448 ("TEACHINGS_OF_THE_MONASTERY", TALENT::TEACHINGS_OF_THE_MONASTERY),
449 ("THUNDERFIST", TALENT::THUNDERFIST),
450 ("WHIRLING_DRAGON_PUNCH", TALENT::WHIRLING_DRAGON_PUNCH),
451 ("WISDOM_OF_THE_WALL", TALENT::WISDOM_OF_THE_WALL),
452 ("ZENITH", TALENT::ZENITH),
453 ("ZENITH_STOMP", TALENT::ZENITH_STOMP),
454];
455pub(crate) mod WINDWALKER_MONK {
456 pub(crate) const TIGER_PALM_CASTS: u32 = 0;
457 pub(crate) const BLACKOUT_KICK_CASTS: u32 = 1;
458 pub(crate) const RISING_SUN_KICK_CASTS: u32 = 2;
459 pub(crate) const FISTS_OF_FURY_CASTS: u32 = 3;
460 pub(crate) const SPINNING_CRANE_KICK_CASTS: u32 = 4;
461 pub(crate) const WHIRLING_DRAGON_PUNCH_CASTS: u32 = 5;
462 pub(crate) const STRIKE_OF_THE_WINDLORD_CASTS: u32 = 6;
463 pub(crate) const TOUCH_OF_DEATH_CASTS: u32 = 7;
464 pub(crate) const ZENITH_UPTIME_MS: u32 = 8;
465}
466fn aura_whirling_dragon_punch(
467 a: AuraDefinitionDraft,
468 data: &ResolvedGameData,
469) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
470 Ok(
471 a
472 .on_player()
473 .apply_base_from_data(data, 196_742)?
474 .max_stacks(
475 data
476 .require_aura_max_stacks(
477 wowlab_types::sim::SpellIdx::from_raw(196_742),
478 )?,
479 ),
480 )
481}
482fn aura_blackout_kick(
483 a: AuraDefinitionDraft,
484 data: &ResolvedGameData,
485) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
486 a.on_player()
487 .apply_base_from_data(data, 116_768)?
488 .max_stacks(
489 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(116_768))?,
490 )
491 .secondary_spell_cost_percent(
492 data.base_points(wowlab_types::sim::SpellIdx::from_raw(116_768), 1),
493 &[100_784],
494 )
495}
496fn aura_zenith(
497 a: AuraDefinitionDraft,
498 data: &ResolvedGameData,
499) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
500 Ok(
501 a
502 .on_player()
503 .apply_base_from_data(data, 1_249_625)?
504 .max_stacks(
505 data
506 .require_aura_max_stacks(
507 wowlab_types::sim::SpellIdx::from_raw(1_249_625),
508 )?,
509 ),
510 )
511}
512fn aura_heart_of_the_jade_serpent(
513 a: AuraDefinitionDraft,
514 data: &ResolvedGameData,
515) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
516 Ok(
517 a
518 .on_player()
519 .apply_base_from_data(data, 443_421)?
520 .max_stacks(
521 data
522 .require_aura_max_stacks(
523 wowlab_types::sim::SpellIdx::from_raw(443_421),
524 )?,
525 ),
526 )
527}
528fn aura_the_emperor_s_capacitor(
529 a: AuraDefinitionDraft,
530 data: &ResolvedGameData,
531) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
532 Ok(
533 a
534 .on_player()
535 .apply_base_from_data(data, 337_291)?
536 .max_stacks(
537 data
538 .require_aura_max_stacks(
539 wowlab_types::sim::SpellIdx::from_raw(337_291),
540 )?,
541 ),
542 )
543}
544fn aura_rushing_wind_kick(
545 a: AuraDefinitionDraft,
546 data: &ResolvedGameData,
547) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
548 Ok(
549 a
550 .on_player()
551 .apply_base_from_data(data, 1_250_554)?
552 .max_stacks(
553 data
554 .require_aura_max_stacks(
555 wowlab_types::sim::SpellIdx::from_raw(1_250_554),
556 )?,
557 ),
558 )
559}
560fn aura_combo_strikes(
561 a: AuraDefinitionDraft,
562 data: &ResolvedGameData,
563) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
564 Ok(
565 a
566 .on_player()
567 .apply_base_from_data(data, 115_636)?
568 .max_stacks(
569 data
570 .require_aura_max_stacks(
571 wowlab_types::sim::SpellIdx::from_raw(115_636),
572 )?,
573 ),
574 )
575}
576fn aura_hit_combo(
577 a: AuraDefinitionDraft,
578 data: &ResolvedGameData,
579) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
580 Ok(
581 a
582 .on_player()
583 .apply_base_from_data(data, 196_741)?
584 .max_stacks(
585 data
586 .require_aura_max_stacks(
587 wowlab_types::sim::SpellIdx::from_raw(196_741),
588 )?,
589 ),
590 )
591}
592fn aura_harmonic_combo(
593 a: AuraDefinitionDraft,
594 data: &ResolvedGameData,
595) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
596 a.on_player()
597 .apply_base_from_data(data, 1_250_041)?
598 .max_stacks(
599 data
600 .require_aura_max_stacks(
601 wowlab_types::sim::SpellIdx::from_raw(1_250_041),
602 )?,
603 )
604 .secondary_spell_cost_flat(
605 data.base_points(wowlab_types::sim::SpellIdx::from_raw(1_250_041), 1),
606 &[100_784],
607 )
608}
609fn aura_combo_strikes_tiger_palm(
610 a: AuraDefinitionDraft,
611 data: &ResolvedGameData,
612) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
613 Ok(
614 a
615 .on_player()
616 .apply_base_from_data(data, 1_249_756)?
617 .max_stacks(
618 data
619 .require_aura_max_stacks(
620 wowlab_types::sim::SpellIdx::from_raw(1_249_756),
621 )?,
622 ),
623 )
624}
625fn aura_combo_strikes_blackout_kick(
626 a: AuraDefinitionDraft,
627 data: &ResolvedGameData,
628) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
629 Ok(
630 a
631 .on_player()
632 .apply_base_from_data(data, 1_249_757)?
633 .max_stacks(
634 data
635 .require_aura_max_stacks(
636 wowlab_types::sim::SpellIdx::from_raw(1_249_757),
637 )?,
638 ),
639 )
640}
641fn aura_combo_strikes_rising_sun_kick(
642 a: AuraDefinitionDraft,
643 data: &ResolvedGameData,
644) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
645 Ok(
646 a
647 .on_player()
648 .apply_base_from_data(data, 1_249_753)?
649 .max_stacks(
650 data
651 .require_aura_max_stacks(
652 wowlab_types::sim::SpellIdx::from_raw(1_249_753),
653 )?,
654 ),
655 )
656}
657fn aura_combo_strikes_fists_of_fury(
658 a: AuraDefinitionDraft,
659 data: &ResolvedGameData,
660) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
661 Ok(
662 a
663 .on_player()
664 .apply_base_from_data(data, 1_249_758)?
665 .max_stacks(
666 data
667 .require_aura_max_stacks(
668 wowlab_types::sim::SpellIdx::from_raw(1_249_758),
669 )?,
670 ),
671 )
672}
673fn aura_combo_strikes_spinning_crane_kick(
674 a: AuraDefinitionDraft,
675 data: &ResolvedGameData,
676) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
677 Ok(
678 a
679 .on_player()
680 .apply_base_from_data(data, 1_249_754)?
681 .max_stacks(
682 data
683 .require_aura_max_stacks(
684 wowlab_types::sim::SpellIdx::from_raw(1_249_754),
685 )?,
686 ),
687 )
688}
689fn aura_combo_strikes_whirling_dragon_punch(
690 a: AuraDefinitionDraft,
691 data: &ResolvedGameData,
692) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
693 Ok(
694 a
695 .on_player()
696 .apply_base_from_data(data, 1_249_765)?
697 .max_stacks(
698 data
699 .require_aura_max_stacks(
700 wowlab_types::sim::SpellIdx::from_raw(1_249_765),
701 )?,
702 ),
703 )
704}
705fn aura_combo_strikes_strike_of_the_windlord(
706 a: AuraDefinitionDraft,
707 data: &ResolvedGameData,
708) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
709 Ok(
710 a
711 .on_player()
712 .apply_base_from_data(data, 1_249_766)?
713 .max_stacks(
714 data
715 .require_aura_max_stacks(
716 wowlab_types::sim::SpellIdx::from_raw(1_249_766),
717 )?,
718 ),
719 )
720}
721fn aura_combo_strikes_crackling_jade_lightning(
722 a: AuraDefinitionDraft,
723 data: &ResolvedGameData,
724) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
725 Ok(
726 a
727 .on_player()
728 .apply_base_from_data(data, 1_249_764)?
729 .max_stacks(
730 data
731 .require_aura_max_stacks(
732 wowlab_types::sim::SpellIdx::from_raw(1_249_764),
733 )?,
734 ),
735 )
736}
737fn aura_dance_of_chi_ji(
738 a: AuraDefinitionDraft,
739 data: &ResolvedGameData,
740) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
741 a.on_player()
742 .apply_base_from_data(data, 325_202)?
743 .max_stacks(
744 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(325_202))?,
745 )
746 .secondary_spell_cost_flat(
747 data.base_points(wowlab_types::sim::SpellIdx::from_raw(325_202), 1),
748 &[101_546],
749 )
750}
751fn aura_teachings_of_the_monastery(
752 a: AuraDefinitionDraft,
753 data: &ResolvedGameData,
754) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
755 Ok(
756 a
757 .on_player()
758 .apply_base_from_data(data, 202_090)?
759 .max_stacks(
760 data
761 .require_aura_max_stacks(
762 wowlab_types::sim::SpellIdx::from_raw(202_090),
763 )?,
764 ),
765 )
766}
767fn aura_spinning_crane_kick(
768 a: AuraDefinitionDraft,
769 data: &ResolvedGameData,
770) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
771 Ok(
772 a
773 .on_player()
774 .apply_base_from_data(data, 101_546)?
775 .max_stacks(
776 data
777 .require_aura_max_stacks(
778 wowlab_types::sim::SpellIdx::from_raw(101_546),
779 )?,
780 ),
781 )
782}
783fn aura_momentum_boost(
784 a: AuraDefinitionDraft,
785 data: &ResolvedGameData,
786) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
787 Ok(
788 a
789 .on_player()
790 .apply_base_from_data(data, 451_297)?
791 .max_stacks(
792 data
793 .require_aura_max_stacks(
794 wowlab_types::sim::SpellIdx::from_raw(451_297),
795 )?,
796 ),
797 )
798}
799fn aura_flurry_charge(
800 a: AuraDefinitionDraft,
801 data: &ResolvedGameData,
802) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
803 Ok(
804 a
805 .on_player()
806 .apply_base_from_data(data, 451_021)?
807 .max_stacks(
808 data
809 .require_aura_max_stacks(
810 wowlab_types::sim::SpellIdx::from_raw(451_021),
811 )?,
812 ),
813 )
814}
815fn aura_stand_ready(
816 a: AuraDefinitionDraft,
817 data: &ResolvedGameData,
818) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
819 Ok(
820 a
821 .on_player()
822 .apply_base_from_data(data, 1_237_196)?
823 .max_stacks(
824 data
825 .require_aura_max_stacks(
826 wowlab_types::sim::SpellIdx::from_raw(1_237_196),
827 )?,
828 ),
829 )
830}
831fn aura_combat_wisdom(
832 a: AuraDefinitionDraft,
833 data: &ResolvedGameData,
834) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
835 Ok(
836 a
837 .on_player()
838 .apply_base_from_data(data, 129_914)?
839 .max_stacks(
840 data
841 .require_aura_max_stacks(
842 wowlab_types::sim::SpellIdx::from_raw(129_914),
843 )?,
844 ),
845 )
846}
847fn aura_combat_wisdom_cycle(
848 a: AuraDefinitionDraft,
849 data: &ResolvedGameData,
850) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
851 a.on_player()
852 .apply_base_from_data(data, 121_817)?
853 .max_stacks(
854 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(121_817))?,
855 )
856 .periodic_apply_aura(
857 wowlab_engine_combat::validated_milliseconds(
858 data.period(wowlab_types::sim::SpellIdx::from_raw(121_817), 2),
859 121_817,
860 "periodic_apply_aura.tick_ms",
861 )?,
862 23,
863 )
864 .apply_periodic_behavior_from_data(data, 121_817)
865}
866fn spell_tiger_palm(
867 s: SpellDefinitionDraft,
868 data: &ResolvedGameData,
869) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
870 Ok(
871 s
872 .apply_base_from_data(data, 100_780)?
873 .apply_aoe_from_data(data)
874 .on_cast(crate::hooks::windwalker_monk::tiger_palm_hook),
875 )
876}
877fn spell_blackout_kick(
878 s: SpellDefinitionDraft,
879 data: &ResolvedGameData,
880) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
881 Ok(
882 s
883 .apply_base_from_data(data, 100_784)?
884 .applies_inferred_aura(AURA_BLACKOUT_KICK, 116_768)
885 .reduces_cd(
886 SPELL_RISING_SUN_KICK,
887 wowlab_engine_combat::validated_milliseconds(
888 data.base_points(wowlab_types::sim::SpellIdx::from_raw(100_784), 3),
889 100_784,
890 "spell.reduces_cd.amount_ms",
891 )?,
892 )
893 .reduces_cd(
894 SPELL_FISTS_OF_FURY,
895 wowlab_engine_combat::validated_milliseconds(
896 data.base_points(wowlab_types::sim::SpellIdx::from_raw(100_784), 3),
897 100_784,
898 "spell.reduces_cd.amount_ms",
899 )?,
900 )
901 .apply_aoe_from_data(data)
902 .on_cast(crate::hooks::windwalker_monk::blackout_kick_hook),
903 )
904}
905fn spell_rising_sun_kick(
906 s: SpellDefinitionDraft,
907 data: &ResolvedGameData,
908) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
909 Ok(
910 s
911 .apply_base_from_data(data, 107_428)?
912 .apply_aoe_from_data(data)
913 .on_cast(crate::hooks::windwalker_monk::rising_sun_kick_hook),
914 )
915}
916fn spell_whirling_dragon_punch(
917 s: SpellDefinitionDraft,
918 data: &ResolvedGameData,
919) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
920 Ok(
921 s
922 .apply_base_from_data(data, 152_175)?
923 .damage_ap_from_data(
924 wowlab_engine_domain::dbc::EffectLookup::new(
925 data,
926 wowlab_types::sim::EffectRef::new(
927 wowlab_types::sim::SpellIdx::from_raw(451_767),
928 1,
929 ),
930 ),
931 )?
932 .applies_inferred_aura(AURA_WHIRLING_DRAGON_PUNCH, 196_742)
933 .apply_aoe_from_data(data)
934 .on_cast(crate::hooks::windwalker_monk::whirling_dragon_punch_hook),
935 )
936}
937fn spell_strike_of_the_windlord(
938 s: SpellDefinitionDraft,
939 data: &ResolvedGameData,
940) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
941 Ok(s.apply_base_from_data(data, 392_983)?.apply_aoe_from_data(data))
942}
943fn spell_touch_of_death(
944 s: SpellDefinitionDraft,
945 data: &ResolvedGameData,
946) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
947 Ok(s.apply_base_from_data(data, 322_109)?.apply_aoe_from_data(data))
948}
949fn spell_flying_serpent_kick(
950 s: SpellDefinitionDraft,
951 data: &ResolvedGameData,
952) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
953 Ok(s.apply_base_from_data(data, 101_545)?.apply_aoe_from_data(data))
954}
955fn spell_crackling_jade_lightning(
956 s: SpellDefinitionDraft,
957 data: &ResolvedGameData,
958) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
959 Ok(s.apply_base_from_data(data, 117_952)?.apply_aoe_from_data(data))
960}
961fn spell_chi_burst(
962 s: SpellDefinitionDraft,
963 data: &ResolvedGameData,
964) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
965 Ok(
966 s
967 .apply_base_from_data(data, 123_986)?
968 .damage_ap_from_data(
969 wowlab_engine_domain::dbc::EffectLookup::new(
970 data,
971 wowlab_types::sim::EffectRef::new(
972 wowlab_types::sim::SpellIdx::from_raw(148_135),
973 1,
974 ),
975 ),
976 )?
977 .apply_aoe_from_data(data),
978 )
979}
980fn spell_jadefire_stomp(
981 s: SpellDefinitionDraft,
982 data: &ResolvedGameData,
983) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
984 Ok(s.apply_base_from_data(data, 1_248_815)?.apply_aoe_from_data(data))
985}
986fn spell_zenith(
987 s: SpellDefinitionDraft,
988 data: &ResolvedGameData,
989) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
990 Ok(
991 s
992 .apply_base_from_data(data, 1_249_625)?
993 .applies_inferred_aura(AURA_ZENITH, 1_249_625)
994 .apply_aoe_from_data(data)
995 .on_cast(crate::hooks::windwalker_monk::zenith_hook),
996 )
997}
998fn spell_celestial_conduit(
999 s: SpellDefinitionDraft,
1000 data: &ResolvedGameData,
1001) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1002 Ok(s.apply_base_from_data(data, 443_028)?.apply_aoe_from_data(data))
1003}
1004fn spell_fists_of_fury(
1005 s: SpellDefinitionDraft,
1006 data: &ResolvedGameData,
1007) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1008 Ok(
1009 s
1010 .apply_base_from_data(data, 113_656)?
1011 .apply_aoe_from_data(data)
1012 .channel(
1013 wowlab_engine_combat::validated_channel_tick_count(
1014 5.0,
1015 113_656,
1016 "channel.tick_count",
1017 )?,
1018 )
1019 .on_channel_tick(crate::hooks::windwalker_monk::fists_of_fury_tick_hook)
1020 .on_cast(crate::hooks::windwalker_monk::fists_of_fury_hook),
1021 )
1022}
1023fn spell_spinning_crane_kick(
1024 s: SpellDefinitionDraft,
1025 data: &ResolvedGameData,
1026) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1027 Ok(
1028 s
1029 .apply_base_from_data(data, 101_546)?
1030 .applies_inferred_aura(AURA_SPINNING_CRANE_KICK, 101_546)
1031 .apply_aoe_from_data(data)
1032 .channel(
1033 wowlab_engine_combat::validated_channel_tick_count(
1034 4.0,
1035 101_546,
1036 "channel.tick_count",
1037 )?,
1038 )
1039 .channel_tick_damage_ap_from_data(
1040 wowlab_engine_domain::dbc::EffectLookup::new(
1041 data,
1042 wowlab_types::sim::EffectRef::new(
1043 wowlab_types::sim::SpellIdx::from_raw(107_270),
1044 1,
1045 ),
1046 ),
1047 )?
1048 .on_cast(crate::hooks::windwalker_monk::spinning_crane_kick_hook),
1049 )
1050}
1051pub(crate) fn build_combat_system(
1052 params: &wowlab_engine_ports::HandlerParams<'_>,
1053) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1054 let builder = BuiltCombatSystem::builder(params.stats.clone())
1055 .spec_id(SpecId::Windwalker)
1056 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1057 .mastery_spell(115_636)
1058 .mastery_hook(crate::hooks::windwalker_monk::mastery)
1059 .resource(
1060 "energy",
1061 params
1062 .game_data
1063 .power_max(3)
1064 .ok_or_else(|| {
1065 wowlab_engine_ports::EngineError::spec_construction(
1066 "missing power-type power_max for type_id 3",
1067 )
1068 })?,
1069 params
1070 .game_data
1071 .power_regen_for_max(
1072 3,
1073 params
1074 .game_data
1075 .power_max(3)
1076 .ok_or_else(|| {
1077 wowlab_engine_ports::EngineError::spec_construction(
1078 "missing power-type power_max for type_id 3",
1079 )
1080 })?,
1081 )
1082 .ok_or_else(|| {
1083 wowlab_engine_ports::EngineError::spec_construction(
1084 "missing power-type power_regen_for_max for type_id 3",
1085 )
1086 })?,
1087 )
1088 .resource_type_id(3)
1089 .resource_start(
1090 params
1091 .game_data
1092 .power_default(3)
1093 .ok_or_else(|| {
1094 wowlab_engine_ports::EngineError::spec_construction(
1095 "missing power-type power_default for type_id 3",
1096 )
1097 })?,
1098 )
1099 .secondary_resource(
1100 "chi",
1101 params
1102 .game_data
1103 .power_max(12)
1104 .ok_or_else(|| {
1105 wowlab_engine_ports::EngineError::spec_construction(
1106 "missing power-type power_max for type_id 12",
1107 )
1108 })?,
1109 )
1110 .secondary_resource_type_id(12)
1111 .aura(
1112 "whirling_dragon_punch",
1113 AURA::WHIRLING_DRAGON_PUNCH,
1114 |a| aura_whirling_dragon_punch(a, ¶ms.game_data),
1115 )
1116 .aura(
1117 "blackout_kick",
1118 AURA::BLACKOUT_KICK,
1119 |a| aura_blackout_kick(a, ¶ms.game_data),
1120 )
1121 .aura("zenith", AURA::ZENITH, |a| aura_zenith(a, ¶ms.game_data))
1122 .aura(
1123 "heart_of_the_jade_serpent",
1124 AURA::HEART_OF_THE_JADE_SERPENT,
1125 |a| aura_heart_of_the_jade_serpent(a, ¶ms.game_data),
1126 )
1127 .aura(
1128 "the_emperors_capacitor",
1129 AURA::THE_EMPEROR_S_CAPACITOR,
1130 |a| aura_the_emperor_s_capacitor(a, ¶ms.game_data),
1131 )
1132 .aura(
1133 "rushing_wind_kick",
1134 AURA::RUSHING_WIND_KICK,
1135 |a| aura_rushing_wind_kick(a, ¶ms.game_data),
1136 )
1137 .aura(
1138 "combo_strikes",
1139 AURA::COMBO_STRIKES,
1140 |a| aura_combo_strikes(a, ¶ms.game_data),
1141 )
1142 .aura("hit_combo", AURA::HIT_COMBO, |a| aura_hit_combo(a, ¶ms.game_data))
1143 .aura(
1144 "harmonic_combo",
1145 AURA::HARMONIC_COMBO,
1146 |a| aura_harmonic_combo(a, ¶ms.game_data),
1147 )
1148 .aura(
1149 "combo_strikes_tiger_palm",
1150 AURA::COMBO_STRIKES_TIGER_PALM,
1151 |a| aura_combo_strikes_tiger_palm(a, ¶ms.game_data),
1152 )
1153 .aura(
1154 "combo_strikes_blackout_kick",
1155 AURA::COMBO_STRIKES_BLACKOUT_KICK,
1156 |a| aura_combo_strikes_blackout_kick(a, ¶ms.game_data),
1157 )
1158 .aura(
1159 "combo_strikes_rising_sun_kick",
1160 AURA::COMBO_STRIKES_RISING_SUN_KICK,
1161 |a| aura_combo_strikes_rising_sun_kick(a, ¶ms.game_data),
1162 )
1163 .aura(
1164 "combo_strikes_fists_of_fury",
1165 AURA::COMBO_STRIKES_FISTS_OF_FURY,
1166 |a| aura_combo_strikes_fists_of_fury(a, ¶ms.game_data),
1167 )
1168 .aura(
1169 "combo_strikes_spinning_crane_kick",
1170 AURA::COMBO_STRIKES_SPINNING_CRANE_KICK,
1171 |a| aura_combo_strikes_spinning_crane_kick(a, ¶ms.game_data),
1172 )
1173 .aura(
1174 "combo_strikes_whirling_dragon_punch",
1175 AURA::COMBO_STRIKES_WHIRLING_DRAGON_PUNCH,
1176 |a| aura_combo_strikes_whirling_dragon_punch(a, ¶ms.game_data),
1177 )
1178 .aura(
1179 "combo_strikes_strike_of_the_windlord",
1180 AURA::COMBO_STRIKES_STRIKE_OF_THE_WINDLORD,
1181 |a| aura_combo_strikes_strike_of_the_windlord(a, ¶ms.game_data),
1182 )
1183 .aura(
1184 "combo_strikes_crackling_jade_lightning",
1185 AURA::COMBO_STRIKES_CRACKLING_JADE_LIGHTNING,
1186 |a| aura_combo_strikes_crackling_jade_lightning(a, ¶ms.game_data),
1187 )
1188 .aura(
1189 "dance_of_chi_ji",
1190 AURA::DANCE_OF_CHI_JI,
1191 |a| aura_dance_of_chi_ji(a, ¶ms.game_data),
1192 )
1193 .aura(
1194 "teachings_of_the_monastery",
1195 AURA::TEACHINGS_OF_THE_MONASTERY,
1196 |a| aura_teachings_of_the_monastery(a, ¶ms.game_data),
1197 )
1198 .aura(
1199 "spinning_crane_kick",
1200 AURA::SPINNING_CRANE_KICK,
1201 |a| aura_spinning_crane_kick(a, ¶ms.game_data),
1202 )
1203 .aura(
1204 "momentum_boost",
1205 AURA::MOMENTUM_BOOST,
1206 |a| aura_momentum_boost(a, ¶ms.game_data),
1207 )
1208 .aura(
1209 "flurry_charge",
1210 AURA::FLURRY_CHARGE,
1211 |a| aura_flurry_charge(a, ¶ms.game_data),
1212 )
1213 .aura(
1214 "stand_ready",
1215 AURA::STAND_READY,
1216 |a| aura_stand_ready(a, ¶ms.game_data),
1217 )
1218 .aura(
1219 "combat_wisdom",
1220 AURA::COMBAT_WISDOM,
1221 |a| aura_combat_wisdom(a, ¶ms.game_data),
1222 )
1223 .aura(
1224 "combat_wisdom_cycle",
1225 AURA::COMBAT_WISDOM_CYCLE,
1226 |a| aura_combat_wisdom_cycle(a, ¶ms.game_data),
1227 )
1228 .spell(
1229 "tiger_palm",
1230 SPELL::TIGER_PALM,
1231 |s| spell_tiger_palm(s, ¶ms.game_data),
1232 )
1233 .spell(
1234 "blackout_kick",
1235 SPELL::BLACKOUT_KICK,
1236 |s| spell_blackout_kick(s, ¶ms.game_data),
1237 )
1238 .spell(
1239 "rising_sun_kick",
1240 SPELL::RISING_SUN_KICK,
1241 |s| spell_rising_sun_kick(s, ¶ms.game_data),
1242 )
1243 .spell(
1244 "whirling_dragon_punch",
1245 SPELL::WHIRLING_DRAGON_PUNCH,
1246 |s| spell_whirling_dragon_punch(s, ¶ms.game_data),
1247 )
1248 .spell(
1249 "strike_of_the_windlord",
1250 SPELL::STRIKE_OF_THE_WINDLORD,
1251 |s| spell_strike_of_the_windlord(s, ¶ms.game_data),
1252 )
1253 .spell(
1254 "touch_of_death",
1255 SPELL::TOUCH_OF_DEATH,
1256 |s| spell_touch_of_death(s, ¶ms.game_data),
1257 )
1258 .spell(
1259 "flying_serpent_kick",
1260 SPELL::FLYING_SERPENT_KICK,
1261 |s| spell_flying_serpent_kick(s, ¶ms.game_data),
1262 )
1263 .spell(
1264 "crackling_jade_lightning",
1265 SPELL::CRACKLING_JADE_LIGHTNING,
1266 |s| spell_crackling_jade_lightning(s, ¶ms.game_data),
1267 )
1268 .spell("chi_burst", SPELL::CHI_BURST, |s| spell_chi_burst(s, ¶ms.game_data))
1269 .spell(
1270 "jadefire_stomp",
1271 SPELL::JADEFIRE_STOMP,
1272 |s| spell_jadefire_stomp(s, ¶ms.game_data),
1273 )
1274 .spell("zenith", SPELL::ZENITH, |s| spell_zenith(s, ¶ms.game_data))
1275 .spell(
1276 "celestial_conduit",
1277 SPELL::CELESTIAL_CONDUIT,
1278 |s| spell_celestial_conduit(s, ¶ms.game_data),
1279 )
1280 .spell(
1281 "fists_of_fury",
1282 SPELL::FISTS_OF_FURY,
1283 |s| spell_fists_of_fury(s, ¶ms.game_data),
1284 )
1285 .spell(
1286 "spinning_crane_kick",
1287 SPELL::SPINNING_CRANE_KICK,
1288 |s| spell_spinning_crane_kick(s, ¶ms.game_data),
1289 )
1290 .auto_attack(|a| {
1291 a
1292 .spell_id(6603)
1293 .swing_ms(2600)
1294 .apply_base_from_data(¶ms.game_data)
1295 .on_swing(crate::hooks::windwalker_monk::swing_hook)
1296 })
1297 .game_data(params.game_data.clone())
1298 .talent_spell_ids(TALENTS)
1299 .talent_selections(params.talent_selections)
1300 .set_bonus_auras(params.set_bonus_auras)
1301 .encounter(params.encounter.clone());
1302 let builder = crate::generated::items::register_equipped(
1303 builder,
1304 ¶ms.game_data,
1305 params.equipped_items,
1306 )?;
1307
1308 builder
1309 .build(params.rotation)
1310 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1311}
1312fn new_handler(
1313 params: wowlab_engine_ports::HandlerParams<'_>,
1314) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1315 let handler = crate::composition::compose_handler(
1316 build_combat_system,
1317 ¶ms,
1318 crate::hooks::windwalker_monk::WindwalkerHandler::try_new,
1319 )?;
1320
1321 Ok(Box::new(handler))
1322}
1323static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1324 primary_resource: ResourceType::Energy,
1325 secondary_resource: Some(ResourceType::Chi),
1326 spell_ids: DECLARED_SPELL_IDS,
1327 aura_ids: DECLARED_AURA_IDS,
1328 server_proc_entries: &[
1329 DeclaredServerProcEntry {
1330 spell_id: 129_914,
1331 attributes: ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1332 },
1333 ],
1334 talents: TALENTS,
1335 rotation_field_schema: &[],
1336 metrics_plugin_id: None,
1337 hero_talent_trees: &[
1338 HeroTalentTreeDesc {
1339 name: "Shado Pan",
1340 spells: HERO_TREE_SHADO_PAN_SPELLS,
1341 auras: HERO_TREE_SHADO_PAN_AURAS,
1342 },
1343 HeroTalentTreeDesc {
1344 name: "Conduit Of The Celestials",
1345 spells: HERO_TREE_CONDUIT_OF_THE_CELESTIALS_SPELLS,
1346 auras: HERO_TREE_CONDUIT_OF_THE_CELESTIALS_AURAS,
1347 },
1348 HeroTalentTreeDesc {
1349 name: "Master Of Harmony",
1350 spells: HERO_TREE_MASTER_OF_HARMONY_SPELLS,
1351 auras: HERO_TREE_MASTER_OF_HARMONY_AURAS,
1352 },
1353 ],
1354 reported_spells: REPORTED_SPELLS,
1355 masked_passive_effects: &[],
1356 passive_effect_overrides: &[],
1357};
1358pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1359 spec_id: SpecId::Windwalker,
1360 display_name: "Windwalker Monk",
1361 metadata: DECLARED_METADATA,
1362 handler_factory: new_handler,
1363};
1364wowlab_engine_combat::smoke_test!(build_combat_system);