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 MOONKIN_FORM: u32 = 24858;
18 pub(crate) const MARK_OF_THE_WILD: u32 = 1126;
20 pub(crate) const WRATH: u32 = 190_984;
22 pub(crate) const STARFIRE: u32 = 194_153;
24 pub(crate) const SOLAR_ECLIPSE: u32 = 1_233_346;
26 pub(crate) const CELESTIAL_ALIGNMENT: u32 = 194_223;
28 pub(crate) const INCARNATION_CHOSEN_OF_ELUNE: u32 = 102_560;
30 pub(crate) const MOONFIRE: u32 = 8921;
32 pub(crate) const SUNFIRE: u32 = 93402;
34 pub(crate) const STARSURGE: u32 = 78674;
36 pub(crate) const STARFALL: u32 = 191_034;
38 pub(crate) const NEW_MOON: u32 = 274_281;
40 pub(crate) const FURY_OF_ELUNE: u32 = 202_770;
42 pub(crate) const FORCE_OF_NATURE: u32 = 205_636;
44 pub(crate) const CONVOKE_THE_SPIRITS: u32 = 391_528;
46 pub(crate) const WILD_MUSHROOM: u32 = 88747;
48}
49pub(crate) mod AURA {
50 pub(crate) const MOONKIN_FORM: u32 = 24858;
52 pub(crate) const MARK_OF_THE_WILD_HIGHLIGHT: u32 = 1126;
54 pub(crate) const HARMONY_OF_THE_GROVE: u32 = 428_737;
56 pub(crate) const DREAM_SURGE: u32 = 433_831;
58 pub(crate) const ATMOSPHERIC_EXPOSURE: u32 = 430_589;
60 pub(crate) const ECLIPSE_SOLAR: u32 = 48517;
62 pub(crate) const ECLIPSE_LUNAR: u32 = 48518;
64 pub(crate) const CELESTIAL_ALIGNMENT: u32 = 194_223;
66 pub(crate) const INCARNATION_CHOSEN_OF_ELUNE: u32 = 102_560;
68 pub(crate) const LUNAR_ECLIPSE_OVERRIDE: u32 = 1_233_353;
70 pub(crate) const ECLIPSE: u32 = 1_239_669;
72 pub(crate) const LUNAR_CALLING: u32 = 429_523;
74 pub(crate) const DREAMSTATE: u32 = 450_346;
76 pub(crate) const MOONFIRE: u32 = 164_812;
78 pub(crate) const SUNFIRE: u32 = 164_815;
80 pub(crate) const STARFALL: u32 = 191_034;
82 pub(crate) const STARLORD: u32 = 279_709;
84 pub(crate) const STARWEAVER_S_WARP: u32 = 393_942;
86 pub(crate) const STARWEAVER_S_WEFT: u32 = 393_944;
88 pub(crate) const TOUCH_THE_COSMOS: u32 = 450_360;
90 pub(crate) const SOLSTICE: u32 = 343_648;
92 pub(crate) const STELLAR_AMPLIFICATION: u32 = 450_214;
94 pub(crate) const BOAT_ARCANE: u32 = 394_050;
96 pub(crate) const BOAT_NATURE: u32 = 394_049;
98 pub(crate) const FUNGAL_GROWTH: u32 = 81281;
100 pub(crate) const NATURES_BALANCE: u32 = 202_430;
102 pub(crate) const FURY_OF_ELUNE_ENERGIZE: u32 = 202_770;
104 pub(crate) const FURY_OF_ELUNE_BEAM: u32 = 211_545;
106 pub(crate) const SUNDERED_FIRMAMENT_ENERGIZE: u32 = 394_108;
108 pub(crate) const SUNDERED_FIRMAMENT_BEAM: u32 = 394_111;
110 pub(crate) const SUNSEEKER_MUSHROOM_DRIVER: u32 = 468_938;
112}
113pub(crate) mod TALENT {
114 pub(crate) const ASCENDANT_ECLIPSES_2: u32 = 1_261_565;
116 pub(crate) const ATMOSPHERIC_EXPOSURE: u32 = 429_532;
118 pub(crate) const BALANCE_OF_ALL_THINGS: u32 = 394_048;
120 pub(crate) const CONVOKE_THE_SPIRITS: u32 = 391_528;
122 pub(crate) const ECLIPSE: u32 = 1_239_669;
124 pub(crate) const FORCE_OF_NATURE: u32 = 205_636;
126 pub(crate) const FURY_OF_ELUNE: u32 = 202_770;
128 pub(crate) const HAIL_OF_STARS: u32 = 469_004;
130 pub(crate) const IMPROVED_ECLIPSE: u32 = 1_240_906;
132 pub(crate) const INCARNATION_CHOSEN_OF_ELUNE: u32 = 102_560;
134 pub(crate) const LUNAR_CALLING: u32 = 429_523;
136 pub(crate) const MOON_GUARDIAN: u32 = 429_520;
138 pub(crate) const NATURE_S_BALANCE: u32 = 202_430;
140 pub(crate) const NEW_MOON: u32 = 274_281;
142 pub(crate) const POWER_OF_GOLDRINN: u32 = 394_046;
144 pub(crate) const RATTLE_THE_STARS: u32 = 393_954;
146 pub(crate) const SHOOTING_STARS: u32 = 202_342;
148 pub(crate) const SOLSTICE: u32 = 343_647;
150 pub(crate) const STARLORD: u32 = 202_345;
152 pub(crate) const STARWEAVER: u32 = 393_940;
154 pub(crate) const STAR_CASCADE: u32 = 1_271_206;
156 pub(crate) const STELLAR_AMPLIFICATION: u32 = 450_212;
158 pub(crate) const SUNDERED_FIRMAMENT: u32 = 394_094;
160 pub(crate) const SUNSEEKER_MUSHROOM: u32 = 468_936;
162 pub(crate) const TOUCH_THE_COSMOS: u32 = 450_356;
164 pub(crate) const UMBRAL_EMBRACE: u32 = 393_760;
166 pub(crate) const WHIRLING_STARS: u32 = 468_743;
168 pub(crate) const WILD_MUSHROOM: u32 = 88747;
170 pub(crate) const WILD_SURGES: u32 = 406_890;
172}
173pub(crate) mod SET_BONUS {
174 pub(crate) const MID1_BALANCE_2PC: u32 = 1_264_810;
176 pub(crate) const MID1_BALANCE_4PC: u32 = 1_264_811;
178}
179pub(crate) mod REPORTED_SPELL {
180 pub(crate) const ASTRAL_SMOLDER: u32 = 1_263_250;
182 pub(crate) const EXPLODING_STAR: u32 = 1_272_339;
184 pub(crate) const FUNGAL_GROWTH: u32 = 1_280_213;
186 pub(crate) const GOLDRINN: u32 = 394_047;
188 pub(crate) const MOONFIRE_PERIODIC: u32 = 164_812;
190 pub(crate) const SHOOTING_STARS: u32 = 202_497;
192 pub(crate) const STARSURGE_CASCADE: u32 = 1_271_222;
194 pub(crate) const SUNFIRE_PERIODIC: u32 = 164_815;
196 pub(crate) const SUNSEEKER_MUSHROOM: u32 = 1_280_212;
198 pub(crate) const WILD_MUSHROOM: u32 = 88751;
200}
201pub(crate) mod HERO {
202 pub(crate) mod KEEPER_OF_THE_GROVE {
203 pub(crate) mod SPELL {
204 pub(crate) const DREAM_BURST: u32 = 433_850;
206 pub(crate) const FORCE_OF_NATURE: u32 = 205_636;
208 }
209 pub(crate) mod AURA {
210 pub(crate) const BLOOMING_INFUSION: u32 = 429_433;
212 pub(crate) const CENARIUS_MIGHT: u32 = 455_801;
214 pub(crate) const DREAM_SURGE: u32 = 433_831;
216 pub(crate) const HARMONY_OF_THE_GROVE: u32 = 428_737;
218 }
219 }
220 pub(crate) mod ELUNES_CHOSEN {
221 pub(crate) mod SPELL {
222 pub(crate) const LUNAR_BOLT: u32 = 1_261_700;
224 pub(crate) const ORBITAL_STRIKE: u32 = 361_237;
226 pub(crate) const SOLAR_BOLT: u32 = 1_261_573;
228 }
229 pub(crate) mod AURA {
230 pub(crate) const ASCENDANT_FIRES: u32 = 1_263_363;
232 pub(crate) const ASCENDANT_STARS: u32 = 1_263_382;
234 pub(crate) const ATMOSPHERIC_EXPOSURE: u32 = 430_589;
236 pub(crate) const LUNAR_CALLING: u32 = 429_523;
238 pub(crate) const PARTING_SKIES: u32 = 395_110;
240 }
241 }
242}
243static HERO_TREE_KEEPER_OF_THE_GROVE_SPELLS: &[(&str, u32)] = &[
244 ("DREAM_BURST", 433_850),
245 ("FORCE_OF_NATURE", 205_636),
246];
247static HERO_TREE_KEEPER_OF_THE_GROVE_AURAS: &[(&str, u32)] = &[
248 ("BLOOMING_INFUSION", 429_433),
249 ("CENARIUS_MIGHT", 455_801),
250 ("DREAM_SURGE", 433_831),
251 ("HARMONY_OF_THE_GROVE", 428_737),
252];
253static HERO_TREE_ELUNES_CHOSEN_SPELLS: &[(&str, u32)] = &[
254 ("LUNAR_BOLT", 1_261_700),
255 ("ORBITAL_STRIKE", 361_237),
256 ("SOLAR_BOLT", 1_261_573),
257];
258static HERO_TREE_ELUNES_CHOSEN_AURAS: &[(&str, u32)] = &[
259 ("ASCENDANT_FIRES", 1_263_363),
260 ("ASCENDANT_STARS", 1_263_382),
261 ("ATMOSPHERIC_EXPOSURE", 430_589),
262 ("LUNAR_CALLING", 429_523),
263 ("PARTING_SKIES", 395_110),
264];
265pub(crate) const AURA_MOONKIN_FORM: LocalAuraIdx = LocalAuraIdx::new(0);
266pub(crate) const AURA_MARK_OF_THE_WILD_HIGHLIGHT: LocalAuraIdx = LocalAuraIdx::new(1);
267pub(crate) const AURA_HARMONY_OF_THE_GROVE: LocalAuraIdx = LocalAuraIdx::new(2);
268pub(crate) const AURA_DREAM_SURGE: LocalAuraIdx = LocalAuraIdx::new(3);
269pub(crate) const AURA_ATMOSPHERIC_EXPOSURE: LocalAuraIdx = LocalAuraIdx::new(4);
270pub(crate) const AURA_ECLIPSE_SOLAR: LocalAuraIdx = LocalAuraIdx::new(5);
271pub(crate) const AURA_ECLIPSE_LUNAR: LocalAuraIdx = LocalAuraIdx::new(6);
272pub(crate) const AURA_CELESTIAL_ALIGNMENT: LocalAuraIdx = LocalAuraIdx::new(7);
273pub(crate) const AURA_INCARNATION_CHOSEN_OF_ELUNE: LocalAuraIdx = LocalAuraIdx::new(8);
274pub(crate) const AURA_LUNAR_ECLIPSE_OVERRIDE: LocalAuraIdx = LocalAuraIdx::new(9);
275pub(crate) const AURA_ECLIPSE: LocalAuraIdx = LocalAuraIdx::new(10);
276pub(crate) const AURA_LUNAR_CALLING: LocalAuraIdx = LocalAuraIdx::new(11);
277pub(crate) const AURA_DREAMSTATE: LocalAuraIdx = LocalAuraIdx::new(12);
278pub(crate) const AURA_MOONFIRE: LocalAuraIdx = LocalAuraIdx::new(13);
279pub(crate) const AURA_SUNFIRE: LocalAuraIdx = LocalAuraIdx::new(14);
280pub(crate) const AURA_STARFALL: LocalAuraIdx = LocalAuraIdx::new(15);
281pub(crate) const AURA_STARLORD: LocalAuraIdx = LocalAuraIdx::new(16);
282pub(crate) const AURA_STARWEAVER_S_WARP: LocalAuraIdx = LocalAuraIdx::new(17);
283pub(crate) const AURA_STARWEAVER_S_WEFT: LocalAuraIdx = LocalAuraIdx::new(18);
284pub(crate) const AURA_TOUCH_THE_COSMOS: LocalAuraIdx = LocalAuraIdx::new(19);
285pub(crate) const AURA_SOLSTICE: LocalAuraIdx = LocalAuraIdx::new(20);
286pub(crate) const AURA_STELLAR_AMPLIFICATION: LocalAuraIdx = LocalAuraIdx::new(21);
287pub(crate) const AURA_BOAT_ARCANE: LocalAuraIdx = LocalAuraIdx::new(22);
288pub(crate) const AURA_BOAT_NATURE: LocalAuraIdx = LocalAuraIdx::new(23);
289pub(crate) const AURA_FUNGAL_GROWTH: LocalAuraIdx = LocalAuraIdx::new(24);
290pub(crate) const AURA_NATURES_BALANCE: LocalAuraIdx = LocalAuraIdx::new(25);
291pub(crate) const AURA_FURY_OF_ELUNE_ENERGIZE: LocalAuraIdx = LocalAuraIdx::new(26);
292pub(crate) const AURA_FURY_OF_ELUNE_BEAM: LocalAuraIdx = LocalAuraIdx::new(27);
293pub(crate) const AURA_SUNDERED_FIRMAMENT_ENERGIZE: LocalAuraIdx = LocalAuraIdx::new(28);
294pub(crate) const AURA_SUNDERED_FIRMAMENT_BEAM: LocalAuraIdx = LocalAuraIdx::new(29);
295pub(crate) const AURA_SUNSEEKER_MUSHROOM_DRIVER: LocalAuraIdx = LocalAuraIdx::new(30);
296pub(crate) const AURA_COUNT: usize = 31;
297const _: () = assert!(
298 AURA_COUNT == 31, "AURA index ABI: count changed -- update positional hook consumers"
299);
300pub(crate) const SPELL_MOONKIN_FORM: LocalSpellIdx = LocalSpellIdx::new(0);
301pub(crate) const SPELL_MARK_OF_THE_WILD: LocalSpellIdx = LocalSpellIdx::new(1);
302pub(crate) const SPELL_WRATH: LocalSpellIdx = LocalSpellIdx::new(2);
303pub(crate) const SPELL_STARFIRE: LocalSpellIdx = LocalSpellIdx::new(3);
304pub(crate) const SPELL_SOLAR_ECLIPSE: LocalSpellIdx = LocalSpellIdx::new(4);
305pub(crate) const SPELL_CELESTIAL_ALIGNMENT: LocalSpellIdx = LocalSpellIdx::new(5);
306pub(crate) const SPELL_INCARNATION_CHOSEN_OF_ELUNE: LocalSpellIdx = LocalSpellIdx::new(
307 6,
308);
309pub(crate) const SPELL_MOONFIRE: LocalSpellIdx = LocalSpellIdx::new(7);
310pub(crate) const SPELL_SUNFIRE: LocalSpellIdx = LocalSpellIdx::new(8);
311pub(crate) const SPELL_STARSURGE: LocalSpellIdx = LocalSpellIdx::new(9);
312pub(crate) const SPELL_STARFALL: LocalSpellIdx = LocalSpellIdx::new(10);
313pub(crate) const SPELL_NEW_MOON: LocalSpellIdx = LocalSpellIdx::new(11);
314pub(crate) const SPELL_FURY_OF_ELUNE: LocalSpellIdx = LocalSpellIdx::new(12);
315pub(crate) const SPELL_FORCE_OF_NATURE: LocalSpellIdx = LocalSpellIdx::new(13);
316pub(crate) const SPELL_CONVOKE_THE_SPIRITS: LocalSpellIdx = LocalSpellIdx::new(14);
317pub(crate) const SPELL_WILD_MUSHROOM: LocalSpellIdx = LocalSpellIdx::new(15);
318pub(crate) const SPELL_COUNT: usize = 16;
319const _: () = assert!(
320 SPELL_COUNT == 16,
321 "SPELL index ABI: count changed -- update positional hook consumers"
322);
323pub(crate) mod EFFECT {
324 pub(crate) const ASTRAL_INVOCATION_ARCANE_DIRECT: (u32, u8) = (393_014, 1);
326 pub(crate) const ASTRAL_INVOCATION_ARCANE_PERIODIC: (u32, u8) = (393_014, 2);
328 pub(crate) const ASTRAL_INVOCATION_NATURE_DIRECT: (u32, u8) = (393_014, 3);
330 pub(crate) const ASTRAL_INVOCATION_NATURE_PERIODIC: (u32, u8) = (393_014, 4);
332 pub(crate) const ASTRAL_POWER_WRATH_AP: (u32, u8) = (197_911, 2);
334 pub(crate) const ASTRAL_SMOLDER_PCT: (u32, u8) = (1_261_565, 1);
336 pub(crate) const EXPLODING_STAR_AP: (u32, u8) = (1_272_339, 2);
338 pub(crate) const EXPLODING_STAR_DMG: (u32, u8) = (1_272_339, 1);
340 pub(crate) const FUNGAL_GROWTH_SUNSEEKER: (u32, u8) = (1_280_213, 1);
342 pub(crate) const GOLDRINN_DMG: (u32, u8) = (394_047, 1);
344 pub(crate) const HAIL_OF_STARS_MS: (u32, u8) = (469_004, 1);
346 pub(crate) const MID1_2PC_AP: (u32, u8) = (1_264_810, 2);
348 pub(crate) const MID1_4PC_EXPLODING_CHANCE: (u32, u8) = (1_264_811, 2);
350 pub(crate) const MOON_GUARDIAN_AP: (u32, u8) = (429_520, 1);
352 pub(crate) const NATURES_BALANCE_START: (u32, u8) = (202_430, 2);
354 pub(crate) const RATTLE_COST_PCT: (u32, u8) = (393_954, 2);
356 pub(crate) const SHOOTING_STARS_AP: (u32, u8) = (202_497, 2);
358 pub(crate) const SHOOTING_STARS_CHANCE: (u32, u8) = (202_342, 1);
360 pub(crate) const SHOOTING_STARS_DMG: (u32, u8) = (202_497, 1);
362 pub(crate) const STARFALL_DAMAGE: (u32, u8) = (191_037, 1);
364 pub(crate) const STARFALL_GEOMETRY: (u32, u8) = (50286, 1);
366 pub(crate) const SOLSTICE_RATE: (u32, u8) = (343_647, 1);
368 pub(crate) const STARSURGE_CASCADE_DMG: (u32, u8) = (1_271_222, 1);
370 pub(crate) const STAR_CASCADE_CHANCE: (u32, u8) = (1_271_206, 1);
372 pub(crate) const STAR_CASCADE_EFFECTIVENESS: (u32, u8) = (1_271_206, 3);
374 pub(crate) const STELLAR_AMP_CAP: (u32, u8) = (450_212, 1);
376 pub(crate) const TTC_CHANCE_STARFIRE: (u32, u8) = (450_356, 2);
378 pub(crate) const TTC_CHANCE_WRATH: (u32, u8) = (450_356, 1);
380 pub(crate) const WHIRLING_STARS_CDR: (u32, u8) = (468_743, 3);
382 pub(crate) const WILD_MUSHROOM_AP_CAP: (u32, u8) = (88751, 2);
384 pub(crate) const SUNSEEKER_MUSHROOM_AP_CAP: (u32, u8) = (1_280_212, 2);
386 pub(crate) const WILD_SURGES_AP: (u32, u8) = (406_890, 2);
388}
389static REPORTED_SPELLS: &[(&str, u32)] = &[
390 ("astral_smolder", 1_263_250),
391 ("exploding_star", 1_272_339),
392 ("fungal_growth", 1_280_213),
393 ("goldrinn", 394_047),
394 ("moonfire_periodic", 164_812),
395 ("shooting_stars", 202_497),
396 ("starsurge_cascade", 1_271_222),
397 ("sunfire_periodic", 164_815),
398 ("sunseeker_mushroom", 1_280_212),
399 ("wild_mushroom", 88751),
400];
401static DECLARED_SPELL_IDS: &[u32] = &[
402 24858, 1126, 190_984, 194_153, 1_233_346, 194_223, 102_560, 8921, 93402, 78674,
403 191_034, 274_281, 202_770, 205_636, 391_528, 88747, 24858, 1126, 428_737, 433_831,
404 430_589, 48517, 48518, 194_223, 102_560, 1_233_353, 1_239_669, 429_523, 450_346,
405 164_812, 164_815, 191_034, 279_709, 393_942, 393_944, 450_360, 343_648, 450_214,
406 394_050, 394_049, 81281, 202_430, 202_770, 211_545, 394_108, 394_111, 468_938, 50286,
407 88751, 164_812, 164_815, 191_034, 191_037, 197_911, 202_342, 202_430, 202_497,
408 202_770, 211_545, 343_647, 393_014, 393_954, 394_047, 394_048, 394_049, 394_050,
409 394_106, 394_111, 406_890, 429_520, 450_212, 450_356, 468_743, 469_004, 1_261_565,
410 1_263_250, 1_264_810, 1_264_811, 1_271_206, 1_271_222, 1_272_339, 1_280_212,
411 1_280_213, 1_263_250, 1_272_339, 1_280_213, 394_047, 164_812, 202_497, 1_271_222,
412 164_815, 1_280_212, 88751, 433_850, 205_636, 429_433, 455_801, 433_831, 428_737,
413 1_261_700, 361_237, 1_261_573, 1_263_363, 1_263_382, 430_589, 429_523, 395_110,
414];
415static DECLARED_AURA_IDS: &[u32] = &[
416 24858, 1126, 428_737, 433_831, 430_589, 48517, 48518, 194_223, 102_560, 1_233_353,
417 1_239_669, 429_523, 450_346, 164_812, 164_815, 191_034, 279_709, 393_942, 393_944,
418 450_360, 343_648, 450_214, 394_050, 394_049, 81281, 202_430, 202_770, 211_545,
419 394_108, 394_111, 468_938, 429_433, 455_801, 433_831, 428_737, 1_263_363, 1_263_382,
420 430_589, 429_523, 395_110,
421];
422static TALENTS: &[(&str, u32)] = &[
423 ("ASCENDANT_ECLIPSES_2", TALENT::ASCENDANT_ECLIPSES_2),
424 ("ATMOSPHERIC_EXPOSURE", TALENT::ATMOSPHERIC_EXPOSURE),
425 ("BALANCE_OF_ALL_THINGS", TALENT::BALANCE_OF_ALL_THINGS),
426 ("CONVOKE_THE_SPIRITS", TALENT::CONVOKE_THE_SPIRITS),
427 ("ECLIPSE", TALENT::ECLIPSE),
428 ("FORCE_OF_NATURE", TALENT::FORCE_OF_NATURE),
429 ("FURY_OF_ELUNE", TALENT::FURY_OF_ELUNE),
430 ("HAIL_OF_STARS", TALENT::HAIL_OF_STARS),
431 ("IMPROVED_ECLIPSE", TALENT::IMPROVED_ECLIPSE),
432 ("INCARNATION_CHOSEN_OF_ELUNE", TALENT::INCARNATION_CHOSEN_OF_ELUNE),
433 ("LUNAR_CALLING", TALENT::LUNAR_CALLING),
434 ("MOON_GUARDIAN", TALENT::MOON_GUARDIAN),
435 ("NATURE_S_BALANCE", TALENT::NATURE_S_BALANCE),
436 ("NEW_MOON", TALENT::NEW_MOON),
437 ("POWER_OF_GOLDRINN", TALENT::POWER_OF_GOLDRINN),
438 ("RATTLE_THE_STARS", TALENT::RATTLE_THE_STARS),
439 ("SHOOTING_STARS", TALENT::SHOOTING_STARS),
440 ("SOLSTICE", TALENT::SOLSTICE),
441 ("STARLORD", TALENT::STARLORD),
442 ("STARWEAVER", TALENT::STARWEAVER),
443 ("STAR_CASCADE", TALENT::STAR_CASCADE),
444 ("STELLAR_AMPLIFICATION", TALENT::STELLAR_AMPLIFICATION),
445 ("SUNDERED_FIRMAMENT", TALENT::SUNDERED_FIRMAMENT),
446 ("SUNSEEKER_MUSHROOM", TALENT::SUNSEEKER_MUSHROOM),
447 ("TOUCH_THE_COSMOS", TALENT::TOUCH_THE_COSMOS),
448 ("UMBRAL_EMBRACE", TALENT::UMBRAL_EMBRACE),
449 ("WHIRLING_STARS", TALENT::WHIRLING_STARS),
450 ("WILD_MUSHROOM", TALENT::WILD_MUSHROOM),
451 ("WILD_SURGES", TALENT::WILD_SURGES),
452];
453pub(crate) mod BALANCE_DRUID {
454 pub(crate) const WRATH_CASTS: u32 = 0;
455 pub(crate) const STARFIRE_CASTS: u32 = 1;
456 pub(crate) const STARSURGE_CASTS: u32 = 2;
457 pub(crate) const STARFALL_CASTS: u32 = 3;
458 pub(crate) const MOONFIRE_CASTS: u32 = 4;
459 pub(crate) const SUNFIRE_CASTS: u32 = 5;
460 pub(crate) const CELESTIAL_ALIGNMENT_CASTS: u32 = 6;
461 pub(crate) const ECLIPSE_SOLAR_UPTIME_MS: u32 = 7;
462 pub(crate) const ECLIPSE_LUNAR_UPTIME_MS: u32 = 8;
463 pub(crate) const STARLORD_UPTIME_MS: u32 = 9;
464}
465fn aura_moonkin_form(
466 a: AuraDefinitionDraft,
467 data: &ResolvedGameData,
468) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
469 Ok(
470 a
471 .on_player()
472 .apply_base_from_data(data, 24858)?
473 .max_stacks(
474 data
475 .require_aura_max_stacks(
476 wowlab_types::sim::SpellIdx::from_raw(24858),
477 )?,
478 ),
479 )
480}
481fn aura_mark_of_the_wild_highlight(
482 a: AuraDefinitionDraft,
483 data: &ResolvedGameData,
484) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
485 Ok(
486 a
487 .on_player()
488 .apply_base_from_data(data, 1126)?
489 .max_stacks(
490 data
491 .require_aura_max_stacks(
492 wowlab_types::sim::SpellIdx::from_raw(1126),
493 )?,
494 ),
495 )
496}
497fn aura_harmony_of_the_grove(
498 a: AuraDefinitionDraft,
499 data: &ResolvedGameData,
500) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
501 Ok(
502 a
503 .on_player()
504 .apply_base_from_data(data, 428_737)?
505 .max_stacks(
506 data
507 .require_aura_max_stacks(
508 wowlab_types::sim::SpellIdx::from_raw(428_737),
509 )?,
510 ),
511 )
512}
513fn aura_dream_surge(
514 a: AuraDefinitionDraft,
515 data: &ResolvedGameData,
516) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
517 Ok(
518 a
519 .on_target()
520 .apply_base_from_data(data, 433_831)?
521 .max_stacks(
522 data
523 .require_aura_max_stacks(
524 wowlab_types::sim::SpellIdx::from_raw(433_831),
525 )?,
526 ),
527 )
528}
529fn aura_atmospheric_exposure(
530 a: AuraDefinitionDraft,
531 data: &ResolvedGameData,
532) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
533 Ok(
534 a
535 .on_target()
536 .apply_base_from_data(data, 430_589)?
537 .max_stacks(
538 data
539 .require_aura_max_stacks(
540 wowlab_types::sim::SpellIdx::from_raw(430_589),
541 )?,
542 ),
543 )
544}
545fn aura_eclipse_solar(
546 a: AuraDefinitionDraft,
547 data: &ResolvedGameData,
548) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
549 Ok(
550 a
551 .on_player()
552 .apply_base_from_data(data, 48517)?
553 .max_stacks(
554 data
555 .require_aura_max_stacks(
556 wowlab_types::sim::SpellIdx::from_raw(48517),
557 )?,
558 ),
559 )
560}
561fn aura_eclipse_lunar(
562 a: AuraDefinitionDraft,
563 data: &ResolvedGameData,
564) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
565 Ok(
566 a
567 .on_player()
568 .apply_base_from_data(data, 48518)?
569 .max_stacks(
570 data
571 .require_aura_max_stacks(
572 wowlab_types::sim::SpellIdx::from_raw(48518),
573 )?,
574 ),
575 )
576}
577fn aura_celestial_alignment(
578 a: AuraDefinitionDraft,
579 data: &ResolvedGameData,
580) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
581 Ok(
582 a
583 .on_player()
584 .apply_base_from_data(data, 194_223)?
585 .max_stacks(
586 data
587 .require_aura_max_stacks(
588 wowlab_types::sim::SpellIdx::from_raw(194_223),
589 )?,
590 ),
591 )
592}
593fn aura_incarnation_chosen_of_elune(
594 a: AuraDefinitionDraft,
595 data: &ResolvedGameData,
596) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
597 Ok(
598 a
599 .on_player()
600 .apply_base_from_data(data, 102_560)?
601 .max_stacks(
602 data
603 .require_aura_max_stacks(
604 wowlab_types::sim::SpellIdx::from_raw(102_560),
605 )?,
606 ),
607 )
608}
609fn aura_lunar_eclipse_override(
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_233_353)?
617 .max_stacks(
618 data
619 .require_aura_max_stacks(
620 wowlab_types::sim::SpellIdx::from_raw(1_233_353),
621 )?,
622 ),
623 )
624}
625fn aura_eclipse(
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_239_669)?
633 .max_stacks(
634 data
635 .require_aura_max_stacks(
636 wowlab_types::sim::SpellIdx::from_raw(1_239_669),
637 )?,
638 ),
639 )
640}
641fn aura_lunar_calling(
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, 429_523)?
649 .max_stacks(
650 data
651 .require_aura_max_stacks(
652 wowlab_types::sim::SpellIdx::from_raw(429_523),
653 )?,
654 ),
655 )
656}
657fn aura_dreamstate(
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, 450_346)?
665 .max_stacks(
666 data
667 .require_aura_max_stacks(
668 wowlab_types::sim::SpellIdx::from_raw(450_346),
669 )?,
670 ),
671 )
672}
673fn aura_moonfire(
674 a: AuraDefinitionDraft,
675 data: &ResolvedGameData,
676) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
677 Ok(
678 a
679 .on_target()
680 .apply_base_from_data(data, 164_812)?
681 .max_stacks(
682 data
683 .require_aura_max_stacks(
684 wowlab_types::sim::SpellIdx::from_raw(164_812),
685 )?,
686 ),
687 )
688}
689fn aura_sunfire(
690 a: AuraDefinitionDraft,
691 data: &ResolvedGameData,
692) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
693 Ok(
694 a
695 .on_target()
696 .apply_base_from_data(data, 164_815)?
697 .max_stacks(
698 data
699 .require_aura_max_stacks(
700 wowlab_types::sim::SpellIdx::from_raw(164_815),
701 )?,
702 ),
703 )
704}
705fn aura_starfall(
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, 191_034)?
713 .max_stacks(
714 data
715 .require_aura_max_stacks(
716 wowlab_types::sim::SpellIdx::from_raw(191_034),
717 )?,
718 )
719 .periodic_hook(
720 wowlab_engine_combat::validated_milliseconds(
721 data.period(wowlab_types::sim::SpellIdx::from_raw(191_034), 3),
722 191_034,
723 "periodic_hook.tick_ms",
724 )?,
725 )
726 .apply_periodic_behavior_from_data(data, 191_034)?
727 .tick_hook(crate::hooks::balance_druid::starfall_tick_hook),
728 )
729}
730fn aura_starlord(
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, 279_709)?
738 .max_stacks(
739 data
740 .require_aura_max_stacks(
741 wowlab_types::sim::SpellIdx::from_raw(279_709),
742 )?,
743 ),
744 )
745}
746fn aura_starweaver_s_warp(
747 a: AuraDefinitionDraft,
748 data: &ResolvedGameData,
749) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
750 Ok(
751 a
752 .on_player()
753 .apply_base_from_data(data, 393_942)?
754 .max_stacks(
755 data
756 .require_aura_max_stacks(
757 wowlab_types::sim::SpellIdx::from_raw(393_942),
758 )?,
759 ),
760 )
761}
762fn aura_starweaver_s_weft(
763 a: AuraDefinitionDraft,
764 data: &ResolvedGameData,
765) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
766 Ok(
767 a
768 .on_player()
769 .apply_base_from_data(data, 393_944)?
770 .max_stacks(
771 data
772 .require_aura_max_stacks(
773 wowlab_types::sim::SpellIdx::from_raw(393_944),
774 )?,
775 ),
776 )
777}
778fn aura_touch_the_cosmos(
779 a: AuraDefinitionDraft,
780 data: &ResolvedGameData,
781) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
782 Ok(
783 a
784 .on_player()
785 .apply_base_from_data(data, 450_360)?
786 .max_stacks(
787 data
788 .require_aura_max_stacks(
789 wowlab_types::sim::SpellIdx::from_raw(450_360),
790 )?,
791 ),
792 )
793}
794fn aura_solstice(
795 a: AuraDefinitionDraft,
796 data: &ResolvedGameData,
797) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
798 Ok(
799 a
800 .on_player()
801 .apply_base_from_data(data, 343_648)?
802 .max_stacks(
803 data
804 .require_aura_max_stacks(
805 wowlab_types::sim::SpellIdx::from_raw(343_648),
806 )?,
807 ),
808 )
809}
810fn aura_stellar_amplification(
811 a: AuraDefinitionDraft,
812 data: &ResolvedGameData,
813) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
814 Ok(
815 a
816 .on_target()
817 .apply_base_from_data(data, 450_214)?
818 .max_stacks(
819 data
820 .require_aura_max_stacks(
821 wowlab_types::sim::SpellIdx::from_raw(450_214),
822 )?,
823 ),
824 )
825}
826fn aura_boat_arcane(
827 a: AuraDefinitionDraft,
828 data: &ResolvedGameData,
829) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
830 Ok(
831 a
832 .on_player()
833 .apply_base_from_data(data, 394_050)?
834 .max_stacks(
835 data
836 .require_aura_max_stacks(
837 wowlab_types::sim::SpellIdx::from_raw(394_050),
838 )?,
839 )
840 .crit_per_stack(
841 data.base_points(wowlab_types::sim::SpellIdx::from_raw(394_048), 1),
842 )?
843 .reverse()
844 .periodic_stack_tick(
845 wowlab_engine_combat::validated_milliseconds(
846 data.period(wowlab_types::sim::SpellIdx::from_raw(394_049), 2),
847 394_050,
848 "aura.stack_tick_ms",
849 )?,
850 )
851 .clip_tick_behavior(1),
852 )
853}
854fn aura_boat_nature(
855 a: AuraDefinitionDraft,
856 data: &ResolvedGameData,
857) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
858 Ok(
859 a
860 .on_player()
861 .apply_base_from_data(data, 394_049)?
862 .max_stacks(
863 data
864 .require_aura_max_stacks(
865 wowlab_types::sim::SpellIdx::from_raw(394_049),
866 )?,
867 )
868 .crit_per_stack(
869 data.base_points(wowlab_types::sim::SpellIdx::from_raw(394_048), 1),
870 )?
871 .reverse()
872 .periodic_stack_tick(
873 wowlab_engine_combat::validated_milliseconds(
874 data.period(wowlab_types::sim::SpellIdx::from_raw(394_050), 2),
875 394_049,
876 "aura.stack_tick_ms",
877 )?,
878 )
879 .clip_tick_behavior(1),
880 )
881}
882fn aura_fungal_growth(
883 a: AuraDefinitionDraft,
884 data: &ResolvedGameData,
885) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
886 Ok(
887 a
888 .on_target()
889 .apply_base_from_data(data, 81281)?
890 .max_stacks(
891 data
892 .require_aura_max_stacks(
893 wowlab_types::sim::SpellIdx::from_raw(81281),
894 )?,
895 ),
896 )
897}
898fn aura_natures_balance(
899 a: AuraDefinitionDraft,
900 data: &ResolvedGameData,
901) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
902 Ok(
903 a
904 .on_player()
905 .apply_base_from_data(data, 202_430)?
906 .max_stacks(
907 data
908 .require_aura_max_stacks(
909 wowlab_types::sim::SpellIdx::from_raw(202_430),
910 )?,
911 ),
912 )
913}
914fn aura_fury_of_elune_energize(
915 a: AuraDefinitionDraft,
916 data: &ResolvedGameData,
917) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
918 Ok(
919 a
920 .on_player()
921 .apply_base_from_data(data, 202_770)?
922 .max_stacks(
923 data
924 .require_aura_max_stacks(
925 wowlab_types::sim::SpellIdx::from_raw(202_770),
926 )?,
927 ),
928 )
929}
930fn aura_fury_of_elune_beam(
931 a: AuraDefinitionDraft,
932 data: &ResolvedGameData,
933) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
934 a.on_target()
935 .duration_ms(
936 wowlab_engine_combat::validated_milliseconds(
937 f64::from(
938 data
939 .require_aura_duration_ms(
940 wowlab_types::sim::SpellIdx::from_raw(202_770),
941 )?,
942 ),
943 211_545,
944 "aura.duration_ms",
945 )?,
946 )
947 .apply_periodic_effect_from_data(data, 211_545)?
948 .apply_duration_behavior_from_data(data, 202_770)?
949 .apply_timing_modifiers_from_data(data, 211_545)?
950 .max_stacks(
951 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(211_545))?,
952 )
953 .periodic_damage_sp(
954 wowlab_engine_combat::validated_milliseconds(
955 500.0,
956 211_545,
957 "periodic_damage.tick_ms",
958 )?,
959 ((data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(211_545), 1)) * 10000.0)
960 .round() / 10000.0,
961 wowlab_engine_combat::DamageFlags::empty(),
962 )
963 .apply_periodic_behavior_from_data(data, 202_770)
964}
965fn aura_sundered_firmament_energize(
966 a: AuraDefinitionDraft,
967 data: &ResolvedGameData,
968) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
969 Ok(
970 a
971 .on_player()
972 .apply_base_from_data(data, 394_108)?
973 .max_stacks(
974 data
975 .require_aura_max_stacks(
976 wowlab_types::sim::SpellIdx::from_raw(394_108),
977 )?,
978 ),
979 )
980}
981fn aura_sundered_firmament_beam(
982 a: AuraDefinitionDraft,
983 data: &ResolvedGameData,
984) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
985 a.on_target()
986 .duration_ms(
987 wowlab_engine_combat::validated_milliseconds(
988 f64::from(
989 data
990 .require_aura_duration_ms(
991 wowlab_types::sim::SpellIdx::from_raw(394_106),
992 )?,
993 ),
994 394_111,
995 "aura.duration_ms",
996 )?,
997 )
998 .apply_periodic_effect_from_data(data, 394_111)?
999 .apply_duration_behavior_from_data(data, 394_106)?
1000 .apply_timing_modifiers_from_data(data, 394_111)?
1001 .max_stacks(
1002 data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(394_111))?,
1003 )
1004 .periodic_damage_sp(
1005 wowlab_engine_combat::validated_milliseconds(
1006 500.0,
1007 394_111,
1008 "periodic_damage.tick_ms",
1009 )?,
1010 (((data.sp_coef(wowlab_types::sim::SpellIdx::from_raw(394_111), 1)) * 0.25)
1011 * 1000.0)
1012 .round() / 1000.0,
1013 wowlab_engine_combat::DamageFlags::empty(),
1014 )
1015 .apply_periodic_behavior_from_data(data, 394_106)
1016}
1017fn aura_sunseeker_mushroom_driver(
1018 a: AuraDefinitionDraft,
1019 data: &ResolvedGameData,
1020) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
1021 Ok(
1022 a
1023 .on_player()
1024 .apply_base_from_data(data, 468_938)?
1025 .max_stacks(
1026 data
1027 .require_aura_max_stacks(
1028 wowlab_types::sim::SpellIdx::from_raw(468_938),
1029 )?,
1030 ),
1031 )
1032}
1033fn spell_moonkin_form(
1034 s: SpellDefinitionDraft,
1035 data: &ResolvedGameData,
1036) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1037 Ok(
1038 s
1039 .apply_base_from_data(data, 24858)?
1040 .applies_inferred_aura(AURA_MOONKIN_FORM, 24858)
1041 .apply_aoe_from_data(data),
1042 )
1043}
1044fn spell_mark_of_the_wild(
1045 s: SpellDefinitionDraft,
1046 data: &ResolvedGameData,
1047) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1048 Ok(
1049 s
1050 .apply_base_from_data(data, 1126)?
1051 .applies_inferred_aura(AURA_MARK_OF_THE_WILD_HIGHLIGHT, 1126)
1052 .apply_aoe_from_data(data),
1053 )
1054}
1055fn spell_wrath(
1056 s: SpellDefinitionDraft,
1057 data: &ResolvedGameData,
1058) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1059 Ok(
1060 s
1061 .apply_base_from_data(data, 190_984)?
1062 .apply_aoe_from_data(data)
1063 .on_cast(crate::hooks::balance_druid::wrath_hook),
1064 )
1065}
1066fn spell_starfire(
1067 s: SpellDefinitionDraft,
1068 data: &ResolvedGameData,
1069) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1070 Ok(
1071 s
1072 .apply_base_from_data(data, 194_153)?
1073 .apply_aoe_from_data(data)
1074 .on_cast(crate::hooks::balance_druid::starfire_hook),
1075 )
1076}
1077fn spell_solar_eclipse(
1078 s: SpellDefinitionDraft,
1079 data: &ResolvedGameData,
1080) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1081 Ok(
1082 s
1083 .apply_base_from_data(data, 1_233_346)?
1084 .applies_aura(AURA_ECLIPSE_SOLAR)
1085 .apply_aoe_from_data(data)
1086 .on_cast(crate::hooks::balance_druid::eclipse_hook),
1087 )
1088}
1089fn spell_celestial_alignment(
1090 s: SpellDefinitionDraft,
1091 data: &ResolvedGameData,
1092) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1093 Ok(
1094 s
1095 .apply_base_from_data(data, 194_223)?
1096 .applies_aura(AURA_ECLIPSE_SOLAR)
1097 .applies_aura(AURA_ECLIPSE_LUNAR)
1098 .apply_aoe_from_data(data)
1099 .on_cast(crate::hooks::balance_druid::celestial_alignment_hook),
1100 )
1101}
1102fn spell_incarnation_chosen_of_elune(
1103 s: SpellDefinitionDraft,
1104 data: &ResolvedGameData,
1105) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1106 Ok(
1107 s
1108 .apply_base_from_data(data, 102_560)?
1109 .applies_aura(AURA_ECLIPSE_SOLAR)
1110 .applies_aura(AURA_ECLIPSE_LUNAR)
1111 .apply_aoe_from_data(data),
1112 )
1113}
1114fn spell_moonfire(
1115 s: SpellDefinitionDraft,
1116 data: &ResolvedGameData,
1117) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1118 Ok(
1119 s
1120 .apply_base_from_data(data, 8921)?
1121 .gain(
1122 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(197_911), 3))
1123 * 0.1,
1124 )
1125 .damage_sp_from_data(
1126 wowlab_engine_domain::dbc::EffectLookup::new(
1127 data,
1128 wowlab_types::sim::EffectRef::new(
1129 wowlab_types::sim::SpellIdx::from_raw(164_812),
1130 1,
1131 ),
1132 ),
1133 )?
1134 .applies_aura(AURA_MOONFIRE)
1135 .apply_aoe_from_data(data),
1136 )
1137}
1138fn spell_sunfire(
1139 s: SpellDefinitionDraft,
1140 data: &ResolvedGameData,
1141) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1142 Ok(
1143 s
1144 .apply_base_from_data(data, 93402)?
1145 .gain(
1146 (data.base_points(wowlab_types::sim::SpellIdx::from_raw(197_911), 3))
1147 * 0.1,
1148 )
1149 .damage_sp_from_data(
1150 wowlab_engine_domain::dbc::EffectLookup::new(
1151 data,
1152 wowlab_types::sim::EffectRef::new(
1153 wowlab_types::sim::SpellIdx::from_raw(164_815),
1154 1,
1155 ),
1156 ),
1157 )?
1158 .applies_aura(AURA_SUNFIRE)
1159 .apply_aoe_from_data(data),
1160 )
1161}
1162fn spell_starsurge(
1163 s: SpellDefinitionDraft,
1164 data: &ResolvedGameData,
1165) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1166 Ok(
1167 s
1168 .apply_base_from_data(data, 78674)?
1169 .applies_aura(AURA_STARLORD)
1170 .apply_aoe_from_data(data)
1171 .on_cast(crate::hooks::balance_druid::starsurge_hook)
1172 .cost_free_when_aura(450_360),
1173 )
1174}
1175fn spell_starfall(
1176 s: SpellDefinitionDraft,
1177 data: &ResolvedGameData,
1178) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1179 Ok(
1180 s
1181 .apply_base_from_data(data, 191_034)?
1182 .applies_aura(AURA_STARLORD)
1183 .apply_aoe_from_data(data),
1184 )
1185}
1186fn spell_new_moon(
1187 s: SpellDefinitionDraft,
1188 data: &ResolvedGameData,
1189) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1190 Ok(s.apply_base_from_data(data, 274_281)?.apply_aoe_from_data(data))
1191}
1192fn spell_fury_of_elune(
1193 s: SpellDefinitionDraft,
1194 data: &ResolvedGameData,
1195) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1196 Ok(
1197 s
1198 .apply_base_from_data(data, 202_770)?
1199 .applies_aura(AURA_FURY_OF_ELUNE_BEAM)
1200 .apply_aoe_from_data(data),
1201 )
1202}
1203fn spell_force_of_nature(
1204 s: SpellDefinitionDraft,
1205 data: &ResolvedGameData,
1206) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1207 Ok(s.apply_base_from_data(data, 205_636)?.apply_aoe_from_data(data))
1208}
1209fn spell_convoke_the_spirits(
1210 s: SpellDefinitionDraft,
1211 data: &ResolvedGameData,
1212) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1213 Ok(s.apply_base_from_data(data, 391_528)?.apply_aoe_from_data(data))
1214}
1215fn spell_wild_mushroom(
1216 s: SpellDefinitionDraft,
1217 data: &ResolvedGameData,
1218) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1219 Ok(
1220 s
1221 .apply_base_from_data(data, 88747)?
1222 .without_primary_data_damage()
1223 .apply_aoe_from_data(data),
1224 )
1225}
1226pub(crate) fn build_combat_system(
1227 params: &wowlab_engine_ports::HandlerParams<'_>,
1228) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1229 let builder = BuiltCombatSystem::builder(params.stats.clone())
1230 .spec_id(SpecId::Balance)
1231 .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1232 .mastery_spell(393_014)
1233 .mastery_hook(crate::hooks::balance_druid::mastery)
1234 .resource(
1235 "astral_power",
1236 100.0,
1237 params
1238 .game_data
1239 .power_regen_for_max(8, 100.0)
1240 .ok_or_else(|| {
1241 wowlab_engine_ports::EngineError::spec_construction(
1242 "missing power-type power_regen_for_max for type_id 8",
1243 )
1244 })?,
1245 )
1246 .resource_type_id(8)
1247 .resource_start(
1248 params
1249 .game_data
1250 .power_default(8)
1251 .ok_or_else(|| {
1252 wowlab_engine_ports::EngineError::spec_construction(
1253 "missing power-type power_default for type_id 8",
1254 )
1255 })?,
1256 )
1257 .aura(
1258 "moonkin_form",
1259 AURA::MOONKIN_FORM,
1260 |a| aura_moonkin_form(a, ¶ms.game_data),
1261 )
1262 .aura(
1263 "mark_of_the_wild_highlight",
1264 AURA::MARK_OF_THE_WILD_HIGHLIGHT,
1265 |a| aura_mark_of_the_wild_highlight(a, ¶ms.game_data),
1266 )
1267 .aura(
1268 "harmony_of_the_grove",
1269 AURA::HARMONY_OF_THE_GROVE,
1270 |a| aura_harmony_of_the_grove(a, ¶ms.game_data),
1271 )
1272 .aura(
1273 "dream_surge",
1274 AURA::DREAM_SURGE,
1275 |a| aura_dream_surge(a, ¶ms.game_data),
1276 )
1277 .aura(
1278 "atmospheric_exposure",
1279 AURA::ATMOSPHERIC_EXPOSURE,
1280 |a| aura_atmospheric_exposure(a, ¶ms.game_data),
1281 )
1282 .aura(
1283 "eclipse_solar",
1284 AURA::ECLIPSE_SOLAR,
1285 |a| aura_eclipse_solar(a, ¶ms.game_data),
1286 )
1287 .aura(
1288 "eclipse_lunar",
1289 AURA::ECLIPSE_LUNAR,
1290 |a| aura_eclipse_lunar(a, ¶ms.game_data),
1291 )
1292 .aura(
1293 "celestial_alignment",
1294 AURA::CELESTIAL_ALIGNMENT,
1295 |a| aura_celestial_alignment(a, ¶ms.game_data),
1296 )
1297 .aura(
1298 "incarnation_chosen_of_elune",
1299 AURA::INCARNATION_CHOSEN_OF_ELUNE,
1300 |a| aura_incarnation_chosen_of_elune(a, ¶ms.game_data),
1301 )
1302 .aura(
1303 "lunar_eclipse_override",
1304 AURA::LUNAR_ECLIPSE_OVERRIDE,
1305 |a| aura_lunar_eclipse_override(a, ¶ms.game_data),
1306 )
1307 .aura("eclipse", AURA::ECLIPSE, |a| aura_eclipse(a, ¶ms.game_data))
1308 .aura(
1309 "lunar_calling",
1310 AURA::LUNAR_CALLING,
1311 |a| aura_lunar_calling(a, ¶ms.game_data),
1312 )
1313 .aura("dreamstate", AURA::DREAMSTATE, |a| aura_dreamstate(a, ¶ms.game_data))
1314 .aura("moonfire", AURA::MOONFIRE, |a| aura_moonfire(a, ¶ms.game_data))
1315 .aura("sunfire", AURA::SUNFIRE, |a| aura_sunfire(a, ¶ms.game_data))
1316 .aura("starfall", AURA::STARFALL, |a| aura_starfall(a, ¶ms.game_data))
1317 .aura("starlord", AURA::STARLORD, |a| aura_starlord(a, ¶ms.game_data))
1318 .aura(
1319 "starweavers_warp",
1320 AURA::STARWEAVER_S_WARP,
1321 |a| aura_starweaver_s_warp(a, ¶ms.game_data),
1322 )
1323 .aura(
1324 "starweavers_weft",
1325 AURA::STARWEAVER_S_WEFT,
1326 |a| aura_starweaver_s_weft(a, ¶ms.game_data),
1327 )
1328 .aura(
1329 "touch_the_cosmos",
1330 AURA::TOUCH_THE_COSMOS,
1331 |a| aura_touch_the_cosmos(a, ¶ms.game_data),
1332 )
1333 .aura("solstice", AURA::SOLSTICE, |a| aura_solstice(a, ¶ms.game_data))
1334 .aura(
1335 "stellar_amplification",
1336 AURA::STELLAR_AMPLIFICATION,
1337 |a| aura_stellar_amplification(a, ¶ms.game_data),
1338 )
1339 .aura(
1340 "boat_arcane",
1341 AURA::BOAT_ARCANE,
1342 |a| aura_boat_arcane(a, ¶ms.game_data),
1343 )
1344 .aura(
1345 "boat_nature",
1346 AURA::BOAT_NATURE,
1347 |a| aura_boat_nature(a, ¶ms.game_data),
1348 )
1349 .aura(
1350 "fungal_growth",
1351 AURA::FUNGAL_GROWTH,
1352 |a| aura_fungal_growth(a, ¶ms.game_data),
1353 )
1354 .aura(
1355 "natures_balance",
1356 AURA::NATURES_BALANCE,
1357 |a| aura_natures_balance(a, ¶ms.game_data),
1358 )
1359 .aura(
1360 "fury_of_elune_energize",
1361 AURA::FURY_OF_ELUNE_ENERGIZE,
1362 |a| aura_fury_of_elune_energize(a, ¶ms.game_data),
1363 )
1364 .aura(
1365 "fury_of_elune_beam",
1366 AURA::FURY_OF_ELUNE_BEAM,
1367 |a| aura_fury_of_elune_beam(a, ¶ms.game_data),
1368 )
1369 .aura(
1370 "sundered_firmament_energize",
1371 AURA::SUNDERED_FIRMAMENT_ENERGIZE,
1372 |a| aura_sundered_firmament_energize(a, ¶ms.game_data),
1373 )
1374 .aura(
1375 "sundered_firmament_beam",
1376 AURA::SUNDERED_FIRMAMENT_BEAM,
1377 |a| aura_sundered_firmament_beam(a, ¶ms.game_data),
1378 )
1379 .aura(
1380 "sunseeker_mushroom_driver",
1381 AURA::SUNSEEKER_MUSHROOM_DRIVER,
1382 |a| aura_sunseeker_mushroom_driver(a, ¶ms.game_data),
1383 )
1384 .spell(
1385 "moonkin_form",
1386 SPELL::MOONKIN_FORM,
1387 |s| spell_moonkin_form(s, ¶ms.game_data),
1388 )
1389 .spell(
1390 "mark_of_the_wild",
1391 SPELL::MARK_OF_THE_WILD,
1392 |s| spell_mark_of_the_wild(s, ¶ms.game_data),
1393 )
1394 .spell("wrath", SPELL::WRATH, |s| spell_wrath(s, ¶ms.game_data))
1395 .spell("starfire", SPELL::STARFIRE, |s| spell_starfire(s, ¶ms.game_data))
1396 .spell(
1397 "solar_eclipse",
1398 SPELL::SOLAR_ECLIPSE,
1399 |s| spell_solar_eclipse(s, ¶ms.game_data),
1400 )
1401 .spell(
1402 "celestial_alignment",
1403 SPELL::CELESTIAL_ALIGNMENT,
1404 |s| spell_celestial_alignment(s, ¶ms.game_data),
1405 )
1406 .spell(
1407 "incarnation_chosen_of_elune",
1408 SPELL::INCARNATION_CHOSEN_OF_ELUNE,
1409 |s| spell_incarnation_chosen_of_elune(s, ¶ms.game_data),
1410 )
1411 .spell("moonfire", SPELL::MOONFIRE, |s| spell_moonfire(s, ¶ms.game_data))
1412 .spell("sunfire", SPELL::SUNFIRE, |s| spell_sunfire(s, ¶ms.game_data))
1413 .spell("starsurge", SPELL::STARSURGE, |s| spell_starsurge(s, ¶ms.game_data))
1414 .spell("starfall", SPELL::STARFALL, |s| spell_starfall(s, ¶ms.game_data))
1415 .spell("new_moon", SPELL::NEW_MOON, |s| spell_new_moon(s, ¶ms.game_data))
1416 .spell(
1417 "fury_of_elune",
1418 SPELL::FURY_OF_ELUNE,
1419 |s| spell_fury_of_elune(s, ¶ms.game_data),
1420 )
1421 .spell(
1422 "force_of_nature",
1423 SPELL::FORCE_OF_NATURE,
1424 |s| spell_force_of_nature(s, ¶ms.game_data),
1425 )
1426 .spell(
1427 "convoke_the_spirits",
1428 SPELL::CONVOKE_THE_SPIRITS,
1429 |s| spell_convoke_the_spirits(s, ¶ms.game_data),
1430 )
1431 .spell(
1432 "wild_mushroom",
1433 SPELL::WILD_MUSHROOM,
1434 |s| spell_wild_mushroom(s, ¶ms.game_data),
1435 )
1436 .game_data(params.game_data.clone())
1437 .talent_spell_ids(TALENTS)
1438 .talent_selections(params.talent_selections)
1439 .talent_companion_aura(TALENT::LUNAR_CALLING, AURA_LUNAR_ECLIPSE_OVERRIDE)
1440 .talent_companion_aura(TALENT::NATURE_S_BALANCE, AURA_NATURES_BALANCE)
1441 .set_bonus_auras(params.set_bonus_auras)
1442 .encounter(params.encounter.clone());
1443 let builder = crate::generated::items::register_equipped(
1444 builder,
1445 ¶ms.game_data,
1446 params.equipped_items,
1447 )?;
1448
1449 builder
1450 .build(params.rotation)
1451 .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1452}
1453fn new_handler(
1454 params: wowlab_engine_ports::HandlerParams<'_>,
1455) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1456 let handler = crate::composition::compose_handler(
1457 build_combat_system,
1458 ¶ms,
1459 |parts, params| Ok(
1460 crate::hooks::balance_druid::BalanceHandler::new(parts, params),
1461 ),
1462 )?;
1463
1464 Ok(Box::new(handler))
1465}
1466static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1467 primary_resource: ResourceType::LunarPower,
1468 secondary_resource: None,
1469 spell_ids: DECLARED_SPELL_IDS,
1470 aura_ids: DECLARED_AURA_IDS,
1471 server_proc_entries: &[
1472 DeclaredServerProcEntry {
1473 spell_id: 450_346,
1474 attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
1475 | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
1476 },
1477 ],
1478 talents: TALENTS,
1479 rotation_field_schema: &[],
1480 metrics_plugin_id: None,
1481 hero_talent_trees: &[
1482 HeroTalentTreeDesc {
1483 name: "Keeper Of The Grove",
1484 spells: HERO_TREE_KEEPER_OF_THE_GROVE_SPELLS,
1485 auras: HERO_TREE_KEEPER_OF_THE_GROVE_AURAS,
1486 },
1487 HeroTalentTreeDesc {
1488 name: "Elunes Chosen",
1489 spells: HERO_TREE_ELUNES_CHOSEN_SPELLS,
1490 auras: HERO_TREE_ELUNES_CHOSEN_AURAS,
1491 },
1492 ],
1493 reported_spells: REPORTED_SPELLS,
1494 masked_passive_effects: &[],
1495 passive_effect_overrides: &[],
1496};
1497pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1498 spec_id: SpecId::Balance,
1499 display_name: "Balance Druid",
1500 metadata: DECLARED_METADATA,
1501 handler_factory: new_handler,
1502};
1503wowlab_engine_combat::smoke_test!(build_combat_system);