Skip to main content

wowlab_engine_content/generated/specs/
feral_druid.rs

1//! @generated by codegen-cli from manifests/specs/druid/feral/manifest.toml -- do not edit by hand.
2// Generated code: naming follows game data conventions
3#![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    ///<https://wowlab.gg/inspect/spell/5221>
15    pub(crate) const SHRED: u32 = 5221;
16    ///<https://wowlab.gg/inspect/spell/106785>
17    pub(crate) const SWIPE: u32 = 106_785;
18    ///<https://wowlab.gg/inspect/spell/155625>
19    pub(crate) const MOONFIRE: u32 = 155_625;
20    ///<https://wowlab.gg/inspect/spell/768>
21    pub(crate) const CAT_FORM: u32 = 768;
22    ///<https://wowlab.gg/inspect/spell/1126>
23    pub(crate) const MARK_OF_THE_WILD: u32 = 1126;
24    ///<https://wowlab.gg/inspect/spell/1249752>
25    pub(crate) const WAITING_FOR_ENERGY: u32 = 1_249_752;
26    ///<https://wowlab.gg/inspect/spell/1822>
27    pub(crate) const RAKE: u32 = 1822;
28    ///<https://wowlab.gg/inspect/spell/1079>
29    pub(crate) const RIP: u32 = 1079;
30    ///<https://wowlab.gg/inspect/spell/22568>
31    pub(crate) const FEROCIOUS_BITE: u32 = 22568;
32    ///<https://wowlab.gg/inspect/spell/285381>
33    pub(crate) const PRIMAL_WRATH: u32 = 285_381;
34    ///<https://wowlab.gg/inspect/spell/274837>
35    pub(crate) const FERAL_FRENZY: u32 = 274_837;
36    ///<https://wowlab.gg/inspect/spell/1243807>
37    pub(crate) const FRANTIC_FRENZY: u32 = 1_243_807;
38    ///<https://wowlab.gg/inspect/spell/5217>
39    pub(crate) const TIGERS_FURY: u32 = 5217;
40    ///<https://wowlab.gg/inspect/spell/106951>
41    pub(crate) const BERSERK: u32 = 106_951;
42    ///<https://wowlab.gg/inspect/spell/102543>
43    pub(crate) const INCARNATION_AVATAR_OF_ASHAMANE: u32 = 102_543;
44    ///<https://wowlab.gg/inspect/spell/391528>
45    pub(crate) const CONVOKE_THE_SPIRITS: u32 = 391_528;
46    ///<https://wowlab.gg/inspect/spell/5176>
47    pub(crate) const WRATH: u32 = 5176;
48    ///<https://wowlab.gg/inspect/spell/1244292>
49    pub(crate) const CHOMP: u32 = 1_244_292;
50}
51pub(crate) mod AURA {
52    ///<https://wowlab.gg/inspect/spell/155625>
53    pub(crate) const MOONFIRE: u32 = 155_625;
54    ///<https://wowlab.gg/inspect/spell/135700>
55    pub(crate) const CLEARCASTING: u32 = 135_700;
56    ///<https://wowlab.gg/inspect/spell/5215>
57    pub(crate) const PROWL: u32 = 5215;
58    ///<https://wowlab.gg/inspect/spell/768>
59    pub(crate) const CAT_FORM: u32 = 768;
60    ///<https://wowlab.gg/inspect/spell/1126>
61    pub(crate) const MARK_OF_THE_WILD_HIGHLIGHT: u32 = 1126;
62    ///<https://wowlab.gg/inspect/spell/155580>
63    pub(crate) const LUNAR_INSPIRATION: u32 = 155_580;
64    ///<https://wowlab.gg/inspect/spell/1079>
65    pub(crate) const RIP: u32 = 1079;
66    ///<https://wowlab.gg/inspect/spell/155722>
67    pub(crate) const RAKE: u32 = 155_722;
68    ///<https://wowlab.gg/inspect/spell/391722>
69    pub(crate) const SABERTOOTH: u32 = 391_722;
70    ///<https://wowlab.gg/inspect/spell/1271863>
71    pub(crate) const UNSEEN_SLASH: u32 = 1_271_863;
72    ///<https://wowlab.gg/inspect/spell/274838>
73    pub(crate) const FERAL_FRENZY: u32 = 274_838;
74    ///<https://wowlab.gg/inspect/spell/5217>
75    pub(crate) const TIGERS_FURY: u32 = 5217;
76    ///<https://wowlab.gg/inspect/spell/106951>
77    pub(crate) const BERSERK: u32 = 106_951;
78    ///<https://wowlab.gg/inspect/spell/102543>
79    pub(crate) const INCARNATION_AVATAR_OF_ASHAMANE: u32 = 102_543;
80    ///<https://wowlab.gg/inspect/spell/391882>
81    pub(crate) const APEX_PREDATORS_CRAVING: u32 = 391_882;
82    ///<https://wowlab.gg/inspect/spell/449646>
83    pub(crate) const SAVAGE_FURY: u32 = 449_646;
84    ///<https://wowlab.gg/inspect/spell/1244292>
85    pub(crate) const CHOMP_ENABLER: u32 = 1_244_292;
86    ///<https://wowlab.gg/inspect/spell/405189>
87    pub(crate) const OVERFLOWING_POWER: u32 = 405_189;
88    ///<https://wowlab.gg/inspect/spell/391873>
89    pub(crate) const TIGERS_TENACITY: u32 = 391_873;
90    ///<https://wowlab.gg/inspect/spell/1244483>
91    pub(crate) const SUDDEN_AMBUSH: u32 = 1_244_483;
92    ///<https://wowlab.gg/inspect/spell/439891>
93    pub(crate) const STRATEGIC_INFUSION: u32 = 439_891;
94    ///<https://wowlab.gg/inspect/spell/378990>
95    pub(crate) const LYCARAS_TEACHINGS_CRIT: u32 = 378_990;
96    ///<https://wowlab.gg/inspect/spell/1272262>
97    pub(crate) const FLASH_OF_CLARITY: u32 = 1_272_262;
98    ///<https://wowlab.gg/inspect/spell/1263939>
99    pub(crate) const UNSEEN_PREDATORS_CRAVING: u32 = 1_263_939;
100    ///<https://wowlab.gg/inspect/spell/1263962>
101    pub(crate) const STALKING_PREDATOR: u32 = 1_263_962;
102    ///<https://wowlab.gg/inspect/spell/439531>
103    pub(crate) const BLOODSEEKER_VINES: u32 = 439_531;
104}
105pub(crate) mod TALENT {
106    ///<https://wowlab.gg/inspect/spell/391881>
107    pub(crate) const APEX_PREDATORS_CRAVING: u32 = 391_881;
108    ///<https://wowlab.gg/inspect/spell/391548>
109    pub(crate) const ASHAMANES_GUIDANCE: u32 = 391_548;
110    ///<https://wowlab.gg/inspect/spell/343223>
111    pub(crate) const BERSERK: u32 = 343_223;
112    ///<https://wowlab.gg/inspect/spell/390902>
113    pub(crate) const CARNIVOROUS_INSTINCT: u32 = 390_902;
114    ///<https://wowlab.gg/inspect/spell/1244292>
115    pub(crate) const CHOMP: u32 = 1_244_292;
116    ///<https://wowlab.gg/inspect/spell/391528>
117    pub(crate) const CONVOKE_THE_SPIRITS: u32 = 391_528;
118    ///<https://wowlab.gg/inspect/spell/274837>
119    pub(crate) const FERAL_FRENZY: u32 = 274_837;
120    ///<https://wowlab.gg/inspect/spell/1243807>
121    pub(crate) const FRANTIC_FRENZY: u32 = 1_243_807;
122    ///<https://wowlab.gg/inspect/spell/102543>
123    pub(crate) const INCARNATION_AVATAR_OF_ASHAMANE: u32 = 102_543;
124    ///<https://wowlab.gg/inspect/spell/155580>
125    pub(crate) const LUNAR_INSPIRATION: u32 = 155_580;
126    ///<https://wowlab.gg/inspect/spell/378988>
127    pub(crate) const LYCARAS_TEACHINGS: u32 = 378_988;
128    ///<https://wowlab.gg/inspect/spell/236068>
129    pub(crate) const MOMENT_OF_CLARITY: u32 = 236_068;
130    ///<https://wowlab.gg/inspect/spell/16864>
131    pub(crate) const OMEN_OF_CLARITY: u32 = 16864;
132    ///<https://wowlab.gg/inspect/spell/1280316>
133    pub(crate) const PANTHERS_GUILE: u32 = 1_280_316;
134    ///<https://wowlab.gg/inspect/spell/159286>
135    pub(crate) const PRIMAL_FURY: u32 = 159_286;
136    ///<https://wowlab.gg/inspect/spell/285381>
137    pub(crate) const PRIMAL_WRATH: u32 = 285_381;
138    ///<https://wowlab.gg/inspect/spell/391709>
139    pub(crate) const RAMPANT_FEROCITY: u32 = 391_709;
140    ///<https://wowlab.gg/inspect/spell/202031>
141    pub(crate) const SABERTOOTH: u32 = 202_031;
142    ///<https://wowlab.gg/inspect/spell/158476>
143    pub(crate) const SOUL_OF_THE_FOREST: u32 = 158_476;
144    ///<https://wowlab.gg/inspect/spell/439890>
145    pub(crate) const STRATEGIC_INFUSION: u32 = 439_890;
146    ///<https://wowlab.gg/inspect/spell/384667>
147    pub(crate) const SUDDEN_AMBUSH: u32 = 384_667;
148    ///<https://wowlab.gg/inspect/spell/384665>
149    pub(crate) const TASTE_FOR_BLOOD: u32 = 384_665;
150    ///<https://wowlab.gg/inspect/spell/439528>
151    pub(crate) const THRIVING_GROWTH: u32 = 439_528;
152    ///<https://wowlab.gg/inspect/spell/391872>
153    pub(crate) const TIGERS_TENACITY: u32 = 391_872;
154    ///<https://wowlab.gg/inspect/spell/1263658>
155    pub(crate) const UNSEEN_PREDATOR: u32 = 1_263_658;
156}
157pub(crate) mod SET_BONUS {
158    ///<https://wowlab.gg/inspect/spell/1264812>
159    pub(crate) const MID1_FERAL_2PC: u32 = 1_264_812;
160}
161pub(crate) mod REPORTED_SPELL {
162    ///<https://wowlab.gg/inspect/spell/1263890>
163    pub(crate) const UNSEEN_SLASH: u32 = 1_263_890;
164}
165pub(crate) mod HERO {
166    pub(crate) mod DRUID_OF_THE_CLAW {
167        pub(crate) mod SPELL {
168            ///<https://wowlab.gg/inspect/spell/441591>
169            pub(crate) const RAVAGE: u32 = 441_591;
170            ///<https://wowlab.gg/inspect/spell/1271635>
171            pub(crate) const TWIN_CLAW: u32 = 1_271_635;
172        }
173        pub(crate) mod AURA {
174            ///<https://wowlab.gg/inspect/spell/441812>
175            pub(crate) const DREADFUL_WOUND: u32 = 441_812;
176            ///<https://wowlab.gg/inspect/spell/441825>
177            pub(crate) const KILLING_STRIKES: u32 = 441_825;
178            ///<https://wowlab.gg/inspect/spell/441827>
179            pub(crate) const KILLING_STRIKES_COMBAT: u32 = 441_827;
180            ///<https://wowlab.gg/inspect/spell/441585>
181            pub(crate) const RAVAGE_FB: u32 = 441_585;
182            ///<https://wowlab.gg/inspect/spell/441814>
183            pub(crate) const RUTHLESS_AGGRESSION: u32 = 441_814;
184        }
185    }
186    pub(crate) mod WILDSTALKER {
187        pub(crate) mod SPELL {
188            ///<https://wowlab.gg/inspect/spell/440122>
189            pub(crate) const BURSTING_GROWTH: u32 = 440_122;
190        }
191        pub(crate) mod AURA {
192            ///<https://wowlab.gg/inspect/spell/439531>
193            pub(crate) const BLOODSEEKER_VINES: u32 = 439_531;
194            ///<https://wowlab.gg/inspect/spell/455496>
195            pub(crate) const IMPLANT: u32 = 455_496;
196            ///<https://wowlab.gg/inspect/spell/439887>
197            pub(crate) const ROOT_NETWORK: u32 = 439_887;
198            ///<https://wowlab.gg/inspect/spell/439891>
199            pub(crate) const STRATEGIC_INFUSION: u32 = 439_891;
200        }
201    }
202}
203static HERO_TREE_DRUID_OF_THE_CLAW_SPELLS: &[(&str, u32)] = &[
204    ("RAVAGE", 441_591),
205    ("TWIN_CLAW", 1_271_635),
206];
207static HERO_TREE_DRUID_OF_THE_CLAW_AURAS: &[(&str, u32)] = &[
208    ("DREADFUL_WOUND", 441_812),
209    ("KILLING_STRIKES", 441_825),
210    ("KILLING_STRIKES_COMBAT", 441_827),
211    ("RAVAGE_FB", 441_585),
212    ("RUTHLESS_AGGRESSION", 441_814),
213];
214static HERO_TREE_WILDSTALKER_SPELLS: &[(&str, u32)] = &[("BURSTING_GROWTH", 440_122)];
215static HERO_TREE_WILDSTALKER_AURAS: &[(&str, u32)] = &[
216    ("BLOODSEEKER_VINES", 439_531),
217    ("IMPLANT", 455_496),
218    ("ROOT_NETWORK", 439_887),
219    ("STRATEGIC_INFUSION", 439_891),
220];
221pub(crate) const AURA_MOONFIRE: LocalAuraIdx = LocalAuraIdx::new(0);
222pub(crate) const AURA_CLEARCASTING: LocalAuraIdx = LocalAuraIdx::new(1);
223pub(crate) const AURA_PROWL: LocalAuraIdx = LocalAuraIdx::new(2);
224pub(crate) const AURA_CAT_FORM: LocalAuraIdx = LocalAuraIdx::new(3);
225pub(crate) const AURA_MARK_OF_THE_WILD_HIGHLIGHT: LocalAuraIdx = LocalAuraIdx::new(4);
226pub(crate) const AURA_LUNAR_INSPIRATION: LocalAuraIdx = LocalAuraIdx::new(5);
227pub(crate) const AURA_RIP: LocalAuraIdx = LocalAuraIdx::new(6);
228pub(crate) const AURA_RAKE: LocalAuraIdx = LocalAuraIdx::new(7);
229pub(crate) const AURA_SABERTOOTH: LocalAuraIdx = LocalAuraIdx::new(8);
230pub(crate) const AURA_UNSEEN_SLASH: LocalAuraIdx = LocalAuraIdx::new(9);
231pub(crate) const AURA_FERAL_FRENZY: LocalAuraIdx = LocalAuraIdx::new(10);
232pub(crate) const AURA_TIGERS_FURY: LocalAuraIdx = LocalAuraIdx::new(11);
233pub(crate) const AURA_BERSERK: LocalAuraIdx = LocalAuraIdx::new(12);
234pub(crate) const AURA_INCARNATION_AVATAR_OF_ASHAMANE: LocalAuraIdx = LocalAuraIdx::new(
235    13,
236);
237pub(crate) const AURA_APEX_PREDATORS_CRAVING: LocalAuraIdx = LocalAuraIdx::new(14);
238pub(crate) const AURA_SAVAGE_FURY: LocalAuraIdx = LocalAuraIdx::new(15);
239pub(crate) const AURA_CHOMP_ENABLER: LocalAuraIdx = LocalAuraIdx::new(16);
240pub(crate) const AURA_OVERFLOWING_POWER: LocalAuraIdx = LocalAuraIdx::new(17);
241pub(crate) const AURA_TIGERS_TENACITY: LocalAuraIdx = LocalAuraIdx::new(18);
242pub(crate) const AURA_SUDDEN_AMBUSH: LocalAuraIdx = LocalAuraIdx::new(19);
243pub(crate) const AURA_STRATEGIC_INFUSION: LocalAuraIdx = LocalAuraIdx::new(20);
244pub(crate) const AURA_LYCARAS_TEACHINGS_CRIT: LocalAuraIdx = LocalAuraIdx::new(21);
245pub(crate) const AURA_FLASH_OF_CLARITY: LocalAuraIdx = LocalAuraIdx::new(22);
246pub(crate) const AURA_UNSEEN_PREDATORS_CRAVING: LocalAuraIdx = LocalAuraIdx::new(23);
247pub(crate) const AURA_STALKING_PREDATOR: LocalAuraIdx = LocalAuraIdx::new(24);
248pub(crate) const AURA_BLOODSEEKER_VINES: LocalAuraIdx = LocalAuraIdx::new(25);
249pub(crate) const AURA_COUNT: usize = 26;
250const _: () = assert!(
251    AURA_COUNT == 26, "AURA index ABI: count changed -- update positional hook consumers"
252);
253pub(crate) const SPELL_SHRED: LocalSpellIdx = LocalSpellIdx::new(0);
254pub(crate) const SPELL_SWIPE: LocalSpellIdx = LocalSpellIdx::new(1);
255pub(crate) const SPELL_MOONFIRE: LocalSpellIdx = LocalSpellIdx::new(2);
256pub(crate) const SPELL_CAT_FORM: LocalSpellIdx = LocalSpellIdx::new(3);
257pub(crate) const SPELL_MARK_OF_THE_WILD: LocalSpellIdx = LocalSpellIdx::new(4);
258pub(crate) const SPELL_WAITING_FOR_ENERGY: LocalSpellIdx = LocalSpellIdx::new(5);
259pub(crate) const SPELL_RAKE: LocalSpellIdx = LocalSpellIdx::new(6);
260pub(crate) const SPELL_RIP: LocalSpellIdx = LocalSpellIdx::new(7);
261pub(crate) const SPELL_FEROCIOUS_BITE: LocalSpellIdx = LocalSpellIdx::new(8);
262pub(crate) const SPELL_PRIMAL_WRATH: LocalSpellIdx = LocalSpellIdx::new(9);
263pub(crate) const SPELL_FERAL_FRENZY: LocalSpellIdx = LocalSpellIdx::new(10);
264pub(crate) const SPELL_FRANTIC_FRENZY: LocalSpellIdx = LocalSpellIdx::new(11);
265pub(crate) const SPELL_TIGERS_FURY: LocalSpellIdx = LocalSpellIdx::new(12);
266pub(crate) const SPELL_BERSERK: LocalSpellIdx = LocalSpellIdx::new(13);
267pub(crate) const SPELL_INCARNATION_AVATAR_OF_ASHAMANE: LocalSpellIdx = LocalSpellIdx::new(
268    14,
269);
270pub(crate) const SPELL_CONVOKE_THE_SPIRITS: LocalSpellIdx = LocalSpellIdx::new(15);
271pub(crate) const SPELL_WRATH: LocalSpellIdx = LocalSpellIdx::new(16);
272pub(crate) const SPELL_CHOMP: LocalSpellIdx = LocalSpellIdx::new(17);
273pub(crate) const SPELL_COUNT: usize = 18;
274const _: () = assert!(
275    SPELL_COUNT == 18,
276    "SPELL index ABI: count changed -- update positional hook consumers"
277);
278pub(crate) mod EFFECT {
279    ///<https://wowlab.gg/inspect/spell/391881>
280    pub(crate) const APEX_PREDATOR_CHANCE: (u32, u8) = (391_881, 1);
281    ///<https://wowlab.gg/inspect/spell/274838>
282    pub(crate) const FERAL_FRENZY_HIT: (u32, u8) = (274_838, 1);
283    ///<https://wowlab.gg/inspect/spell/22568>
284    pub(crate) const FEROCIOUS_BITE_DMG: (u32, u8) = (22568, 1);
285    ///<https://wowlab.gg/inspect/spell/236068>
286    pub(crate) const MOMENT_OF_CLARITY_PROC_BONUS: (u32, u8) = (236_068, 2);
287    ///<https://wowlab.gg/inspect/spell/77493>
288    pub(crate) const RAZOR_CLAWS_BLOODSEEKER_PERIODIC: (u32, u8) = (77493, 6);
289    ///<https://wowlab.gg/inspect/spell/77493>
290    pub(crate) const RAZOR_CLAWS_DAMAGE: (u32, u8) = (77493, 1);
291    ///<https://wowlab.gg/inspect/spell/77493>
292    pub(crate) const RAZOR_CLAWS_DREADFUL_WOUND_PERIODIC: (u32, u8) = (77493, 7);
293    ///<https://wowlab.gg/inspect/spell/77493>
294    pub(crate) const RAZOR_CLAWS_PERIODIC: (u32, u8) = (77493, 2);
295    ///<https://wowlab.gg/inspect/spell/77493>
296    pub(crate) const RAZOR_CLAWS_RAMPANT_DIRECT: (u32, u8) = (77493, 5);
297    ///<https://wowlab.gg/inspect/spell/77493>
298    pub(crate) const RAZOR_CLAWS_RAMPANT_PERIODIC: (u32, u8) = (77493, 4);
299    ///<https://wowlab.gg/inspect/spell/77493>
300    pub(crate) const RAZOR_CLAWS_UNSEEN_SLASH_PERIODIC: (u32, u8) = (77493, 8);
301    ///<https://wowlab.gg/inspect/spell/384667>
302    pub(crate) const SUDDEN_AMBUSH_CHANCE: (u32, u8) = (384_667, 1);
303    ///<https://wowlab.gg/inspect/spell/439528>
304    pub(crate) const THRIVING_GROWTH_RAKE: (u32, u8) = (439_528, 2);
305    ///<https://wowlab.gg/inspect/spell/439528>
306    pub(crate) const THRIVING_GROWTH_RIP: (u32, u8) = (439_528, 1);
307    ///<https://wowlab.gg/inspect/spell/1263890>
308    pub(crate) const UNSEEN_SLASH_DMG: (u32, u8) = (1_263_890, 1);
309}
310static REPORTED_SPELLS: &[(&str, u32)] = &[("unseen_slash", 1_263_890)];
311static DECLARED_SPELL_IDS: &[u32] = &[
312    5221, 106_785, 155_625, 768, 1126, 1_249_752, 1822, 1079, 22568, 285_381, 274_837,
313    1_243_807, 5217, 106_951, 102_543, 391_528, 5176, 1_244_292, 155_625, 135_700, 5215,
314    768, 1126, 155_580, 1079, 155_722, 391_722, 1_271_863, 274_838, 5217, 106_951,
315    102_543, 391_882, 449_646, 1_244_292, 405_189, 391_873, 1_244_483, 439_891, 378_990,
316    1_272_262, 1_263_939, 1_263_962, 439_531, 6603, 1079, 22568, 77493, 155_625, 155_722,
317    202_031, 236_068, 274_838, 378_988, 384_667, 391_881, 439_528, 1_263_658, 1_263_890,
318    1_271_863, 1_263_890, 441_591, 1_271_635, 441_812, 441_825, 441_827, 441_585,
319    441_814, 440_122, 439_531, 455_496, 439_887, 439_891,
320];
321static DECLARED_AURA_IDS: &[u32] = &[
322    155_625, 135_700, 5215, 768, 1126, 155_580, 1079, 155_722, 391_722, 1_271_863,
323    274_838, 5217, 106_951, 102_543, 391_882, 449_646, 1_244_292, 405_189, 391_873,
324    1_244_483, 439_891, 378_990, 1_272_262, 1_263_939, 1_263_962, 439_531, 441_812,
325    441_825, 441_827, 441_585, 441_814, 439_531, 455_496, 439_887, 439_891,
326];
327static TALENTS: &[(&str, u32)] = &[
328    ("APEX_PREDATORS_CRAVING", TALENT::APEX_PREDATORS_CRAVING),
329    ("ASHAMANES_GUIDANCE", TALENT::ASHAMANES_GUIDANCE),
330    ("BERSERK", TALENT::BERSERK),
331    ("CARNIVOROUS_INSTINCT", TALENT::CARNIVOROUS_INSTINCT),
332    ("CHOMP", TALENT::CHOMP),
333    ("CONVOKE_THE_SPIRITS", TALENT::CONVOKE_THE_SPIRITS),
334    ("FERAL_FRENZY", TALENT::FERAL_FRENZY),
335    ("FRANTIC_FRENZY", TALENT::FRANTIC_FRENZY),
336    ("INCARNATION_AVATAR_OF_ASHAMANE", TALENT::INCARNATION_AVATAR_OF_ASHAMANE),
337    ("LUNAR_INSPIRATION", TALENT::LUNAR_INSPIRATION),
338    ("LYCARAS_TEACHINGS", TALENT::LYCARAS_TEACHINGS),
339    ("MOMENT_OF_CLARITY", TALENT::MOMENT_OF_CLARITY),
340    ("OMEN_OF_CLARITY", TALENT::OMEN_OF_CLARITY),
341    ("PANTHERS_GUILE", TALENT::PANTHERS_GUILE),
342    ("PRIMAL_FURY", TALENT::PRIMAL_FURY),
343    ("PRIMAL_WRATH", TALENT::PRIMAL_WRATH),
344    ("RAMPANT_FEROCITY", TALENT::RAMPANT_FEROCITY),
345    ("SABERTOOTH", TALENT::SABERTOOTH),
346    ("SOUL_OF_THE_FOREST", TALENT::SOUL_OF_THE_FOREST),
347    ("STRATEGIC_INFUSION", TALENT::STRATEGIC_INFUSION),
348    ("SUDDEN_AMBUSH", TALENT::SUDDEN_AMBUSH),
349    ("TASTE_FOR_BLOOD", TALENT::TASTE_FOR_BLOOD),
350    ("THRIVING_GROWTH", TALENT::THRIVING_GROWTH),
351    ("TIGERS_TENACITY", TALENT::TIGERS_TENACITY),
352    ("UNSEEN_PREDATOR", TALENT::UNSEEN_PREDATOR),
353];
354pub(crate) mod FERAL_DRUID {
355    pub(crate) const SHRED_CASTS: u32 = 0;
356    pub(crate) const RAKE_CASTS: u32 = 1;
357    pub(crate) const RIP_CASTS: u32 = 2;
358    pub(crate) const FEROCIOUS_BITE_CASTS: u32 = 3;
359    pub(crate) const TIGERS_FURY_CASTS: u32 = 4;
360    pub(crate) const BERSERK_CASTS: u32 = 5;
361    pub(crate) const FERAL_FRENZY_CASTS: u32 = 6;
362    pub(crate) const TIGERS_FURY_UPTIME_MS: u32 = 7;
363    pub(crate) const BERSERK_UPTIME_MS: u32 = 8;
364    pub(crate) const RIP_UPTIME_MS: u32 = 9;
365    pub(crate) const RAKE_UPTIME_MS: u32 = 10;
366}
367fn aura_moonfire(
368    a: AuraDefinitionDraft,
369    data: &ResolvedGameData,
370) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
371    a.on_target()
372        .apply_base_from_data(data, 155_625)?
373        .max_stacks(
374            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(155_625))?,
375        )
376        .periodic_damage(
377            wowlab_engine_combat::validated_milliseconds(
378                (data.period(wowlab_types::sim::SpellIdx::from_raw(155_625), 1)) * 0.8,
379                155_625,
380                "periodic_damage.tick_ms",
381            )?,
382            ((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(155_625), 1)) * 100.0)
383                .round() / 100.0,
384            wowlab_engine_combat::DamageFlags::empty(),
385        )
386        .apply_periodic_behavior_from_data(data, 155_625)
387}
388fn aura_clearcasting(
389    a: AuraDefinitionDraft,
390    data: &ResolvedGameData,
391) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
392    Ok(
393        a
394            .on_player()
395            .apply_base_from_data(data, 135_700)?
396            .max_stacks(
397                data
398                    .require_aura_max_stacks(
399                        wowlab_types::sim::SpellIdx::from_raw(135_700),
400                    )?,
401            ),
402    )
403}
404fn aura_prowl(
405    a: AuraDefinitionDraft,
406    data: &ResolvedGameData,
407) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
408    Ok(
409        a
410            .on_player()
411            .apply_base_from_data(data, 5215)?
412            .max_stacks(
413                data
414                    .require_aura_max_stacks(
415                        wowlab_types::sim::SpellIdx::from_raw(5215),
416                    )?,
417            ),
418    )
419}
420fn aura_cat_form(
421    a: AuraDefinitionDraft,
422    data: &ResolvedGameData,
423) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
424    Ok(
425        a
426            .on_player()
427            .apply_base_from_data(data, 768)?
428            .max_stacks(
429                data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(768))?,
430            ),
431    )
432}
433fn aura_mark_of_the_wild_highlight(
434    a: AuraDefinitionDraft,
435    data: &ResolvedGameData,
436) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
437    Ok(
438        a
439            .on_player()
440            .apply_base_from_data(data, 1126)?
441            .max_stacks(
442                data
443                    .require_aura_max_stacks(
444                        wowlab_types::sim::SpellIdx::from_raw(1126),
445                    )?,
446            ),
447    )
448}
449fn aura_lunar_inspiration(
450    a: AuraDefinitionDraft,
451    data: &ResolvedGameData,
452) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
453    Ok(
454        a
455            .on_player()
456            .apply_base_from_data(data, 155_580)?
457            .max_stacks(
458                data
459                    .require_aura_max_stacks(
460                        wowlab_types::sim::SpellIdx::from_raw(155_580),
461                    )?,
462            ),
463    )
464}
465fn aura_rip(
466    a: AuraDefinitionDraft,
467    data: &ResolvedGameData,
468) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
469    a.on_target()
470        .apply_base_from_data(data, 1079)?
471        .max_stacks(
472            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(1079))?,
473        )
474        .snapshot()
475        .periodic_damage(
476            wowlab_engine_combat::validated_milliseconds(
477                (data.period(wowlab_types::sim::SpellIdx::from_raw(1079), 1)) * 0.8,
478                1079,
479                "periodic_damage.tick_ms",
480            )?,
481            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(1079), 1)) * 1.3)
482                * 100_000.0)
483                .round() / 100_000.0,
484            wowlab_engine_combat::DamageFlags::PHYSICAL,
485        )
486        .apply_periodic_behavior_from_data(data, 1079)
487}
488fn aura_rake(
489    a: AuraDefinitionDraft,
490    data: &ResolvedGameData,
491) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
492    a.on_target()
493        .apply_base_from_data(data, 155_722)?
494        .max_stacks(
495            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(155_722))?,
496        )
497        .snapshot()
498        .periodic_damage(
499            wowlab_engine_combat::validated_milliseconds(
500                (data.period(wowlab_types::sim::SpellIdx::from_raw(155_722), 1)) * 0.8,
501                155_722,
502                "periodic_damage.tick_ms",
503            )?,
504            0.18,
505            wowlab_engine_combat::DamageFlags::PHYSICAL,
506        )
507        .apply_periodic_behavior_from_data(data, 155_722)
508}
509fn aura_sabertooth(
510    a: AuraDefinitionDraft,
511    data: &ResolvedGameData,
512) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
513    a.on_target()
514        .apply_base_from_data(data, 391_722)?
515        .no_pandemic()
516        .max_stacks(
517            wowlab_engine_combat::validated_max_stacks(5.0, 391_722, "aura.max_stacks")?,
518        )
519        .damage_taken_from_caster_spells(
520            data,
521            data.base_points(wowlab_types::sim::SpellIdx::from_raw(202_031), 2),
522        )
523}
524fn aura_unseen_slash(
525    a: AuraDefinitionDraft,
526    data: &ResolvedGameData,
527) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
528    a.on_target()
529        .apply_base_from_data(data, 1_271_863)?
530        .max_stacks(
531            data
532                .require_aura_max_stacks(
533                    wowlab_types::sim::SpellIdx::from_raw(1_271_863),
534                )?,
535        )
536        .snapshot()
537        .periodic_damage(
538            wowlab_engine_combat::validated_milliseconds(
539                (data.period(wowlab_types::sim::SpellIdx::from_raw(1_271_863), 1)) * 0.8,
540                1_271_863,
541                "periodic_damage.tick_ms",
542            )?,
543            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(1_271_863), 1)) * 1.3)
544                * 1000.0)
545                .round() / 1000.0,
546            wowlab_engine_combat::DamageFlags::PHYSICAL,
547        )
548        .apply_periodic_behavior_from_data(data, 1_271_863)
549}
550fn aura_feral_frenzy(
551    a: AuraDefinitionDraft,
552    data: &ResolvedGameData,
553) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
554    a.on_target()
555        .apply_base_from_data(data, 274_838)?
556        .max_stacks(
557            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(274_838))?,
558        )
559        .snapshot()
560        .periodic_damage(
561            wowlab_engine_combat::validated_milliseconds(
562                (data.period(wowlab_types::sim::SpellIdx::from_raw(274_838), 2)) * 0.8,
563                274_838,
564                "periodic_damage.tick_ms",
565            )?,
566            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(274_838), 2)) * 5.0)
567                * 10000.0)
568                .round() / 10000.0,
569            wowlab_engine_combat::DamageFlags::PHYSICAL,
570        )
571        .apply_periodic_behavior_from_data(data, 274_838)
572}
573fn aura_tigers_fury(
574    a: AuraDefinitionDraft,
575    data: &ResolvedGameData,
576) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
577    Ok(
578        a
579            .on_player()
580            .apply_base_from_data(data, 5217)?
581            .max_stacks(
582                data
583                    .require_aura_max_stacks(
584                        wowlab_types::sim::SpellIdx::from_raw(5217),
585                    )?,
586            ),
587    )
588}
589fn aura_berserk(
590    a: AuraDefinitionDraft,
591    data: &ResolvedGameData,
592) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
593    Ok(
594        a
595            .on_player()
596            .apply_base_from_data(data, 106_951)?
597            .max_stacks(
598                data
599                    .require_aura_max_stacks(
600                        wowlab_types::sim::SpellIdx::from_raw(106_951),
601                    )?,
602            ),
603    )
604}
605fn aura_incarnation_avatar_of_ashamane(
606    a: AuraDefinitionDraft,
607    data: &ResolvedGameData,
608) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
609    Ok(
610        a
611            .on_player()
612            .apply_base_from_data(data, 102_543)?
613            .max_stacks(
614                data
615                    .require_aura_max_stacks(
616                        wowlab_types::sim::SpellIdx::from_raw(102_543),
617                    )?,
618            ),
619    )
620}
621fn aura_apex_predators_craving(
622    a: AuraDefinitionDraft,
623    data: &ResolvedGameData,
624) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
625    Ok(
626        a
627            .on_player()
628            .apply_base_from_data(data, 391_882)?
629            .max_stacks(
630                data
631                    .require_aura_max_stacks(
632                        wowlab_types::sim::SpellIdx::from_raw(391_882),
633                    )?,
634            ),
635    )
636}
637fn aura_savage_fury(
638    a: AuraDefinitionDraft,
639    data: &ResolvedGameData,
640) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
641    Ok(
642        a
643            .on_player()
644            .apply_base_from_data(data, 449_646)?
645            .max_stacks(
646                data
647                    .require_aura_max_stacks(
648                        wowlab_types::sim::SpellIdx::from_raw(449_646),
649                    )?,
650            ),
651    )
652}
653fn aura_chomp_enabler(
654    a: AuraDefinitionDraft,
655    data: &ResolvedGameData,
656) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
657    Ok(
658        a
659            .on_player()
660            .apply_base_from_data(data, 1_244_292)?
661            .max_stacks(
662                data
663                    .require_aura_max_stacks(
664                        wowlab_types::sim::SpellIdx::from_raw(1_244_292),
665                    )?,
666            ),
667    )
668}
669fn aura_overflowing_power(
670    a: AuraDefinitionDraft,
671    data: &ResolvedGameData,
672) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
673    Ok(
674        a
675            .on_player()
676            .apply_base_from_data(data, 405_189)?
677            .max_stacks(
678                data
679                    .require_aura_max_stacks(
680                        wowlab_types::sim::SpellIdx::from_raw(405_189),
681                    )?,
682            ),
683    )
684}
685fn aura_tigers_tenacity(
686    a: AuraDefinitionDraft,
687    data: &ResolvedGameData,
688) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
689    Ok(
690        a
691            .on_player()
692            .apply_base_from_data(data, 391_873)?
693            .max_stacks(
694                wowlab_engine_combat::validated_max_stacks(
695                    3.0,
696                    391_873,
697                    "aura.max_stacks",
698                )?,
699            ),
700    )
701}
702fn aura_sudden_ambush(
703    a: AuraDefinitionDraft,
704    data: &ResolvedGameData,
705) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
706    Ok(
707        a
708            .on_player()
709            .apply_base_from_data(data, 1_244_483)?
710            .max_stacks(
711                data
712                    .require_aura_max_stacks(
713                        wowlab_types::sim::SpellIdx::from_raw(1_244_483),
714                    )?,
715            ),
716    )
717}
718fn aura_strategic_infusion(
719    a: AuraDefinitionDraft,
720    data: &ResolvedGameData,
721) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
722    Ok(
723        a
724            .on_player()
725            .apply_base_from_data(data, 439_891)?
726            .max_stacks(
727                data
728                    .require_aura_max_stacks(
729                        wowlab_types::sim::SpellIdx::from_raw(439_891),
730                    )?,
731            ),
732    )
733}
734fn aura_lycaras_teachings_crit(
735    a: AuraDefinitionDraft,
736    data: &ResolvedGameData,
737) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
738    a.on_player()
739        .apply_base_from_data(data, 378_990)?
740        .max_stacks(
741            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(378_990))?,
742        )
743        .crit_per_stack(
744            data.base_points(wowlab_types::sim::SpellIdx::from_raw(378_988), 1),
745        )
746}
747fn aura_flash_of_clarity(
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, 1_272_262)?
755            .max_stacks(
756                data
757                    .require_aura_max_stacks(
758                        wowlab_types::sim::SpellIdx::from_raw(1_272_262),
759                    )?,
760            ),
761    )
762}
763fn aura_unseen_predators_craving(
764    a: AuraDefinitionDraft,
765    data: &ResolvedGameData,
766) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
767    a.on_player()
768        .apply_base_from_data(data, 1_263_939)?
769        .max_stacks(
770            data
771                .require_aura_max_stacks(
772                    wowlab_types::sim::SpellIdx::from_raw(1_263_939),
773                )?,
774        )
775        .no_pandemic()
776        .forwarded_effect_value(
777            data,
778            data.base_points(wowlab_types::sim::SpellIdx::from_raw(1_263_658), 1),
779        )
780}
781fn aura_stalking_predator(
782    a: AuraDefinitionDraft,
783    data: &ResolvedGameData,
784) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
785    Ok(
786        a
787            .on_player()
788            .apply_base_from_data(data, 1_263_962)?
789            .max_stacks(
790                data
791                    .require_aura_max_stacks(
792                        wowlab_types::sim::SpellIdx::from_raw(1_263_962),
793                    )?,
794            ),
795    )
796}
797fn aura_bloodseeker_vines(
798    a: AuraDefinitionDraft,
799    data: &ResolvedGameData,
800) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
801    Ok(
802        a
803            .on_target()
804            .apply_base_from_data(data, 439_531)?
805            .max_stacks(
806                data
807                    .require_aura_max_stacks(
808                        wowlab_types::sim::SpellIdx::from_raw(439_531),
809                    )?,
810            )
811            .snapshot()
812            .async_stacks()
813            .periodic_damage_scales_with_stacks(),
814    )
815}
816fn spell_shred(
817    s: SpellDefinitionDraft,
818    data: &ResolvedGameData,
819) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
820    Ok(
821        s
822            .apply_base_from_data(data, 5221)?
823            .apply_aoe_from_data(data)
824            .on_cast(crate::hooks::feral_druid::shred_hook)
825            .cost_free_when_aura(135_700)
826            .consume_aura_on_cast(1_244_483),
827    )
828}
829fn spell_swipe(
830    s: SpellDefinitionDraft,
831    data: &ResolvedGameData,
832) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
833    Ok(
834        s
835            .apply_base_from_data(data, 106_785)?
836            .apply_aoe_from_data(data)
837            .on_cast(crate::hooks::feral_druid::builder_hook)
838            .consume_aura_on_cast(1_244_483),
839    )
840}
841fn spell_moonfire(
842    s: SpellDefinitionDraft,
843    data: &ResolvedGameData,
844) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
845    Ok(
846        s
847            .apply_base_from_data(data, 155_625)?
848            .applies_inferred_aura(AURA_MOONFIRE, 155_625)
849            .apply_aoe_from_data(data)
850            .on_cast(crate::hooks::feral_druid::moonfire_hook),
851    )
852}
853fn spell_cat_form(
854    s: SpellDefinitionDraft,
855    data: &ResolvedGameData,
856) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
857    Ok(
858        s
859            .apply_base_from_data(data, 768)?
860            .applies_inferred_aura(AURA_CAT_FORM, 768)
861            .apply_aoe_from_data(data)
862            .on_cast(crate::hooks::feral_druid::cat_form_hook),
863    )
864}
865fn spell_mark_of_the_wild(
866    s: SpellDefinitionDraft,
867    data: &ResolvedGameData,
868) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
869    Ok(
870        s
871            .apply_base_from_data(data, 1126)?
872            .applies_inferred_aura(AURA_MARK_OF_THE_WILD_HIGHLIGHT, 1126)
873            .apply_aoe_from_data(data),
874    )
875}
876fn spell_waiting_for_energy(
877    s: SpellDefinitionDraft,
878    data: &ResolvedGameData,
879) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
880    Ok(s.apply_base_from_data(data, 1_249_752)?.apply_aoe_from_data(data))
881}
882fn spell_rake(
883    s: SpellDefinitionDraft,
884    data: &ResolvedGameData,
885) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
886    Ok(
887        s
888            .apply_base_from_data(data, 1822)?
889            .applies_aura(AURA_RAKE)
890            .apply_aoe_from_data(data)
891            .on_cast(crate::hooks::feral_druid::rake_hook)
892            .consume_aura_on_cast(1_244_483),
893    )
894}
895fn spell_rip(
896    s: SpellDefinitionDraft,
897    data: &ResolvedGameData,
898) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
899    Ok(
900        s
901            .apply_base_from_data(data, 1079)?
902            .applies_inferred_aura(AURA_RIP, 1079)
903            .apply_aoe_from_data(data)
904            .on_cast(crate::hooks::feral_druid::rip_hook),
905    )
906}
907fn spell_ferocious_bite(
908    s: SpellDefinitionDraft,
909    data: &ResolvedGameData,
910) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
911    Ok(
912        s
913            .apply_base_from_data(data, 22568)?
914            .damage_flat(0.0)
915            .apply_aoe_from_data(data)
916            .on_cast(crate::hooks::feral_druid::ferocious_bite_hook),
917    )
918}
919fn spell_primal_wrath(
920    s: SpellDefinitionDraft,
921    data: &ResolvedGameData,
922) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
923    Ok(s.apply_base_from_data(data, 285_381)?.apply_aoe_from_data(data))
924}
925fn spell_feral_frenzy(
926    s: SpellDefinitionDraft,
927    data: &ResolvedGameData,
928) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
929    Ok(
930        s
931            .apply_base_from_data(data, 274_837)?
932            .applies_aura(AURA_FERAL_FRENZY)
933            .apply_aoe_from_data(data)
934            .on_cast(crate::hooks::feral_druid::feral_frenzy_hook),
935    )
936}
937fn spell_frantic_frenzy(
938    s: SpellDefinitionDraft,
939    data: &ResolvedGameData,
940) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
941    Ok(s.apply_base_from_data(data, 1_243_807)?.apply_aoe_from_data(data))
942}
943fn spell_tigers_fury(
944    s: SpellDefinitionDraft,
945    data: &ResolvedGameData,
946) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
947    Ok(
948        s
949            .apply_base_from_data(data, 5217)?
950            .applies_inferred_aura(AURA_TIGERS_FURY, 5217)
951            .apply_aoe_from_data(data)
952            .on_cast(crate::hooks::feral_druid::tigers_fury_hook),
953    )
954}
955fn spell_berserk(
956    s: SpellDefinitionDraft,
957    data: &ResolvedGameData,
958) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
959    Ok(
960        s
961            .apply_base_from_data(data, 106_951)?
962            .applies_inferred_aura(AURA_BERSERK, 106_951)
963            .apply_aoe_from_data(data),
964    )
965}
966fn spell_incarnation_avatar_of_ashamane(
967    s: SpellDefinitionDraft,
968    data: &ResolvedGameData,
969) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
970    Ok(
971        s
972            .apply_base_from_data(data, 102_543)?
973            .applies_inferred_aura(AURA_INCARNATION_AVATAR_OF_ASHAMANE, 102_543)
974            .apply_aoe_from_data(data),
975    )
976}
977fn spell_convoke_the_spirits(
978    s: SpellDefinitionDraft,
979    data: &ResolvedGameData,
980) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
981    Ok(
982        s
983            .apply_base_from_data(data, 391_528)?
984            .apply_aoe_from_data(data)
985            .channel(
986                data
987                    .require_channel_tick_count(
988                        wowlab_types::sim::SpellIdx::from_raw(391_528),
989                    )?,
990            )
991            .on_channel_tick(crate::hooks::feral_druid::convoke_tick_hook)
992            .on_cast(crate::hooks::feral_druid::convoke_cast_hook),
993    )
994}
995fn spell_wrath(
996    s: SpellDefinitionDraft,
997    data: &ResolvedGameData,
998) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
999    Ok(s.apply_base_from_data(data, 5176)?.apply_aoe_from_data(data))
1000}
1001fn spell_chomp(
1002    s: SpellDefinitionDraft,
1003    data: &ResolvedGameData,
1004) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
1005    Ok(
1006        s
1007            .apply_base_from_data(data, 1_244_292)?
1008            .applies_inferred_aura(AURA_CHOMP_ENABLER, 1_244_292)
1009            .apply_aoe_from_data(data),
1010    )
1011}
1012pub(crate) fn build_combat_system(
1013    params: &wowlab_engine_ports::HandlerParams<'_>,
1014) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
1015    let builder = BuiltCombatSystem::builder(params.stats.clone())
1016        .spec_id(SpecId::Feral)
1017        .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
1018        .mastery_spell(77493)
1019        .mastery_hook(crate::hooks::feral_druid::mastery)
1020        .resource(
1021            "energy",
1022            params
1023                .game_data
1024                .power_max(3)
1025                .ok_or_else(|| {
1026                    wowlab_engine_ports::EngineError::spec_construction(
1027                        "missing power-type power_max for type_id 3",
1028                    )
1029                })?,
1030            12.65,
1031        )
1032        .resource_type_id(3)
1033        .resource_start(
1034            params
1035                .game_data
1036                .power_default(3)
1037                .ok_or_else(|| {
1038                    wowlab_engine_ports::EngineError::spec_construction(
1039                        "missing power-type power_default for type_id 3",
1040                    )
1041                })?,
1042        )
1043        .secondary_resource(
1044            "combo_points",
1045            params
1046                .game_data
1047                .power_max(4)
1048                .ok_or_else(|| {
1049                    wowlab_engine_ports::EngineError::spec_construction(
1050                        "missing power-type power_max for type_id 4",
1051                    )
1052                })?,
1053        )
1054        .secondary_resource_type_id(4)
1055        .aura("moonfire", AURA::MOONFIRE, |a| aura_moonfire(a, &params.game_data))
1056        .aura(
1057            "clearcasting",
1058            AURA::CLEARCASTING,
1059            |a| aura_clearcasting(a, &params.game_data),
1060        )
1061        .aura("prowl", AURA::PROWL, |a| aura_prowl(a, &params.game_data))
1062        .aura("cat_form", AURA::CAT_FORM, |a| aura_cat_form(a, &params.game_data))
1063        .aura(
1064            "mark_of_the_wild_highlight",
1065            AURA::MARK_OF_THE_WILD_HIGHLIGHT,
1066            |a| aura_mark_of_the_wild_highlight(a, &params.game_data),
1067        )
1068        .aura(
1069            "lunar_inspiration",
1070            AURA::LUNAR_INSPIRATION,
1071            |a| aura_lunar_inspiration(a, &params.game_data),
1072        )
1073        .aura("rip", AURA::RIP, |a| aura_rip(a, &params.game_data))
1074        .aura("rake", AURA::RAKE, |a| aura_rake(a, &params.game_data))
1075        .aura("sabertooth", AURA::SABERTOOTH, |a| aura_sabertooth(a, &params.game_data))
1076        .aura(
1077            "unseen_slash",
1078            AURA::UNSEEN_SLASH,
1079            |a| aura_unseen_slash(a, &params.game_data),
1080        )
1081        .aura(
1082            "feral_frenzy",
1083            AURA::FERAL_FRENZY,
1084            |a| aura_feral_frenzy(a, &params.game_data),
1085        )
1086        .aura(
1087            "tigers_fury",
1088            AURA::TIGERS_FURY,
1089            |a| aura_tigers_fury(a, &params.game_data),
1090        )
1091        .aura("berserk", AURA::BERSERK, |a| aura_berserk(a, &params.game_data))
1092        .aura(
1093            "incarnation_avatar_of_ashamane",
1094            AURA::INCARNATION_AVATAR_OF_ASHAMANE,
1095            |a| aura_incarnation_avatar_of_ashamane(a, &params.game_data),
1096        )
1097        .aura(
1098            "apex_predators_craving",
1099            AURA::APEX_PREDATORS_CRAVING,
1100            |a| aura_apex_predators_craving(a, &params.game_data),
1101        )
1102        .aura(
1103            "savage_fury",
1104            AURA::SAVAGE_FURY,
1105            |a| aura_savage_fury(a, &params.game_data),
1106        )
1107        .aura(
1108            "chomp_enabler",
1109            AURA::CHOMP_ENABLER,
1110            |a| aura_chomp_enabler(a, &params.game_data),
1111        )
1112        .aura(
1113            "overflowing_power",
1114            AURA::OVERFLOWING_POWER,
1115            |a| aura_overflowing_power(a, &params.game_data),
1116        )
1117        .aura(
1118            "tigers_tenacity",
1119            AURA::TIGERS_TENACITY,
1120            |a| aura_tigers_tenacity(a, &params.game_data),
1121        )
1122        .aura(
1123            "sudden_ambush",
1124            AURA::SUDDEN_AMBUSH,
1125            |a| aura_sudden_ambush(a, &params.game_data),
1126        )
1127        .aura(
1128            "strategic_infusion",
1129            AURA::STRATEGIC_INFUSION,
1130            |a| aura_strategic_infusion(a, &params.game_data),
1131        )
1132        .aura(
1133            "lycaras_teachings_crit",
1134            AURA::LYCARAS_TEACHINGS_CRIT,
1135            |a| aura_lycaras_teachings_crit(a, &params.game_data),
1136        )
1137        .aura(
1138            "flash_of_clarity",
1139            AURA::FLASH_OF_CLARITY,
1140            |a| aura_flash_of_clarity(a, &params.game_data),
1141        )
1142        .aura(
1143            "unseen_predators_craving",
1144            AURA::UNSEEN_PREDATORS_CRAVING,
1145            |a| aura_unseen_predators_craving(a, &params.game_data),
1146        )
1147        .aura(
1148            "stalking_predator",
1149            AURA::STALKING_PREDATOR,
1150            |a| aura_stalking_predator(a, &params.game_data),
1151        )
1152        .aura(
1153            "bloodseeker_vines",
1154            AURA::BLOODSEEKER_VINES,
1155            |a| aura_bloodseeker_vines(a, &params.game_data),
1156        )
1157        .spell("shred", SPELL::SHRED, |s| spell_shred(s, &params.game_data))
1158        .spell("swipe", SPELL::SWIPE, |s| spell_swipe(s, &params.game_data))
1159        .spell("moonfire", SPELL::MOONFIRE, |s| spell_moonfire(s, &params.game_data))
1160        .spell("cat_form", SPELL::CAT_FORM, |s| spell_cat_form(s, &params.game_data))
1161        .spell(
1162            "mark_of_the_wild",
1163            SPELL::MARK_OF_THE_WILD,
1164            |s| spell_mark_of_the_wild(s, &params.game_data),
1165        )
1166        .spell(
1167            "waiting_for_energy",
1168            SPELL::WAITING_FOR_ENERGY,
1169            |s| spell_waiting_for_energy(s, &params.game_data),
1170        )
1171        .spell("rake", SPELL::RAKE, |s| spell_rake(s, &params.game_data))
1172        .spell("rip", SPELL::RIP, |s| spell_rip(s, &params.game_data))
1173        .spell(
1174            "ferocious_bite",
1175            SPELL::FEROCIOUS_BITE,
1176            |s| spell_ferocious_bite(s, &params.game_data),
1177        )
1178        .spell(
1179            "primal_wrath",
1180            SPELL::PRIMAL_WRATH,
1181            |s| spell_primal_wrath(s, &params.game_data),
1182        )
1183        .spell(
1184            "feral_frenzy",
1185            SPELL::FERAL_FRENZY,
1186            |s| spell_feral_frenzy(s, &params.game_data),
1187        )
1188        .spell(
1189            "frantic_frenzy",
1190            SPELL::FRANTIC_FRENZY,
1191            |s| spell_frantic_frenzy(s, &params.game_data),
1192        )
1193        .spell(
1194            "tigers_fury",
1195            SPELL::TIGERS_FURY,
1196            |s| spell_tigers_fury(s, &params.game_data),
1197        )
1198        .spell("berserk", SPELL::BERSERK, |s| spell_berserk(s, &params.game_data))
1199        .spell(
1200            "incarnation_avatar_of_ashamane",
1201            SPELL::INCARNATION_AVATAR_OF_ASHAMANE,
1202            |s| spell_incarnation_avatar_of_ashamane(s, &params.game_data),
1203        )
1204        .spell(
1205            "convoke_the_spirits",
1206            SPELL::CONVOKE_THE_SPIRITS,
1207            |s| spell_convoke_the_spirits(s, &params.game_data),
1208        )
1209        .spell("wrath", SPELL::WRATH, |s| spell_wrath(s, &params.game_data))
1210        .spell("chomp", SPELL::CHOMP, |s| spell_chomp(s, &params.game_data))
1211        .auto_attack(|a| {
1212            a
1213                .spell_id(6603)
1214                .swing_ms(1000)
1215                .apply_base_from_data(&params.game_data)
1216                .on_swing(crate::hooks::feral_druid::swing_hook)
1217        })
1218        .game_data(params.game_data.clone())
1219        .talent_spell_ids(TALENTS)
1220        .talent_selections(params.talent_selections)
1221        .set_bonus_auras(params.set_bonus_auras)
1222        .encounter(params.encounter.clone());
1223    let builder = crate::generated::items::register_equipped(
1224        builder,
1225        &params.game_data,
1226        params.equipped_items,
1227    )?;
1228
1229    builder
1230        .build(params.rotation)
1231        .map_err(wowlab_engine_ports::EngineError::rotation_compile)
1232}
1233fn new_handler(
1234    params: wowlab_engine_ports::HandlerParams<'_>,
1235) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
1236    let handler = crate::composition::compose_handler(
1237        build_combat_system,
1238        &params,
1239        |parts, params| Ok(crate::hooks::feral_druid::FeralHandler::new(parts, params)),
1240    )?;
1241
1242    Ok(Box::new(handler))
1243}
1244static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
1245    primary_resource: ResourceType::Energy,
1246    secondary_resource: Some(ResourceType::ComboPoints),
1247    spell_ids: DECLARED_SPELL_IDS,
1248    aura_ids: DECLARED_AURA_IDS,
1249    server_proc_entries: &[],
1250    talents: TALENTS,
1251    rotation_field_schema: &[],
1252    metrics_plugin_id: None,
1253    hero_talent_trees: &[
1254        HeroTalentTreeDesc {
1255            name: "Druid Of The Claw",
1256            spells: HERO_TREE_DRUID_OF_THE_CLAW_SPELLS,
1257            auras: HERO_TREE_DRUID_OF_THE_CLAW_AURAS,
1258        },
1259        HeroTalentTreeDesc {
1260            name: "Wildstalker",
1261            spells: HERO_TREE_WILDSTALKER_SPELLS,
1262            auras: HERO_TREE_WILDSTALKER_AURAS,
1263        },
1264    ],
1265    reported_spells: REPORTED_SPELLS,
1266    masked_passive_effects: &[(474_530, 3), (474_530, 4)],
1267    passive_effect_overrides: &[],
1268};
1269pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
1270    spec_id: SpecId::Feral,
1271    display_name: "Feral Druid",
1272    metadata: DECLARED_METADATA,
1273    handler_factory: new_handler,
1274};
1275wowlab_engine_combat::smoke_test!(build_combat_system);