Skip to main content

wowlab_engine_content/generated/specs/
survival_hunter.rs

1//! @generated by codegen-cli from manifests/specs/hunter/survival/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_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    ///<https://wowlab.gg/inspect/spell/259489>
17    pub(crate) const KILL_COMMAND: u32 = 259_489;
18    ///<https://wowlab.gg/inspect/spell/259495>
19    pub(crate) const WILDFIRE_BOMB: u32 = 259_495;
20    ///<https://wowlab.gg/inspect/spell/259387>
21    pub(crate) const MONGOOSE_BITE: u32 = 259_387;
22    ///<https://wowlab.gg/inspect/spell/186270>
23    pub(crate) const RAPTOR_STRIKE: u32 = 186_270;
24    ///<https://wowlab.gg/inspect/spell/185358>
25    pub(crate) const ARCANE_SHOT: u32 = 185_358;
26    ///<https://wowlab.gg/inspect/spell/56641>
27    pub(crate) const STEADY_SHOT: u32 = 56641;
28    ///<https://wowlab.gg/inspect/spell/982>
29    pub(crate) const REVIVE_PET: u32 = 982;
30    ///<https://wowlab.gg/inspect/spell/883>
31    pub(crate) const CALL_PET_1: u32 = 883;
32    ///<https://wowlab.gg/inspect/spell/259277>
33    pub(crate) const KILL_COMMAND_PET: u32 = 259_277;
34    ///<https://wowlab.gg/inspect/spell/265157>
35    pub(crate) const WILDFIRE_BOMB_DAMAGE: u32 = 265_157;
36    ///<https://wowlab.gg/inspect/spell/1253171>
37    pub(crate) const WILDFIRE_BOMB_BLEED: u32 = 1_253_171;
38    ///<https://wowlab.gg/inspect/spell/1250646>
39    pub(crate) const TAKEDOWN: u32 = 1_250_646;
40    ///<https://wowlab.gg/inspect/spell/1261193>
41    pub(crate) const BOOMSTICK: u32 = 1_261_193;
42    ///<https://wowlab.gg/inspect/spell/1251592>
43    pub(crate) const FLAMEFANG_PITCH: u32 = 1_251_592;
44    ///<https://wowlab.gg/inspect/spell/193265>
45    pub(crate) const HATCHET_TOSS: u32 = 193_265;
46    ///<https://wowlab.gg/inspect/spell/1262293>
47    pub(crate) const RAPTOR_SWIPE: u32 = 1_262_293;
48    ///<https://wowlab.gg/inspect/spell/1261215>
49    pub(crate) const BOOMSTICK_DAMAGE: u32 = 1_261_215;
50    ///<https://wowlab.gg/inspect/spell/1253859>
51    pub(crate) const TAKEDOWN_DAMAGE: u32 = 1_253_859;
52    ///<https://wowlab.gg/inspect/spell/1253862>
53    pub(crate) const TAKEDOWN_PET: u32 = 1_253_862;
54    ///<https://wowlab.gg/inspect/spell/1251595>
55    pub(crate) const FLAMEFANG_PITCH_DAMAGE: u32 = 1_251_595;
56    ///<https://wowlab.gg/inspect/spell/1251614>
57    pub(crate) const FLAMEFANG_PITCH_AOE: u32 = 1_251_614;
58    ///<https://wowlab.gg/inspect/spell/16827>
59    pub(crate) const CLAW: u32 = 16827;
60    ///<https://wowlab.gg/inspect/spell/1251779>
61    pub(crate) const STRIKE_AS_ONE: u32 = 1_251_779;
62    ///<https://wowlab.gg/inspect/spell/471936>
63    pub(crate) const BOAR_CHARGE: u32 = 471_936;
64    ///<https://wowlab.gg/inspect/spell/471938>
65    pub(crate) const BOAR_CHARGE_CLEAVE: u32 = 471_938;
66    ///<https://wowlab.gg/inspect/spell/201594>
67    pub(crate) const STAMPEDE_TICK: u32 = 201_594;
68}
69pub(crate) mod AURA {
70    ///<https://wowlab.gg/inspect/spell/459529>
71    pub(crate) const UNNATURAL_CAUSES: u32 = 459_529;
72    ///<https://wowlab.gg/inspect/spell/260286>
73    pub(crate) const TIP_OF_THE_SPEAR: u32 = 260_286;
74    ///<https://wowlab.gg/inspect/spell/462599>
75    pub(crate) const TRACK_PETS: u32 = 462_599;
76    ///<https://wowlab.gg/inspect/spell/1273155>
77    pub(crate) const RAPTOR_SWIPE: u32 = 1_273_155;
78    ///<https://wowlab.gg/inspect/spell/1250646>
79    pub(crate) const TAKEDOWN: u32 = 1_250_646;
80    ///<https://wowlab.gg/inspect/spell/471877>
81    pub(crate) const HOWL_COOLDOWN: u32 = 471_877;
82    ///<https://wowlab.gg/inspect/spell/471878>
83    pub(crate) const WYVERN_READY: u32 = 471_878;
84    ///<https://wowlab.gg/inspect/spell/472324>
85    pub(crate) const BOAR_READY: u32 = 472_324;
86    ///<https://wowlab.gg/inspect/spell/472325>
87    pub(crate) const BEAR_READY: u32 = 472_325;
88    ///<https://wowlab.gg/inspect/spell/471999>
89    pub(crate) const REND_FLESH: u32 = 471_999;
90    ///<https://wowlab.gg/inspect/spell/471881>
91    pub(crate) const WYVERNS_CRY: u32 = 471_881;
92    ///<https://wowlab.gg/inspect/spell/1253138>
93    pub(crate) const SIC_EM: u32 = 1_253_138;
94}
95pub(crate) mod TALENT {
96    ///<https://wowlab.gg/inspect/spell/1251592>
97    pub(crate) const FLAMEFANG_PITCH: u32 = 1_251_592;
98    ///<https://wowlab.gg/inspect/spell/1259017>
99    pub(crate) const RAPTOR_SWIPE_2: u32 = 1_259_017;
100    ///<https://wowlab.gg/inspect/spell/1251717>
101    pub(crate) const STRIKE_AS_ONE: u32 = 1_251_717;
102    ///<https://wowlab.gg/inspect/spell/260285>
103    pub(crate) const TIP_OF_THE_SPEAR: u32 = 260_285;
104    ///<https://wowlab.gg/inspect/spell/459527>
105    pub(crate) const UNNATURAL_CAUSES: u32 = 459_527;
106}
107pub(crate) mod HERO {
108    pub(crate) mod PACK_LEADER {
109        pub(crate) mod SPELL {
110            ///<https://wowlab.gg/inspect/spell/471936>
111            pub(crate) const BOAR_CHARGE: u32 = 471_936;
112            ///<https://wowlab.gg/inspect/spell/471938>
113            pub(crate) const BOAR_CHARGE_CLEAVE: u32 = 471_938;
114            ///<https://wowlab.gg/inspect/spell/471878>
115            pub(crate) const HOWL_OF_THE_PACK_LEADER: u32 = 471_878;
116        }
117        pub(crate) mod AURA {
118            ///<https://wowlab.gg/inspect/spell/472325>
119            pub(crate) const BEAR_READY: u32 = 472_325;
120            ///<https://wowlab.gg/inspect/spell/472324>
121            pub(crate) const BOAR_READY: u32 = 472_324;
122            ///<https://wowlab.gg/inspect/spell/471944>
123            pub(crate) const ENVENOMED_FANGS: u32 = 471_944;
124            ///<https://wowlab.gg/inspect/spell/471939>
125            pub(crate) const MONGOOSE_FURY: u32 = 471_939;
126            ///<https://wowlab.gg/inspect/spell/321014>
127            pub(crate) const PACK_MENTALITY: u32 = 321_014;
128            ///<https://wowlab.gg/inspect/spell/471878>
129            pub(crate) const WYVERN_READY: u32 = 471_878;
130        }
131    }
132    pub(crate) mod SENTINEL {
133        pub(crate) mod SPELL {
134            ///<https://wowlab.gg/inspect/spell/1253733>
135            pub(crate) const LUNAR_STORM_DAMAGE: u32 = 1_253_733;
136            ///<https://wowlab.gg/inspect/spell/1264949>
137            pub(crate) const MOONLIGHT_CHAKRAM: u32 = 1_264_949;
138            ///<https://wowlab.gg/inspect/spell/1266081>
139            pub(crate) const MOONLIGHT_CHAKRAM_DAMAGE: u32 = 1_266_081;
140            ///<https://wowlab.gg/inspect/spell/1266096>
141            pub(crate) const TWILIGHT_REQUIEM_DAMAGE: u32 = 1_266_096;
142        }
143        pub(crate) mod AURA {
144            ///<https://wowlab.gg/inspect/spell/1264946>
145            pub(crate) const MOONLIGHT_CHAKRAM_BUFF: u32 = 1_264_946;
146            ///<https://wowlab.gg/inspect/spell/1253836>
147            pub(crate) const SANCTIFIED_ARMAMENTS_DOT: u32 = 1_253_836;
148            ///<https://wowlab.gg/inspect/spell/1253601>
149            pub(crate) const SENTINELS_MARK: u32 = 1_253_601;
150            ///<https://wowlab.gg/inspect/spell/1253750>
151            pub(crate) const STARGAZER: u32 = 1_253_750;
152        }
153    }
154}
155static HERO_TREE_PACK_LEADER_SPELLS: &[(&str, u32)] = &[
156    ("BOAR_CHARGE", 471_936),
157    ("BOAR_CHARGE_CLEAVE", 471_938),
158    ("HOWL_OF_THE_PACK_LEADER", 471_878),
159];
160static HERO_TREE_PACK_LEADER_AURAS: &[(&str, u32)] = &[
161    ("BEAR_READY", 472_325),
162    ("BOAR_READY", 472_324),
163    ("ENVENOMED_FANGS", 471_944),
164    ("MONGOOSE_FURY", 471_939),
165    ("PACK_MENTALITY", 321_014),
166    ("WYVERN_READY", 471_878),
167];
168static HERO_TREE_SENTINEL_SPELLS: &[(&str, u32)] = &[
169    ("LUNAR_STORM_DAMAGE", 1_253_733),
170    ("MOONLIGHT_CHAKRAM", 1_264_949),
171    ("MOONLIGHT_CHAKRAM_DAMAGE", 1_266_081),
172    ("TWILIGHT_REQUIEM_DAMAGE", 1_266_096),
173];
174static HERO_TREE_SENTINEL_AURAS: &[(&str, u32)] = &[
175    ("MOONLIGHT_CHAKRAM_BUFF", 1_264_946),
176    ("SANCTIFIED_ARMAMENTS_DOT", 1_253_836),
177    ("SENTINELS_MARK", 1_253_601),
178    ("STARGAZER", 1_253_750),
179];
180pub(crate) const AURA_UNNATURAL_CAUSES: LocalAuraIdx = LocalAuraIdx::new(0);
181pub(crate) const AURA_TIP_OF_THE_SPEAR: LocalAuraIdx = LocalAuraIdx::new(1);
182pub(crate) const AURA_TRACK_PETS: LocalAuraIdx = LocalAuraIdx::new(2);
183pub(crate) const AURA_RAPTOR_SWIPE: LocalAuraIdx = LocalAuraIdx::new(3);
184pub(crate) const AURA_TAKEDOWN: LocalAuraIdx = LocalAuraIdx::new(4);
185pub(crate) const AURA_HOWL_COOLDOWN: LocalAuraIdx = LocalAuraIdx::new(5);
186pub(crate) const AURA_WYVERN_READY: LocalAuraIdx = LocalAuraIdx::new(6);
187pub(crate) const AURA_BOAR_READY: LocalAuraIdx = LocalAuraIdx::new(7);
188pub(crate) const AURA_BEAR_READY: LocalAuraIdx = LocalAuraIdx::new(8);
189pub(crate) const AURA_REND_FLESH: LocalAuraIdx = LocalAuraIdx::new(9);
190pub(crate) const AURA_WYVERNS_CRY: LocalAuraIdx = LocalAuraIdx::new(10);
191pub(crate) const AURA_SIC_EM: LocalAuraIdx = LocalAuraIdx::new(11);
192pub(crate) const AURA_COUNT: usize = 12;
193const _: () = assert!(
194    AURA_COUNT == 12, "AURA index ABI: count changed -- update positional hook consumers"
195);
196pub(crate) const SPELL_KILL_COMMAND: LocalSpellIdx = LocalSpellIdx::new(0);
197pub(crate) const SPELL_WILDFIRE_BOMB: LocalSpellIdx = LocalSpellIdx::new(1);
198pub(crate) const SPELL_MONGOOSE_BITE: LocalSpellIdx = LocalSpellIdx::new(2);
199pub(crate) const SPELL_RAPTOR_STRIKE: LocalSpellIdx = LocalSpellIdx::new(3);
200pub(crate) const SPELL_ARCANE_SHOT: LocalSpellIdx = LocalSpellIdx::new(4);
201pub(crate) const SPELL_STEADY_SHOT: LocalSpellIdx = LocalSpellIdx::new(5);
202pub(crate) const SPELL_REVIVE_PET: LocalSpellIdx = LocalSpellIdx::new(6);
203pub(crate) const SPELL_CALL_PET_1: LocalSpellIdx = LocalSpellIdx::new(7);
204pub(crate) const SPELL_KILL_COMMAND_PET: LocalSpellIdx = LocalSpellIdx::new(8);
205pub(crate) const SPELL_WILDFIRE_BOMB_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(9);
206pub(crate) const SPELL_WILDFIRE_BOMB_BLEED: LocalSpellIdx = LocalSpellIdx::new(10);
207pub(crate) const SPELL_TAKEDOWN: LocalSpellIdx = LocalSpellIdx::new(11);
208pub(crate) const SPELL_BOOMSTICK: LocalSpellIdx = LocalSpellIdx::new(12);
209pub(crate) const SPELL_FLAMEFANG_PITCH: LocalSpellIdx = LocalSpellIdx::new(13);
210pub(crate) const SPELL_HATCHET_TOSS: LocalSpellIdx = LocalSpellIdx::new(14);
211pub(crate) const SPELL_RAPTOR_SWIPE: LocalSpellIdx = LocalSpellIdx::new(15);
212pub(crate) const SPELL_BOOMSTICK_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(16);
213pub(crate) const SPELL_TAKEDOWN_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(17);
214pub(crate) const SPELL_TAKEDOWN_PET: LocalSpellIdx = LocalSpellIdx::new(18);
215pub(crate) const SPELL_FLAMEFANG_PITCH_DAMAGE: LocalSpellIdx = LocalSpellIdx::new(19);
216pub(crate) const SPELL_FLAMEFANG_PITCH_AOE: LocalSpellIdx = LocalSpellIdx::new(20);
217pub(crate) const SPELL_CLAW: LocalSpellIdx = LocalSpellIdx::new(21);
218pub(crate) const SPELL_STRIKE_AS_ONE: LocalSpellIdx = LocalSpellIdx::new(22);
219pub(crate) const SPELL_BOAR_CHARGE: LocalSpellIdx = LocalSpellIdx::new(23);
220pub(crate) const SPELL_BOAR_CHARGE_CLEAVE: LocalSpellIdx = LocalSpellIdx::new(24);
221pub(crate) const SPELL_STAMPEDE_TICK: LocalSpellIdx = LocalSpellIdx::new(25);
222pub(crate) const SPELL_COUNT: usize = 26;
223const _: () = assert!(
224    SPELL_COUNT == 26,
225    "SPELL index ABI: count changed -- update positional hook consumers"
226);
227pub(crate) mod EFFECT {
228    ///<https://wowlab.gg/inspect/spell/471936>
229    pub(crate) const BOAR_CHARGE: (u32, u8) = (471_936, 1);
230    ///<https://wowlab.gg/inspect/spell/471938>
231    pub(crate) const BOAR_CHARGE_CLEAVE: (u32, u8) = (471_938, 1);
232    ///<https://wowlab.gg/inspect/spell/1261215>
233    pub(crate) const BOOMSTICK_DAMAGE: (u32, u8) = (1_261_215, 1);
234    ///<https://wowlab.gg/inspect/spell/1251614>
235    pub(crate) const FLAMEFANG_PITCH_AOE: (u32, u8) = (1_251_614, 1);
236    ///<https://wowlab.gg/inspect/spell/1251595>
237    pub(crate) const FLAMEFANG_PITCH_DAMAGE: (u32, u8) = (1_251_595, 1);
238    ///<https://wowlab.gg/inspect/spell/471876>
239    pub(crate) const HOWL_WYVERN_STACKS: (u32, u8) = (471_876, 3);
240    ///<https://wowlab.gg/inspect/spell/259277>
241    pub(crate) const KILL_COMMAND_PET_DAMAGE: (u32, u8) = (259_277, 1);
242    ///<https://wowlab.gg/inspect/spell/186270>
243    pub(crate) const RAPTOR_STRIKE_DAMAGE: (u32, u8) = (186_270, 1);
244    ///<https://wowlab.gg/inspect/spell/1259019>
245    pub(crate) const RAPTOR_SWIPE_CHANCE: (u32, u8) = (1_259_019, 1);
246    ///<https://wowlab.gg/inspect/spell/1262293>
247    pub(crate) const RAPTOR_SWIPE_DAMAGE: (u32, u8) = (1_262_293, 1);
248    ///<https://wowlab.gg/inspect/spell/1259019>
249    pub(crate) const RAPTOR_SWIPE_STRIKE_AS_ONE: (u32, u8) = (1_259_019, 2);
250    ///<https://wowlab.gg/inspect/spell/1259017>
251    pub(crate) const RAPTOR_SWIPE_TWO_PRIMARY: (u32, u8) = (1_259_017, 2);
252    ///<https://wowlab.gg/inspect/spell/263135>
253    pub(crate) const SPIRIT_BOND_DIRECT: (u32, u8) = (263_135, 1);
254    ///<https://wowlab.gg/inspect/spell/201594>
255    pub(crate) const STAMPEDE_DAMAGE: (u32, u8) = (201_594, 1);
256    ///<https://wowlab.gg/inspect/spell/1251779>
257    pub(crate) const STRIKE_AS_ONE_DAMAGE: (u32, u8) = (1_251_779, 1);
258    ///<https://wowlab.gg/inspect/spell/1253859>
259    pub(crate) const TAKEDOWN_DAMAGE: (u32, u8) = (1_253_859, 1);
260    ///<https://wowlab.gg/inspect/spell/1258571>
261    pub(crate) const TAKEDOWN_FOCUS: (u32, u8) = (1_258_571, 1);
262    ///<https://wowlab.gg/inspect/spell/1253862>
263    pub(crate) const TAKEDOWN_PET_DAMAGE: (u32, u8) = (1_253_862, 1);
264    ///<https://wowlab.gg/inspect/spell/260285>
265    pub(crate) const TIP_OF_THE_SPEAR_BONUS: (u32, u8) = (260_285, 1);
266    ///<https://wowlab.gg/inspect/spell/265157>
267    pub(crate) const WILDFIRE_BOMB_DAMAGE: (u32, u8) = (265_157, 1);
268    ///<https://wowlab.gg/inspect/spell/1253171>
269    pub(crate) const WILDFIRE_BOMB_DOT: (u32, u8) = (1_253_171, 1);
270}
271static REPORTED_SPELLS: &[(&str, u32)] = &[];
272static DECLARED_SPELL_IDS: &[u32] = &[
273    259_489, 259_495, 259_387, 186_270, 185_358, 56641, 982, 883, 259_277, 265_157,
274    1_253_171, 1_250_646, 1_261_193, 1_251_592, 193_265, 1_262_293, 1_261_215, 1_253_859,
275    1_253_862, 1_251_595, 1_251_614, 16827, 1_251_779, 471_936, 471_938, 201_594,
276    459_529, 260_286, 462_599, 1_273_155, 1_250_646, 471_877, 471_878, 472_324, 472_325,
277    471_999, 471_881, 1_253_138, 6603, 6603, 186_270, 201_594, 259_277, 260_285, 263_135,
278    265_157, 471_876, 471_936, 471_938, 471_993, 471_999, 1_251_595, 1_251_614,
279    1_251_779, 1_253_138, 1_253_171, 1_253_859, 1_253_862, 1_258_571, 1_259_017,
280    1_259_019, 1_261_215, 1_262_293, 471_936, 471_938, 471_878, 472_325, 472_324,
281    471_944, 471_939, 321_014, 471_878, 1_253_733, 1_264_949, 1_266_081, 1_266_096,
282    1_264_946, 1_253_836, 1_253_601, 1_253_750,
283];
284static DECLARED_AURA_IDS: &[u32] = &[
285    459_529, 260_286, 462_599, 1_273_155, 1_250_646, 471_877, 471_878, 472_324, 472_325,
286    471_999, 471_881, 1_253_138, 472_325, 472_324, 471_944, 471_939, 321_014, 471_878,
287    1_264_946, 1_253_836, 1_253_601, 1_253_750,
288];
289static TALENTS: &[(&str, u32)] = &[
290    ("FLAMEFANG_PITCH", TALENT::FLAMEFANG_PITCH),
291    ("RAPTOR_SWIPE_2", TALENT::RAPTOR_SWIPE_2),
292    ("STRIKE_AS_ONE", TALENT::STRIKE_AS_ONE),
293    ("TIP_OF_THE_SPEAR", TALENT::TIP_OF_THE_SPEAR),
294    ("UNNATURAL_CAUSES", TALENT::UNNATURAL_CAUSES),
295];
296fn aura_unnatural_causes(
297    a: AuraDefinitionDraft,
298    data: &ResolvedGameData,
299) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
300    Ok(
301        a
302            .on_target()
303            .apply_base_from_data(data, 459_529)?
304            .max_stacks(
305                data
306                    .require_aura_max_stacks(
307                        wowlab_types::sim::SpellIdx::from_raw(459_529),
308                    )?,
309            ),
310    )
311}
312fn aura_tip_of_the_spear(
313    a: AuraDefinitionDraft,
314    data: &ResolvedGameData,
315) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
316    Ok(
317        a
318            .on_player()
319            .apply_base_from_data(data, 260_286)?
320            .max_stacks(
321                data
322                    .require_aura_max_stacks(
323                        wowlab_types::sim::SpellIdx::from_raw(260_286),
324                    )?,
325            ),
326    )
327}
328fn aura_track_pets(
329    a: AuraDefinitionDraft,
330    data: &ResolvedGameData,
331) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
332    Ok(
333        a
334            .on_player()
335            .apply_base_from_data(data, 462_599)?
336            .max_stacks(
337                data
338                    .require_aura_max_stacks(
339                        wowlab_types::sim::SpellIdx::from_raw(462_599),
340                    )?,
341            ),
342    )
343}
344fn aura_raptor_swipe(
345    a: AuraDefinitionDraft,
346    data: &ResolvedGameData,
347) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
348    Ok(
349        a
350            .on_player()
351            .apply_base_from_data(data, 1_273_155)?
352            .max_stacks(
353                data
354                    .require_aura_max_stacks(
355                        wowlab_types::sim::SpellIdx::from_raw(1_273_155),
356                    )?,
357            ),
358    )
359}
360fn aura_takedown(
361    a: AuraDefinitionDraft,
362    data: &ResolvedGameData,
363) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
364    Ok(
365        a
366            .on_player()
367            .apply_base_from_data(data, 1_250_646)?
368            .max_stacks(
369                data
370                    .require_aura_max_stacks(
371                        wowlab_types::sim::SpellIdx::from_raw(1_250_646),
372                    )?,
373            ),
374    )
375}
376fn aura_howl_cooldown(
377    a: AuraDefinitionDraft,
378    data: &ResolvedGameData,
379) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
380    Ok(
381        a
382            .on_player()
383            .apply_base_from_data(data, 471_877)?
384            .max_stacks(
385                data
386                    .require_aura_max_stacks(
387                        wowlab_types::sim::SpellIdx::from_raw(471_877),
388                    )?,
389            )
390            .on_expire(crate::hooks::survival_hunter::howl_cooldown_expire_hook),
391    )
392}
393fn aura_wyvern_ready(
394    a: AuraDefinitionDraft,
395    data: &ResolvedGameData,
396) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
397    Ok(
398        a
399            .on_player()
400            .apply_base_from_data(data, 471_878)?
401            .max_stacks(
402                data
403                    .require_aura_max_stacks(
404                        wowlab_types::sim::SpellIdx::from_raw(471_878),
405                    )?,
406            ),
407    )
408}
409fn aura_boar_ready(
410    a: AuraDefinitionDraft,
411    data: &ResolvedGameData,
412) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
413    Ok(
414        a
415            .on_player()
416            .apply_base_from_data(data, 472_324)?
417            .max_stacks(
418                data
419                    .require_aura_max_stacks(
420                        wowlab_types::sim::SpellIdx::from_raw(472_324),
421                    )?,
422            ),
423    )
424}
425fn aura_bear_ready(
426    a: AuraDefinitionDraft,
427    data: &ResolvedGameData,
428) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
429    Ok(
430        a
431            .on_player()
432            .apply_base_from_data(data, 472_325)?
433            .max_stacks(
434                data
435                    .require_aura_max_stacks(
436                        wowlab_types::sim::SpellIdx::from_raw(472_325),
437                    )?,
438            ),
439    )
440}
441fn aura_rend_flesh(
442    a: AuraDefinitionDraft,
443    data: &ResolvedGameData,
444) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
445    a.on_target()
446        .apply_base_from_data(data, 471_999)?
447        .max_stacks(
448            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(471_999))?,
449        )
450        .periodic_damage(
451            wowlab_engine_combat::validated_milliseconds(
452                data.period(wowlab_types::sim::SpellIdx::from_raw(471_999), 1),
453                471_999,
454                "periodic_damage.tick_ms",
455            )?,
456            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(471_999), 1)) * 0.6)
457                * 100.0)
458                .round() / 100.0,
459            wowlab_engine_combat::DamageFlags::PHYSICAL,
460        )
461        .apply_periodic_behavior_from_data(data, 471_999)
462}
463fn aura_wyverns_cry(
464    a: AuraDefinitionDraft,
465    data: &ResolvedGameData,
466) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
467    a.on_player()
468        .duration_ms(
469            wowlab_engine_combat::validated_milliseconds(
470                f64::from(
471                    data
472                        .require_aura_duration_ms(
473                            wowlab_types::sim::SpellIdx::from_raw(471_993),
474                        )?,
475                ),
476                471_881,
477                "aura.duration_ms",
478            )?,
479        )
480        .apply_periodic_effect_from_data(data, 471_881)?
481        .apply_duration_behavior_from_data(data, 471_993)?
482        .apply_timing_modifiers_from_data(data, 471_881)?
483        .max_stacks(
484            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(471_881))?,
485        )
486        .apply_periodic_behavior_from_data(data, 471_993)
487}
488fn aura_sic_em(
489    a: AuraDefinitionDraft,
490    data: &ResolvedGameData,
491) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
492    a.on_target()
493        .apply_base_from_data(data, 1_253_138)?
494        .max_stacks(
495            data
496                .require_aura_max_stacks(
497                    wowlab_types::sim::SpellIdx::from_raw(1_253_138),
498                )?,
499        )
500        .periodic_damage(
501            wowlab_engine_combat::validated_milliseconds(
502                data.period(wowlab_types::sim::SpellIdx::from_raw(1_253_138), 1),
503                1_253_138,
504                "periodic_damage.tick_ms",
505            )?,
506            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(1_253_138), 1)) * 0.6)
507                * 1000.0)
508                .round() / 1000.0,
509            wowlab_engine_combat::DamageFlags::PHYSICAL,
510        )
511        .apply_periodic_behavior_from_data(data, 1_253_138)
512}
513fn spell_kill_command(
514    s: SpellDefinitionDraft,
515    data: &ResolvedGameData,
516) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
517    Ok(
518        s
519            .apply_base_from_data(data, 259_489)?
520            .gain(15.0)
521            .applies_aura(AURA_TIP_OF_THE_SPEAR)
522            .apply_aoe_from_data(data)
523            .on_cast(crate::hooks::survival_hunter::kill_command_hook),
524    )
525}
526fn spell_wildfire_bomb(
527    s: SpellDefinitionDraft,
528    data: &ResolvedGameData,
529) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
530    Ok(
531        s
532            .apply_base_from_data(data, 259_495)?
533            .apply_aoe_from_data(data)
534            .on_cast(crate::hooks::survival_hunter::wildfire_bomb_hook),
535    )
536}
537fn spell_mongoose_bite(
538    s: SpellDefinitionDraft,
539    data: &ResolvedGameData,
540) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
541    Ok(s.apply_base_from_data(data, 259_387)?.apply_aoe_from_data(data))
542}
543fn spell_raptor_strike(
544    s: SpellDefinitionDraft,
545    data: &ResolvedGameData,
546) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
547    Ok(
548        s
549            .apply_base_from_data(data, 186_270)?
550            .damage_flat(0.0)
551            .apply_aoe_from_data(data)
552            .on_cast(crate::hooks::survival_hunter::raptor_strike_hook),
553    )
554}
555fn spell_arcane_shot(
556    s: SpellDefinitionDraft,
557    data: &ResolvedGameData,
558) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
559    Ok(s.apply_base_from_data(data, 185_358)?.apply_aoe_from_data(data))
560}
561fn spell_steady_shot(
562    s: SpellDefinitionDraft,
563    data: &ResolvedGameData,
564) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
565    Ok(s.apply_base_from_data(data, 56641)?.apply_aoe_from_data(data))
566}
567fn spell_revive_pet(
568    s: SpellDefinitionDraft,
569    data: &ResolvedGameData,
570) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
571    Ok(s.apply_base_from_data(data, 982)?.apply_aoe_from_data(data))
572}
573fn spell_call_pet_1(
574    s: SpellDefinitionDraft,
575    data: &ResolvedGameData,
576) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
577    Ok(s.apply_base_from_data(data, 883)?.apply_aoe_from_data(data))
578}
579fn spell_kill_command_pet(
580    s: SpellDefinitionDraft,
581    data: &ResolvedGameData,
582) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
583    Ok(s.apply_base_from_data(data, 259_277)?.apply_aoe_from_data(data))
584}
585fn spell_wildfire_bomb_damage(
586    s: SpellDefinitionDraft,
587    data: &ResolvedGameData,
588) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
589    Ok(s.apply_base_from_data(data, 265_157)?.apply_aoe_from_data(data))
590}
591fn spell_wildfire_bomb_bleed(
592    s: SpellDefinitionDraft,
593    data: &ResolvedGameData,
594) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
595    Ok(s.apply_base_from_data(data, 1_253_171)?.apply_aoe_from_data(data))
596}
597fn spell_takedown(
598    s: SpellDefinitionDraft,
599    data: &ResolvedGameData,
600) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
601    Ok(
602        s
603            .apply_base_from_data(data, 1_250_646)?
604            .applies_inferred_aura(AURA_TAKEDOWN, 1_250_646)
605            .apply_aoe_from_data(data)
606            .on_cast(crate::hooks::survival_hunter::takedown_hook),
607    )
608}
609fn spell_boomstick(
610    s: SpellDefinitionDraft,
611    data: &ResolvedGameData,
612) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
613    Ok(
614        s
615            .apply_base_from_data(data, 1_261_193)?
616            .damage_flat(0.0)
617            .apply_aoe_from_data(data)
618            .on_cast(crate::hooks::survival_hunter::boomstick_hook),
619    )
620}
621fn spell_flamefang_pitch(
622    s: SpellDefinitionDraft,
623    data: &ResolvedGameData,
624) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
625    Ok(
626        s
627            .apply_base_from_data(data, 1_251_592)?
628            .apply_aoe_from_data(data)
629            .on_cast(crate::hooks::survival_hunter::flamefang_pitch_hook),
630    )
631}
632fn spell_hatchet_toss(
633    s: SpellDefinitionDraft,
634    data: &ResolvedGameData,
635) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
636    Ok(s.apply_base_from_data(data, 193_265)?.apply_aoe_from_data(data))
637}
638fn spell_raptor_swipe(
639    s: SpellDefinitionDraft,
640    data: &ResolvedGameData,
641) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
642    Ok(
643        s
644            .apply_base_from_data(data, 1_262_293)?
645            .applies_inferred_aura(AURA_RAPTOR_SWIPE, 1_273_155)
646            .apply_aoe_from_data(data),
647    )
648}
649fn spell_boomstick_damage(
650    s: SpellDefinitionDraft,
651    data: &ResolvedGameData,
652) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
653    Ok(s.apply_base_from_data(data, 1_261_215)?.apply_aoe_from_data(data))
654}
655fn spell_takedown_damage(
656    s: SpellDefinitionDraft,
657    data: &ResolvedGameData,
658) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
659    Ok(s.apply_base_from_data(data, 1_253_859)?.apply_aoe_from_data(data))
660}
661fn spell_takedown_pet(
662    s: SpellDefinitionDraft,
663    data: &ResolvedGameData,
664) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
665    Ok(s.apply_base_from_data(data, 1_253_862)?.apply_aoe_from_data(data))
666}
667fn spell_flamefang_pitch_damage(
668    s: SpellDefinitionDraft,
669    data: &ResolvedGameData,
670) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
671    Ok(s.apply_base_from_data(data, 1_251_595)?.apply_aoe_from_data(data))
672}
673fn spell_flamefang_pitch_aoe(
674    s: SpellDefinitionDraft,
675    data: &ResolvedGameData,
676) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
677    Ok(s.apply_base_from_data(data, 1_251_614)?.apply_aoe_from_data(data))
678}
679fn spell_claw(
680    s: SpellDefinitionDraft,
681    data: &ResolvedGameData,
682) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
683    Ok(s.apply_base_from_data(data, 16827)?.apply_aoe_from_data(data))
684}
685fn spell_strike_as_one(
686    s: SpellDefinitionDraft,
687    data: &ResolvedGameData,
688) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
689    Ok(s.apply_base_from_data(data, 1_251_779)?.apply_aoe_from_data(data))
690}
691fn spell_boar_charge(
692    s: SpellDefinitionDraft,
693    data: &ResolvedGameData,
694) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
695    Ok(s.apply_base_from_data(data, 471_936)?.apply_aoe_from_data(data))
696}
697fn spell_boar_charge_cleave(
698    s: SpellDefinitionDraft,
699    data: &ResolvedGameData,
700) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
701    Ok(s.apply_base_from_data(data, 471_938)?.apply_aoe_from_data(data))
702}
703fn spell_stampede_tick(
704    s: SpellDefinitionDraft,
705    data: &ResolvedGameData,
706) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
707    Ok(s.apply_base_from_data(data, 201_594)?.apply_aoe_from_data(data))
708}
709pub(crate) fn build_combat_system(
710    params: &wowlab_engine_ports::HandlerParams<'_>,
711) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
712    let builder = BuiltCombatSystem::builder(params.stats.clone())
713        .spec_id(SpecId::Survival)
714        .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
715        .mastery_spell(263_135)
716        .mastery_hook(crate::hooks::survival_hunter::mastery)
717        .resource(
718            "focus",
719            params
720                .game_data
721                .power_max(2)
722                .ok_or_else(|| {
723                    wowlab_engine_ports::EngineError::spec_construction(
724                        "missing power-type power_max for type_id 2",
725                    )
726                })?,
727            params
728                .game_data
729                .power_regen_for_max(
730                    2,
731                    params
732                        .game_data
733                        .power_max(2)
734                        .ok_or_else(|| {
735                            wowlab_engine_ports::EngineError::spec_construction(
736                                "missing power-type power_max for type_id 2",
737                            )
738                        })?,
739                )
740                .ok_or_else(|| {
741                    wowlab_engine_ports::EngineError::spec_construction(
742                        "missing power-type power_regen_for_max for type_id 2",
743                    )
744                })?,
745        )
746        .resource_type_id(2)
747        .resource_start(
748            params
749                .game_data
750                .power_default(2)
751                .ok_or_else(|| {
752                    wowlab_engine_ports::EngineError::spec_construction(
753                        "missing power-type power_default for type_id 2",
754                    )
755                })?,
756        )
757        .has_pet(true)
758        .aura(
759            "unnatural_causes",
760            AURA::UNNATURAL_CAUSES,
761            |a| aura_unnatural_causes(a, &params.game_data),
762        )
763        .aura(
764            "tip_of_the_spear",
765            AURA::TIP_OF_THE_SPEAR,
766            |a| aura_tip_of_the_spear(a, &params.game_data),
767        )
768        .aura("track_pets", AURA::TRACK_PETS, |a| aura_track_pets(a, &params.game_data))
769        .aura(
770            "raptor_swipe",
771            AURA::RAPTOR_SWIPE,
772            |a| aura_raptor_swipe(a, &params.game_data),
773        )
774        .aura("takedown", AURA::TAKEDOWN, |a| aura_takedown(a, &params.game_data))
775        .aura(
776            "howl_cooldown",
777            AURA::HOWL_COOLDOWN,
778            |a| aura_howl_cooldown(a, &params.game_data),
779        )
780        .aura(
781            "wyvern_ready",
782            AURA::WYVERN_READY,
783            |a| aura_wyvern_ready(a, &params.game_data),
784        )
785        .aura("boar_ready", AURA::BOAR_READY, |a| aura_boar_ready(a, &params.game_data))
786        .aura("bear_ready", AURA::BEAR_READY, |a| aura_bear_ready(a, &params.game_data))
787        .aura("rend_flesh", AURA::REND_FLESH, |a| aura_rend_flesh(a, &params.game_data))
788        .aura(
789            "wyverns_cry",
790            AURA::WYVERNS_CRY,
791            |a| aura_wyverns_cry(a, &params.game_data),
792        )
793        .aura("sic_em", AURA::SIC_EM, |a| aura_sic_em(a, &params.game_data))
794        .spell(
795            "kill_command",
796            SPELL::KILL_COMMAND,
797            |s| spell_kill_command(s, &params.game_data),
798        )
799        .spell(
800            "wildfire_bomb",
801            SPELL::WILDFIRE_BOMB,
802            |s| spell_wildfire_bomb(s, &params.game_data),
803        )
804        .spell(
805            "mongoose_bite",
806            SPELL::MONGOOSE_BITE,
807            |s| spell_mongoose_bite(s, &params.game_data),
808        )
809        .spell(
810            "raptor_strike",
811            SPELL::RAPTOR_STRIKE,
812            |s| spell_raptor_strike(s, &params.game_data),
813        )
814        .spell(
815            "arcane_shot",
816            SPELL::ARCANE_SHOT,
817            |s| spell_arcane_shot(s, &params.game_data),
818        )
819        .spell(
820            "steady_shot",
821            SPELL::STEADY_SHOT,
822            |s| spell_steady_shot(s, &params.game_data),
823        )
824        .spell(
825            "revive_pet",
826            SPELL::REVIVE_PET,
827            |s| spell_revive_pet(s, &params.game_data),
828        )
829        .spell(
830            "call_pet_1",
831            SPELL::CALL_PET_1,
832            |s| spell_call_pet_1(s, &params.game_data),
833        )
834        .spell(
835            "kill_command_pet",
836            SPELL::KILL_COMMAND_PET,
837            |s| spell_kill_command_pet(s, &params.game_data),
838        )
839        .spell(
840            "wildfire_bomb_damage",
841            SPELL::WILDFIRE_BOMB_DAMAGE,
842            |s| spell_wildfire_bomb_damage(s, &params.game_data),
843        )
844        .spell(
845            "wildfire_bomb_bleed",
846            SPELL::WILDFIRE_BOMB_BLEED,
847            |s| spell_wildfire_bomb_bleed(s, &params.game_data),
848        )
849        .spell("takedown", SPELL::TAKEDOWN, |s| spell_takedown(s, &params.game_data))
850        .spell("boomstick", SPELL::BOOMSTICK, |s| spell_boomstick(s, &params.game_data))
851        .spell(
852            "flamefang_pitch",
853            SPELL::FLAMEFANG_PITCH,
854            |s| spell_flamefang_pitch(s, &params.game_data),
855        )
856        .spell(
857            "hatchet_toss",
858            SPELL::HATCHET_TOSS,
859            |s| spell_hatchet_toss(s, &params.game_data),
860        )
861        .spell(
862            "raptor_swipe",
863            SPELL::RAPTOR_SWIPE,
864            |s| spell_raptor_swipe(s, &params.game_data),
865        )
866        .spell(
867            "boomstick_damage",
868            SPELL::BOOMSTICK_DAMAGE,
869            |s| spell_boomstick_damage(s, &params.game_data),
870        )
871        .spell(
872            "takedown_damage",
873            SPELL::TAKEDOWN_DAMAGE,
874            |s| spell_takedown_damage(s, &params.game_data),
875        )
876        .spell(
877            "takedown_pet",
878            SPELL::TAKEDOWN_PET,
879            |s| spell_takedown_pet(s, &params.game_data),
880        )
881        .spell(
882            "flamefang_pitch_damage",
883            SPELL::FLAMEFANG_PITCH_DAMAGE,
884            |s| spell_flamefang_pitch_damage(s, &params.game_data),
885        )
886        .spell(
887            "flamefang_pitch_aoe",
888            SPELL::FLAMEFANG_PITCH_AOE,
889            |s| spell_flamefang_pitch_aoe(s, &params.game_data),
890        )
891        .spell("claw", SPELL::CLAW, |s| spell_claw(s, &params.game_data))
892        .spell(
893            "strike_as_one",
894            SPELL::STRIKE_AS_ONE,
895            |s| spell_strike_as_one(s, &params.game_data),
896        )
897        .spell(
898            "boar_charge",
899            SPELL::BOAR_CHARGE,
900            |s| spell_boar_charge(s, &params.game_data),
901        )
902        .spell(
903            "boar_charge_cleave",
904            SPELL::BOAR_CHARGE_CLEAVE,
905            |s| spell_boar_charge_cleave(s, &params.game_data),
906        )
907        .spell(
908            "stampede_tick",
909            SPELL::STAMPEDE_TICK,
910            |s| spell_stampede_tick(s, &params.game_data),
911        )
912        .auto_attack(|a| {
913            a.spell_id(6603).swing_ms(3000).apply_base_from_data(&params.game_data)
914        })
915        .auto_attack(|a| {
916            a
917                .spell_id(6603)
918                .swing_ms(2000)
919                .apply_base_from_data(&params.game_data)
920                .ap_coef(0.2)
921                .is_pet()
922                .on_swing(crate::hooks::survival_hunter::pet_swing)
923        })
924        .game_data(params.game_data.clone())
925        .talent_spell_ids(TALENTS)
926        .talent_selections(params.talent_selections)
927        .talent_companion_aura(TALENT::UNNATURAL_CAUSES, AURA_UNNATURAL_CAUSES)
928        .set_bonus_auras(params.set_bonus_auras)
929        .encounter(params.encounter.clone());
930    let builder = crate::generated::items::register_equipped(
931        builder,
932        &params.game_data,
933        params.equipped_items,
934    )?;
935
936    builder
937        .build(params.rotation)
938        .map_err(wowlab_engine_ports::EngineError::rotation_compile)
939}
940fn new_handler(
941    params: wowlab_engine_ports::HandlerParams<'_>,
942) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
943    let handler = crate::composition::compose_handler(
944        build_combat_system,
945        &params,
946        |parts, _| Ok(parts.into_handler()),
947    )?;
948
949    Ok(Box::new(handler))
950}
951static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
952    primary_resource: ResourceType::Focus,
953    secondary_resource: None,
954    spell_ids: DECLARED_SPELL_IDS,
955    aura_ids: DECLARED_AURA_IDS,
956    server_proc_entries: &[
957        DeclaredServerProcEntry {
958            spell_id: 260_286,
959            attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
960                | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
961        },
962    ],
963    talents: TALENTS,
964    rotation_field_schema: &[],
965    metrics_plugin_id: None,
966    hero_talent_trees: &[
967        HeroTalentTreeDesc {
968            name: "Pack Leader",
969            spells: HERO_TREE_PACK_LEADER_SPELLS,
970            auras: HERO_TREE_PACK_LEADER_AURAS,
971        },
972        HeroTalentTreeDesc {
973            name: "Sentinel",
974            spells: HERO_TREE_SENTINEL_SPELLS,
975            auras: HERO_TREE_SENTINEL_AURAS,
976        },
977    ],
978    reported_spells: REPORTED_SPELLS,
979    masked_passive_effects: &[],
980    passive_effect_overrides: &[],
981};
982pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
983    spec_id: SpecId::Survival,
984    display_name: "Survival Hunter",
985    metadata: DECLARED_METADATA,
986    handler_factory: new_handler,
987};
988wowlab_engine_combat::smoke_test!(build_combat_system);