Skip to main content

wowlab_engine_content/generated/specs/
beast_mastery_hunter.rs

1//! @generated by codegen-cli from manifests/specs/hunter/beast_mastery/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/34026>
15    pub(crate) const KILL_COMMAND: u32 = 34026;
16    ///<https://wowlab.gg/inspect/spell/217200>
17    pub(crate) const BARBED_SHOT: u32 = 217_200;
18    ///<https://wowlab.gg/inspect/spell/19574>
19    pub(crate) const BESTIAL_WRATH: u32 = 19574;
20    ///<https://wowlab.gg/inspect/spell/193455>
21    pub(crate) const ARCANE_SHOT: u32 = 193_455;
22    ///<https://wowlab.gg/inspect/spell/56641>
23    pub(crate) const STEADY_SHOT: u32 = 56641;
24    ///<https://wowlab.gg/inspect/spell/466930>
25    pub(crate) const BLACK_ARROW: u32 = 466_930;
26    ///<https://wowlab.gg/inspect/spell/1264359>
27    pub(crate) const WILD_THRASH: u32 = 1_264_359;
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}
33pub(crate) mod AURA {
34    ///<https://wowlab.gg/inspect/spell/19574>
35    pub(crate) const BESTIAL_WRATH: u32 = 19574;
36    ///<https://wowlab.gg/inspect/spell/459529>
37    pub(crate) const UNNATURAL_CAUSES: u32 = 459_529;
38    ///<https://wowlab.gg/inspect/spell/217200>
39    pub(crate) const BARBED_SHOT_DOT: u32 = 217_200;
40    ///<https://wowlab.gg/inspect/spell/246152>
41    pub(crate) const BARBED_SHOT_REGEN: u32 = 246_152;
42    ///<https://wowlab.gg/inspect/spell/268877>
43    pub(crate) const BEAST_CLEAVE: u32 = 268_877;
44    ///<https://wowlab.gg/inspect/spell/321538>
45    pub(crate) const BLOODSHED_DOT: u32 = 321_538;
46    ///<https://wowlab.gg/inspect/spell/219199>
47    pub(crate) const DIRE_BEAST_ACTIVE: u32 = 219_199;
48    ///<https://wowlab.gg/inspect/spell/1282474>
49    pub(crate) const NATURES_ALLY: u32 = 1_282_474;
50    ///<https://wowlab.gg/inspect/spell/1276720>
51    pub(crate) const NATURES_ALLY_KILL_COMMAND: u32 = 1_276_720;
52    ///<https://wowlab.gg/inspect/spell/1265063>
53    pub(crate) const BLOODY_FRENZY: u32 = 1_265_063;
54    ///<https://wowlab.gg/inspect/spell/471877>
55    pub(crate) const HOWL_COOLDOWN: u32 = 471_877;
56    ///<https://wowlab.gg/inspect/spell/471878>
57    pub(crate) const WYVERN_READY: u32 = 471_878;
58    ///<https://wowlab.gg/inspect/spell/472324>
59    pub(crate) const BOAR_READY: u32 = 472_324;
60    ///<https://wowlab.gg/inspect/spell/472325>
61    pub(crate) const BEAR_READY: u32 = 472_325;
62    ///<https://wowlab.gg/inspect/spell/471881>
63    pub(crate) const WYVERNS_CRY: u32 = 471_881;
64    ///<https://wowlab.gg/inspect/spell/459731>
65    pub(crate) const HUNTMASTERS_CALL: u32 = 459_731;
66    ///<https://wowlab.gg/inspect/spell/471993>
67    pub(crate) const BEAR_ACTIVE: u32 = 471_993;
68    ///<https://wowlab.gg/inspect/spell/471999>
69    pub(crate) const REND_FLESH: u32 = 471_999;
70}
71pub(crate) mod TALENT {
72    ///<https://wowlab.gg/inspect/spell/217200>
73    pub(crate) const BARBED_SHOT: u32 = 217_200;
74    ///<https://wowlab.gg/inspect/spell/19574>
75    pub(crate) const BESTIAL_WRATH: u32 = 19574;
76    ///<https://wowlab.gg/inspect/spell/466930>
77    pub(crate) const BLACK_ARROW: u32 = 466_930;
78    ///<https://wowlab.gg/inspect/spell/407412>
79    pub(crate) const BLOODY_FRENZY: u32 = 407_412;
80    ///<https://wowlab.gg/inspect/spell/120679>
81    pub(crate) const DIRE_BEAST: u32 = 120_679;
82    ///<https://wowlab.gg/inspect/spell/34026>
83    pub(crate) const KILL_COMMAND: u32 = 34026;
84    ///<https://wowlab.gg/inspect/spell/321014>
85    pub(crate) const PACK_TACTICS: u32 = 321_014;
86    ///<https://wowlab.gg/inspect/spell/459527>
87    pub(crate) const UNNATURAL_CAUSES: u32 = 459_527;
88    ///<https://wowlab.gg/inspect/spell/1264359>
89    pub(crate) const WILD_THRASH: u32 = 1_264_359;
90}
91pub(crate) mod HERO {
92    pub(crate) mod PACK_LEADER {
93        pub(crate) mod SPELL {
94            ///<https://wowlab.gg/inspect/spell/471936>
95            pub(crate) const BOAR_CHARGE: u32 = 471_936;
96            ///<https://wowlab.gg/inspect/spell/471938>
97            pub(crate) const BOAR_CHARGE_CLEAVE: u32 = 471_938;
98            ///<https://wowlab.gg/inspect/spell/201594>
99            pub(crate) const STAMPEDE_TICK: u32 = 201_594;
100        }
101    }
102    pub(crate) mod BM_PETS {
103        pub(crate) mod SPELL {
104            ///<https://wowlab.gg/inspect/spell/118459>
105            pub(crate) const BEAST_CLEAVE: u32 = 118_459;
106            ///<https://wowlab.gg/inspect/spell/321538>
107            pub(crate) const BLOODSHED: u32 = 321_538;
108            ///<https://wowlab.gg/inspect/spell/16827>
109            pub(crate) const CLAW: u32 = 16827;
110            ///<https://wowlab.gg/inspect/spell/83381>
111            pub(crate) const KILL_COMMAND_PET: u32 = 83381;
112            ///<https://wowlab.gg/inspect/spell/6603>
113            pub(crate) const MELEE: u32 = 6603;
114            ///<https://wowlab.gg/inspect/spell/344572>
115            pub(crate) const PET_BESTIAL_WRATH: u32 = 344_572;
116            ///<https://wowlab.gg/inspect/spell/459753>
117            pub(crate) const RAVENOUS_LEAP: u32 = 459_753;
118            ///<https://wowlab.gg/inspect/spell/201754>
119            pub(crate) const STOMP: u32 = 201_754;
120            ///<https://wowlab.gg/inspect/spell/1232922>
121            pub(crate) const WILDSPEAKER_KILL_COMMAND: u32 = 1_232_922;
122            ///<https://wowlab.gg/inspect/spell/1264355>
123            pub(crate) const WILD_THRASH: u32 = 1_264_355;
124        }
125    }
126}
127static HERO_TREE_PACK_LEADER_SPELLS: &[(&str, u32)] = &[
128    ("BOAR_CHARGE", 471_936),
129    ("BOAR_CHARGE_CLEAVE", 471_938),
130    ("STAMPEDE_TICK", 201_594),
131];
132static HERO_TREE_PACK_LEADER_AURAS: &[(&str, u32)] = &[];
133static HERO_TREE_BM_PETS_SPELLS: &[(&str, u32)] = &[
134    ("BEAST_CLEAVE", 118_459),
135    ("BLOODSHED", 321_538),
136    ("CLAW", 16827),
137    ("KILL_COMMAND_PET", 83381),
138    ("MELEE", 6603),
139    ("PET_BESTIAL_WRATH", 344_572),
140    ("RAVENOUS_LEAP", 459_753),
141    ("STOMP", 201_754),
142    ("WILDSPEAKER_KILL_COMMAND", 1_232_922),
143    ("WILD_THRASH", 1_264_355),
144];
145static HERO_TREE_BM_PETS_AURAS: &[(&str, u32)] = &[];
146pub(crate) const AURA_BESTIAL_WRATH: LocalAuraIdx = LocalAuraIdx::new(0);
147pub(crate) const AURA_UNNATURAL_CAUSES: LocalAuraIdx = LocalAuraIdx::new(1);
148pub(crate) const AURA_BARBED_SHOT_DOT: LocalAuraIdx = LocalAuraIdx::new(2);
149pub(crate) const AURA_BARBED_SHOT_REGEN: LocalAuraIdx = LocalAuraIdx::new(3);
150pub(crate) const AURA_BEAST_CLEAVE: LocalAuraIdx = LocalAuraIdx::new(4);
151pub(crate) const AURA_BLOODSHED_DOT: LocalAuraIdx = LocalAuraIdx::new(5);
152pub(crate) const AURA_DIRE_BEAST_ACTIVE: LocalAuraIdx = LocalAuraIdx::new(6);
153pub(crate) const AURA_NATURES_ALLY: LocalAuraIdx = LocalAuraIdx::new(7);
154pub(crate) const AURA_NATURES_ALLY_KILL_COMMAND: LocalAuraIdx = LocalAuraIdx::new(8);
155pub(crate) const AURA_BLOODY_FRENZY: LocalAuraIdx = LocalAuraIdx::new(9);
156pub(crate) const AURA_HOWL_COOLDOWN: LocalAuraIdx = LocalAuraIdx::new(10);
157pub(crate) const AURA_WYVERN_READY: LocalAuraIdx = LocalAuraIdx::new(11);
158pub(crate) const AURA_BOAR_READY: LocalAuraIdx = LocalAuraIdx::new(12);
159pub(crate) const AURA_BEAR_READY: LocalAuraIdx = LocalAuraIdx::new(13);
160pub(crate) const AURA_WYVERNS_CRY: LocalAuraIdx = LocalAuraIdx::new(14);
161pub(crate) const AURA_HUNTMASTERS_CALL: LocalAuraIdx = LocalAuraIdx::new(15);
162pub(crate) const AURA_BEAR_ACTIVE: LocalAuraIdx = LocalAuraIdx::new(16);
163pub(crate) const AURA_REND_FLESH: LocalAuraIdx = LocalAuraIdx::new(17);
164pub(crate) const AURA_COUNT: usize = 18;
165const _: () = assert!(
166    AURA_COUNT == 18, "AURA index ABI: count changed -- update positional hook consumers"
167);
168pub(crate) const SPELL_KILL_COMMAND: LocalSpellIdx = LocalSpellIdx::new(0);
169pub(crate) const SPELL_BARBED_SHOT: LocalSpellIdx = LocalSpellIdx::new(1);
170pub(crate) const SPELL_BESTIAL_WRATH: LocalSpellIdx = LocalSpellIdx::new(2);
171pub(crate) const SPELL_ARCANE_SHOT: LocalSpellIdx = LocalSpellIdx::new(3);
172pub(crate) const SPELL_STEADY_SHOT: LocalSpellIdx = LocalSpellIdx::new(4);
173pub(crate) const SPELL_BLACK_ARROW: LocalSpellIdx = LocalSpellIdx::new(5);
174pub(crate) const SPELL_WILD_THRASH: LocalSpellIdx = LocalSpellIdx::new(6);
175pub(crate) const SPELL_REVIVE_PET: LocalSpellIdx = LocalSpellIdx::new(7);
176pub(crate) const SPELL_CALL_PET_1: LocalSpellIdx = LocalSpellIdx::new(8);
177pub(crate) const SPELL_COUNT: usize = 9;
178const _: () = assert!(
179    SPELL_COUNT == 9,
180    "SPELL index ABI: count changed -- update positional hook consumers"
181);
182pub(crate) mod EFFECT {
183    ///<https://wowlab.gg/inspect/spell/269737>
184    pub(crate) const ALPHA_PREDATOR_KC_PCT: (u32, u8) = (269_737, 2);
185    ///<https://wowlab.gg/inspect/spell/471936>
186    pub(crate) const BOAR_CHARGE: (u32, u8) = (471_936, 1);
187    ///<https://wowlab.gg/inspect/spell/471938>
188    pub(crate) const BOAR_CHARGE_CLEAVE: (u32, u8) = (471_938, 1);
189    ///<https://wowlab.gg/inspect/spell/378743>
190    pub(crate) const DIRE_COMMAND_PCT: (u32, u8) = (378_743, 1);
191    ///<https://wowlab.gg/inspect/spell/471876>
192    pub(crate) const HOWL_WYVERN_STACKS: (u32, u8) = (471_876, 3);
193    ///<https://wowlab.gg/inspect/spell/83381>
194    pub(crate) const KC_PET_DAMAGE: (u32, u8) = (83381, 1);
195    ///<https://wowlab.gg/inspect/spell/472358>
196    pub(crate) const PACK_MENTALITY_BARBED_CDR: (u32, u8) = (472_358, 2);
197    ///<https://wowlab.gg/inspect/spell/472358>
198    pub(crate) const PACK_MENTALITY_KC_PCT: (u32, u8) = (472_358, 1);
199    ///<https://wowlab.gg/inspect/spell/1282660>
200    pub(crate) const PACK_TACTICS_FOCUS: (u32, u8) = (1_282_660, 1);
201    ///<https://wowlab.gg/inspect/spell/344572>
202    pub(crate) const PET_BW_DAMAGE: (u32, u8) = (344_572, 1);
203    ///<https://wowlab.gg/inspect/spell/459753>
204    pub(crate) const RAVENOUS_LEAP: (u32, u8) = (459_753, 1);
205    ///<https://wowlab.gg/inspect/spell/201594>
206    pub(crate) const STAMPEDE_DAMAGE: (u32, u8) = (201_594, 1);
207    ///<https://wowlab.gg/inspect/spell/1258344>
208    pub(crate) const STAMPEDE_GEOMETRY: (u32, u8) = (1_258_344, 1);
209    ///<https://wowlab.gg/inspect/spell/201754>
210    pub(crate) const STOMP_DAMAGE: (u32, u8) = (201_754, 1);
211    ///<https://wowlab.gg/inspect/spell/118459>
212    pub(crate) const BEAST_CLEAVE_DAMAGE: (u32, u8) = (118_459, 1);
213    ///<https://wowlab.gg/inspect/spell/115939>
214    pub(crate) const BEAST_CLEAVE_FRACTION: (u32, u8) = (115_939, 1);
215    ///<https://wowlab.gg/inspect/spell/118459>
216    pub(crate) const BEAST_CLEAVE_REDUCED_TARGETS: (u32, u8) = (118_459, 2);
217    ///<https://wowlab.gg/inspect/spell/115939>
218    pub(crate) const BEAST_CLEAVE_DURATION: (u32, u8) = (115_939, 2);
219    ///<https://wowlab.gg/inspect/spell/459693>
220    pub(crate) const THUNDERING_HOOVES_PCT: (u32, u8) = (459_693, 1);
221    ///<https://wowlab.gg/inspect/spell/1264355>
222    pub(crate) const WILD_THRASH_DAMAGE: (u32, u8) = (1_264_355, 1);
223    ///<https://wowlab.gg/inspect/spell/1264359>
224    pub(crate) const WILD_THRASH_BONUS: (u32, u8) = (1_264_359, 1);
225    ///<https://wowlab.gg/inspect/spell/1264359>
226    pub(crate) const WILD_THRASH_THRESHOLD: (u32, u8) = (1_264_359, 2);
227    ///<https://wowlab.gg/inspect/spell/1232922>
228    pub(crate) const WILDSPEAKER_KC: (u32, u8) = (1_232_922, 1);
229    ///<https://wowlab.gg/inspect/spell/471881>
230    pub(crate) const WYVERNS_CRY_PCT: (u32, u8) = (471_881, 1);
231}
232static REPORTED_SPELLS: &[(&str, u32)] = &[];
233static DECLARED_SPELL_IDS: &[u32] = &[
234    34026, 217_200, 19574, 193_455, 56641, 466_930, 1_264_359, 982, 883, 19574, 459_529,
235    217_200, 246_152, 268_877, 321_538, 219_199, 1_282_474, 1_276_720, 1_265_063,
236    471_877, 471_878, 472_324, 472_325, 471_881, 459_731, 471_993, 471_999, 75, 6603,
237    76657, 83381, 115_939, 118_459, 120_679, 186_254, 193_455, 201_594, 201_754, 269_737,
238    321_538, 344_572, 378_743, 459_693, 459_753, 471_876, 471_881, 471_936, 471_938,
239    471_999, 472_358, 1_232_922, 1_258_344, 1_264_355, 1_264_359, 1_282_660, 471_936,
240    471_938, 201_594, 118_459, 321_538, 16827, 83381, 6603, 344_572, 459_753, 201_754,
241    1_232_922, 1_264_355,
242];
243static DECLARED_AURA_IDS: &[u32] = &[
244    19574, 459_529, 217_200, 246_152, 268_877, 321_538, 219_199, 1_282_474, 1_276_720,
245    1_265_063, 471_877, 471_878, 472_324, 472_325, 471_881, 459_731, 471_993, 471_999,
246];
247static TALENTS: &[(&str, u32)] = &[
248    ("BARBED_SHOT", TALENT::BARBED_SHOT),
249    ("BESTIAL_WRATH", TALENT::BESTIAL_WRATH),
250    ("BLACK_ARROW", TALENT::BLACK_ARROW),
251    ("BLOODY_FRENZY", TALENT::BLOODY_FRENZY),
252    ("DIRE_BEAST", TALENT::DIRE_BEAST),
253    ("KILL_COMMAND", TALENT::KILL_COMMAND),
254    ("PACK_TACTICS", TALENT::PACK_TACTICS),
255    ("UNNATURAL_CAUSES", TALENT::UNNATURAL_CAUSES),
256    ("WILD_THRASH", TALENT::WILD_THRASH),
257];
258pub(crate) mod BM_HUNTER {
259    pub(crate) const KILL_COMMAND_CASTS: u32 = 0;
260    pub(crate) const BARBED_SHOT_CASTS: u32 = 1;
261    pub(crate) const BESTIAL_WRATH_CASTS: u32 = 2;
262    pub(crate) const COBRA_SHOT_CASTS: u32 = 3;
263    pub(crate) const BESTIAL_WRATH_UPTIME_MS: u32 = 4;
264}
265fn aura_bestial_wrath(
266    a: AuraDefinitionDraft,
267    data: &ResolvedGameData,
268) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
269    a.on_player()
270        .apply_base_from_data(data, 19574)?
271        .max_stacks(
272            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(19574))?,
273        )
274        .pet_damage_multiplier(
275            ((data.base_points(wowlab_types::sim::SpellIdx::from_raw(186_254), 1))
276                * 0.01) + 1.0,
277        )
278}
279fn aura_unnatural_causes(
280    a: AuraDefinitionDraft,
281    data: &ResolvedGameData,
282) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
283    Ok(
284        a
285            .on_target()
286            .apply_base_from_data(data, 459_529)?
287            .max_stacks(
288                data
289                    .require_aura_max_stacks(
290                        wowlab_types::sim::SpellIdx::from_raw(459_529),
291                    )?,
292            ),
293    )
294}
295fn aura_barbed_shot_dot(
296    a: AuraDefinitionDraft,
297    data: &ResolvedGameData,
298) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
299    Ok(
300        a
301            .on_target()
302            .apply_base_from_data(data, 217_200)?
303            .max_stacks(
304                data
305                    .require_aura_max_stacks(
306                        wowlab_types::sim::SpellIdx::from_raw(217_200),
307                    )?,
308            ),
309    )
310}
311fn aura_barbed_shot_regen(
312    a: AuraDefinitionDraft,
313    data: &ResolvedGameData,
314) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
315    Ok(
316        a
317            .on_player()
318            .apply_base_from_data(data, 246_152)?
319            .max_stacks(
320                data
321                    .require_aura_max_stacks(
322                        wowlab_types::sim::SpellIdx::from_raw(246_152),
323                    )?,
324            ),
325    )
326}
327fn aura_beast_cleave(
328    a: AuraDefinitionDraft,
329    data: &ResolvedGameData,
330) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
331    Ok(
332        a
333            .on_player()
334            .apply_base_from_data(data, 268_877)?
335            .max_stacks(
336                data
337                    .require_aura_max_stacks(
338                        wowlab_types::sim::SpellIdx::from_raw(268_877),
339                    )?,
340            ),
341    )
342}
343fn aura_bloodshed_dot(
344    a: AuraDefinitionDraft,
345    data: &ResolvedGameData,
346) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
347    a.on_target()
348        .apply_base_from_data(data, 321_538)?
349        .max_stacks(
350            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(321_538))?,
351        )
352        .periodic_damage(
353            wowlab_engine_combat::validated_milliseconds(
354                data.period(wowlab_types::sim::SpellIdx::from_raw(321_538), 1),
355                321_538,
356                "periodic_damage.tick_ms",
357            )?,
358            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(321_538), 1)) * 1.8)
359                * 100.0)
360                .round() / 100.0,
361            wowlab_engine_combat::DamageFlags::PHYSICAL,
362        )
363        .apply_periodic_behavior_from_data(data, 321_538)
364}
365fn aura_dire_beast_active(
366    a: AuraDefinitionDraft,
367    data: &ResolvedGameData,
368) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
369    Ok(
370        a
371            .on_player()
372            .apply_base_from_data(data, 219_199)?
373            .max_stacks(
374                wowlab_engine_combat::validated_max_stacks(
375                    6.0,
376                    219_199,
377                    "aura.max_stacks",
378                )?,
379            ),
380    )
381}
382fn aura_natures_ally(
383    a: AuraDefinitionDraft,
384    data: &ResolvedGameData,
385) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
386    Ok(
387        a
388            .on_player()
389            .apply_base_from_data(data, 1_282_474)?
390            .max_stacks(
391                data
392                    .require_aura_max_stacks(
393                        wowlab_types::sim::SpellIdx::from_raw(1_282_474),
394                    )?,
395            ),
396    )
397}
398fn aura_natures_ally_kill_command(
399    a: AuraDefinitionDraft,
400    data: &ResolvedGameData,
401) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
402    Ok(
403        a
404            .on_player()
405            .apply_base_from_data(data, 1_276_720)?
406            .max_stacks(
407                data
408                    .require_aura_max_stacks(
409                        wowlab_types::sim::SpellIdx::from_raw(1_276_720),
410                    )?,
411            ),
412    )
413}
414fn aura_bloody_frenzy(
415    a: AuraDefinitionDraft,
416    data: &ResolvedGameData,
417) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
418    Ok(
419        a
420            .on_player()
421            .apply_base_from_data(data, 1_265_063)?
422            .max_stacks(
423                data
424                    .require_aura_max_stacks(
425                        wowlab_types::sim::SpellIdx::from_raw(1_265_063),
426                    )?,
427            ),
428    )
429}
430fn aura_howl_cooldown(
431    a: AuraDefinitionDraft,
432    data: &ResolvedGameData,
433) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
434    Ok(
435        a
436            .on_player()
437            .apply_base_from_data(data, 471_877)?
438            .max_stacks(
439                data
440                    .require_aura_max_stacks(
441                        wowlab_types::sim::SpellIdx::from_raw(471_877),
442                    )?,
443            ),
444    )
445}
446fn aura_wyvern_ready(
447    a: AuraDefinitionDraft,
448    data: &ResolvedGameData,
449) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
450    Ok(
451        a
452            .on_player()
453            .apply_base_from_data(data, 471_878)?
454            .max_stacks(
455                data
456                    .require_aura_max_stacks(
457                        wowlab_types::sim::SpellIdx::from_raw(471_878),
458                    )?,
459            ),
460    )
461}
462fn aura_boar_ready(
463    a: AuraDefinitionDraft,
464    data: &ResolvedGameData,
465) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
466    Ok(
467        a
468            .on_player()
469            .apply_base_from_data(data, 472_324)?
470            .max_stacks(
471                data
472                    .require_aura_max_stacks(
473                        wowlab_types::sim::SpellIdx::from_raw(472_324),
474                    )?,
475            ),
476    )
477}
478fn aura_bear_ready(
479    a: AuraDefinitionDraft,
480    data: &ResolvedGameData,
481) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
482    Ok(
483        a
484            .on_player()
485            .apply_base_from_data(data, 472_325)?
486            .max_stacks(
487                data
488                    .require_aura_max_stacks(
489                        wowlab_types::sim::SpellIdx::from_raw(472_325),
490                    )?,
491            ),
492    )
493}
494fn aura_wyverns_cry(
495    a: AuraDefinitionDraft,
496    data: &ResolvedGameData,
497) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
498    Ok(
499        a
500            .on_player()
501            .apply_base_from_data(data, 471_881)?
502            .max_stacks(
503                data
504                    .require_aura_max_stacks(
505                        wowlab_types::sim::SpellIdx::from_raw(471_881),
506                    )?,
507            ),
508    )
509}
510fn aura_huntmasters_call(
511    a: AuraDefinitionDraft,
512    data: &ResolvedGameData,
513) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
514    Ok(
515        a
516            .on_player()
517            .apply_base_from_data(data, 459_731)?
518            .max_stacks(
519                data
520                    .require_aura_max_stacks(
521                        wowlab_types::sim::SpellIdx::from_raw(459_731),
522                    )?,
523            ),
524    )
525}
526fn aura_bear_active(
527    a: AuraDefinitionDraft,
528    data: &ResolvedGameData,
529) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
530    Ok(
531        a
532            .on_player()
533            .apply_base_from_data(data, 471_993)?
534            .max_stacks(
535                data
536                    .require_aura_max_stacks(
537                        wowlab_types::sim::SpellIdx::from_raw(471_993),
538                    )?,
539            ),
540    )
541}
542fn aura_rend_flesh(
543    a: AuraDefinitionDraft,
544    data: &ResolvedGameData,
545) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
546    a.on_target()
547        .apply_base_from_data(data, 471_999)?
548        .max_stacks(
549            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(471_999))?,
550        )
551        .periodic_damage(
552            wowlab_engine_combat::validated_milliseconds(
553                data.period(wowlab_types::sim::SpellIdx::from_raw(471_999), 1),
554                471_999,
555                "periodic_damage.tick_ms",
556            )?,
557            (((data.ap_coef(wowlab_types::sim::SpellIdx::from_raw(471_999), 1)) * 0.6)
558                * 100.0)
559                .round() / 100.0,
560            wowlab_engine_combat::DamageFlags::PHYSICAL,
561        )
562        .apply_periodic_behavior_from_data(data, 471_999)
563}
564fn spell_kill_command(
565    s: SpellDefinitionDraft,
566    data: &ResolvedGameData,
567) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
568    Ok(
569        s
570            .apply_base_from_data(data, 34026)?
571            .apply_aoe_from_data(data)
572            .on_cast(crate::hooks::beast_mastery_hunter::kill_command_hook),
573    )
574}
575fn spell_barbed_shot(
576    s: SpellDefinitionDraft,
577    data: &ResolvedGameData,
578) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
579    Ok(
580        s
581            .apply_base_from_data(data, 217_200)?
582            .applies_inferred_aura(AURA_BARBED_SHOT_DOT, 217_200)
583            .apply_aoe_from_data(data)
584            .on_cast(crate::hooks::beast_mastery_hunter::barbed_shot_hook),
585    )
586}
587fn spell_bestial_wrath(
588    s: SpellDefinitionDraft,
589    data: &ResolvedGameData,
590) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
591    Ok(
592        s
593            .apply_base_from_data(data, 19574)?
594            .applies_inferred_aura(AURA_BESTIAL_WRATH, 19574)
595            .apply_aoe_from_data(data)
596            .on_cast(crate::hooks::beast_mastery_hunter::bestial_wrath_hook),
597    )
598}
599fn spell_arcane_shot(
600    s: SpellDefinitionDraft,
601    data: &ResolvedGameData,
602) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
603    Ok(
604        s
605            .apply_base_from_data(data, 193_455)?
606            .reduces_cd(
607                SPELL_KILL_COMMAND,
608                wowlab_engine_combat::validated_milliseconds(
609                    (data.base_points(wowlab_types::sim::SpellIdx::from_raw(193_455), 3))
610                        * 1000.0,
611                    193_455,
612                    "spell.reduces_cd.amount_ms",
613                )?,
614            )
615            .apply_aoe_from_data(data)
616            .on_cast(crate::hooks::beast_mastery_hunter::cobra_shot_hook),
617    )
618}
619fn spell_steady_shot(
620    s: SpellDefinitionDraft,
621    data: &ResolvedGameData,
622) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
623    Ok(s.apply_base_from_data(data, 56641)?.apply_aoe_from_data(data))
624}
625fn spell_black_arrow(
626    s: SpellDefinitionDraft,
627    data: &ResolvedGameData,
628) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
629    Ok(s.apply_base_from_data(data, 466_930)?.apply_aoe_from_data(data))
630}
631fn spell_wild_thrash(
632    s: SpellDefinitionDraft,
633    data: &ResolvedGameData,
634) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
635    Ok(
636        s
637            .apply_base_from_data(data, 1_264_359)?
638            .apply_aoe_from_data(data)
639            .on_cast(crate::hooks::beast_mastery_hunter::wild_thrash_hook),
640    )
641}
642fn spell_revive_pet(
643    s: SpellDefinitionDraft,
644    data: &ResolvedGameData,
645) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
646    Ok(s.apply_base_from_data(data, 982)?.apply_aoe_from_data(data))
647}
648fn spell_call_pet_1(
649    s: SpellDefinitionDraft,
650    data: &ResolvedGameData,
651) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
652    Ok(s.apply_base_from_data(data, 883)?.apply_aoe_from_data(data))
653}
654pub(crate) fn build_combat_system(
655    params: &wowlab_engine_ports::HandlerParams<'_>,
656) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
657    let builder = BuiltCombatSystem::builder(params.stats.clone())
658        .spec_id(SpecId::BeastMastery)
659        .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
660        .mastery_spell(76657)
661        .mastery_hook(crate::hooks::beast_mastery_hunter::mastery)
662        .resource(
663            "focus",
664            params
665                .game_data
666                .power_max(2)
667                .ok_or_else(|| {
668                    wowlab_engine_ports::EngineError::spec_construction(
669                        "missing power-type power_max for type_id 2",
670                    )
671                })?,
672            params
673                .game_data
674                .power_regen_for_max(
675                    2,
676                    params
677                        .game_data
678                        .power_max(2)
679                        .ok_or_else(|| {
680                            wowlab_engine_ports::EngineError::spec_construction(
681                                "missing power-type power_max for type_id 2",
682                            )
683                        })?,
684                )
685                .ok_or_else(|| {
686                    wowlab_engine_ports::EngineError::spec_construction(
687                        "missing power-type power_regen_for_max for type_id 2",
688                    )
689                })?,
690        )
691        .resource_type_id(2)
692        .resource_start(
693            params
694                .game_data
695                .power_default(2)
696                .ok_or_else(|| {
697                    wowlab_engine_ports::EngineError::spec_construction(
698                        "missing power-type power_default for type_id 2",
699                    )
700                })?,
701        )
702        .has_pet(true)
703        .aura(
704            "bestial_wrath",
705            AURA::BESTIAL_WRATH,
706            |a| aura_bestial_wrath(a, &params.game_data),
707        )
708        .aura(
709            "unnatural_causes",
710            AURA::UNNATURAL_CAUSES,
711            |a| aura_unnatural_causes(a, &params.game_data),
712        )
713        .aura(
714            "barbed_shot_dot",
715            AURA::BARBED_SHOT_DOT,
716            |a| aura_barbed_shot_dot(a, &params.game_data),
717        )
718        .aura(
719            "barbed_shot_regen",
720            AURA::BARBED_SHOT_REGEN,
721            |a| aura_barbed_shot_regen(a, &params.game_data),
722        )
723        .aura(
724            "beast_cleave",
725            AURA::BEAST_CLEAVE,
726            |a| aura_beast_cleave(a, &params.game_data),
727        )
728        .aura(
729            "bloodshed_dot",
730            AURA::BLOODSHED_DOT,
731            |a| aura_bloodshed_dot(a, &params.game_data),
732        )
733        .aura(
734            "dire_beast_active",
735            AURA::DIRE_BEAST_ACTIVE,
736            |a| aura_dire_beast_active(a, &params.game_data),
737        )
738        .aura(
739            "natures_ally",
740            AURA::NATURES_ALLY,
741            |a| aura_natures_ally(a, &params.game_data),
742        )
743        .aura(
744            "natures_ally_kill_command",
745            AURA::NATURES_ALLY_KILL_COMMAND,
746            |a| aura_natures_ally_kill_command(a, &params.game_data),
747        )
748        .aura(
749            "bloody_frenzy",
750            AURA::BLOODY_FRENZY,
751            |a| aura_bloody_frenzy(a, &params.game_data),
752        )
753        .aura(
754            "howl_cooldown",
755            AURA::HOWL_COOLDOWN,
756            |a| aura_howl_cooldown(a, &params.game_data),
757        )
758        .aura(
759            "wyvern_ready",
760            AURA::WYVERN_READY,
761            |a| aura_wyvern_ready(a, &params.game_data),
762        )
763        .aura("boar_ready", AURA::BOAR_READY, |a| aura_boar_ready(a, &params.game_data))
764        .aura("bear_ready", AURA::BEAR_READY, |a| aura_bear_ready(a, &params.game_data))
765        .aura(
766            "wyverns_cry",
767            AURA::WYVERNS_CRY,
768            |a| aura_wyverns_cry(a, &params.game_data),
769        )
770        .aura(
771            "huntmasters_call",
772            AURA::HUNTMASTERS_CALL,
773            |a| aura_huntmasters_call(a, &params.game_data),
774        )
775        .aura(
776            "bear_active",
777            AURA::BEAR_ACTIVE,
778            |a| aura_bear_active(a, &params.game_data),
779        )
780        .aura("rend_flesh", AURA::REND_FLESH, |a| aura_rend_flesh(a, &params.game_data))
781        .spell(
782            "kill_command",
783            SPELL::KILL_COMMAND,
784            |s| spell_kill_command(s, &params.game_data),
785        )
786        .spell(
787            "barbed_shot",
788            SPELL::BARBED_SHOT,
789            |s| spell_barbed_shot(s, &params.game_data),
790        )
791        .spell(
792            "bestial_wrath",
793            SPELL::BESTIAL_WRATH,
794            |s| spell_bestial_wrath(s, &params.game_data),
795        )
796        .spell(
797            "arcane_shot",
798            SPELL::ARCANE_SHOT,
799            |s| spell_arcane_shot(s, &params.game_data),
800        )
801        .spell(
802            "steady_shot",
803            SPELL::STEADY_SHOT,
804            |s| spell_steady_shot(s, &params.game_data),
805        )
806        .spell(
807            "black_arrow",
808            SPELL::BLACK_ARROW,
809            |s| spell_black_arrow(s, &params.game_data),
810        )
811        .spell(
812            "wild_thrash",
813            SPELL::WILD_THRASH,
814            |s| spell_wild_thrash(s, &params.game_data),
815        )
816        .spell(
817            "revive_pet",
818            SPELL::REVIVE_PET,
819            |s| spell_revive_pet(s, &params.game_data),
820        )
821        .spell(
822            "call_pet_1",
823            SPELL::CALL_PET_1,
824            |s| spell_call_pet_1(s, &params.game_data),
825        )
826        .auto_attack(|a| {
827            a.spell_id(75).swing_ms(3000).apply_base_from_data(&params.game_data)
828        })
829        .auto_attack(|a| {
830            a
831                .spell_id(6603)
832                .swing_ms(1667)
833                .apply_base_from_data(&params.game_data)
834                .ap_coef(
835                    wowlab_engine_domain::damage::pet_swing_power_coefficient(
836                        0.6,
837                        2000,
838                        1.0,
839                    ),
840                )
841                .is_pet()
842                .on_swing(crate::hooks::beast_mastery_hunter::pet_swing)
843        })
844        .game_data(params.game_data.clone())
845        .talent_spell_ids(TALENTS)
846        .talent_selections(params.talent_selections)
847        .talent_companion_aura(TALENT::UNNATURAL_CAUSES, AURA_UNNATURAL_CAUSES)
848        .register_impact_effect_proc_if_talent(
849            TALENT::DIRE_BEAST,
850            wowlab_engine_combat::ImpactEffectProcDefinition::new(
851                    wowlab_engine_combat::ImpactSource::ProcTypeMask(
852                        params
853                            .game_data
854                            .require_proc_type_mask(
855                                wowlab_types::sim::SpellIdx::from_raw(120_679),
856                            )?,
857                    ),
858                )
859                .dbc_driver_from_data(
860                    wowlab_engine_domain::dbc::EffectLookup::new(
861                        &params.game_data,
862                        wowlab_types::sim::EffectRef::new(
863                            wowlab_types::sim::SpellIdx::from_raw(120_679),
864                            1,
865                        ),
866                    ),
867                )
868                .chance(
869                    (params
870                        .game_data
871                        .base_points(wowlab_types::sim::SpellIdx::from_raw(120_679), 1))
872                        / 100.0,
873                )
874                .icd_ms(
875                    wowlab_engine_combat::validated_milliseconds(
876                            f64::from(
877                                params
878                                    .game_data
879                                    .require_proc_category_recovery_ms(
880                                        wowlab_types::sim::SpellIdx::from_raw(120_679),
881                                    )?,
882                            ),
883                            120_679,
884                            "impact_proc.icd_ms",
885                        )
886                        .map_err(|error| {
887                            wowlab_engine_ports::EngineError::spec_construction(
888                                error.to_string(),
889                            )
890                        })?,
891                )
892                .physical_only()
893                .fire(crate::hooks::beast_mastery_hunter::dire_beast_proc),
894        )
895        .set_bonus_auras(params.set_bonus_auras)
896        .encounter(params.encounter.clone());
897    let builder = crate::generated::items::register_equipped(
898        builder,
899        &params.game_data,
900        params.equipped_items,
901    )?;
902
903    builder
904        .build(params.rotation)
905        .map_err(wowlab_engine_ports::EngineError::rotation_compile)
906}
907fn new_handler(
908    params: wowlab_engine_ports::HandlerParams<'_>,
909) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
910    let handler = crate::composition::compose_handler(
911        build_combat_system,
912        &params,
913        crate::hooks::beast_mastery_hunter::BeastMasteryHandler::try_new,
914    )?;
915
916    Ok(Box::new(handler))
917}
918static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
919    primary_resource: ResourceType::Focus,
920    secondary_resource: None,
921    spell_ids: DECLARED_SPELL_IDS,
922    aura_ids: DECLARED_AURA_IDS,
923    server_proc_entries: &[],
924    talents: TALENTS,
925    rotation_field_schema: &[],
926    metrics_plugin_id: None,
927    hero_talent_trees: &[
928        HeroTalentTreeDesc {
929            name: "Pack Leader",
930            spells: HERO_TREE_PACK_LEADER_SPELLS,
931            auras: HERO_TREE_PACK_LEADER_AURAS,
932        },
933        HeroTalentTreeDesc {
934            name: "Bm Pets",
935            spells: HERO_TREE_BM_PETS_SPELLS,
936            auras: HERO_TREE_BM_PETS_AURAS,
937        },
938    ],
939    reported_spells: REPORTED_SPELLS,
940    masked_passive_effects: &[],
941    passive_effect_overrides: &[],
942};
943pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
944    spec_id: SpecId::BeastMastery,
945    display_name: "Beast Mastery Hunter",
946    metadata: DECLARED_METADATA,
947    handler_factory: new_handler,
948};
949wowlab_engine_combat::smoke_test!(build_combat_system);