Skip to main content

wowlab_engine_content/generated/specs/
marksmanship_hunter.rs

1//! @generated by codegen-cli from manifests/specs/hunter/marksmanship/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/19434>
17    pub(crate) const AIMED_SHOT: u32 = 19434;
18    ///<https://wowlab.gg/inspect/spell/257044>
19    pub(crate) const RAPID_FIRE: u32 = 257_044;
20    ///<https://wowlab.gg/inspect/spell/185358>
21    pub(crate) const ARCANE_SHOT: u32 = 185_358;
22    ///<https://wowlab.gg/inspect/spell/288613>
23    pub(crate) const TRUESHOT: u32 = 288_613;
24    ///<https://wowlab.gg/inspect/spell/53351>
25    pub(crate) const KILL_SHOT: u32 = 53351;
26    ///<https://wowlab.gg/inspect/spell/257620>
27    pub(crate) const MULTI_SHOT: u32 = 257_620;
28    ///<https://wowlab.gg/inspect/spell/56641>
29    pub(crate) const STEADY_SHOT: u32 = 56641;
30    ///<https://wowlab.gg/inspect/spell/260243>
31    pub(crate) const VOLLEY: u32 = 260_243;
32    ///<https://wowlab.gg/inspect/spell/257045>
33    pub(crate) const RAPID_FIRE_TICK: u32 = 257_045;
34}
35pub(crate) mod AURA {
36    ///<https://wowlab.gg/inspect/spell/459529>
37    pub(crate) const UNNATURAL_CAUSES: u32 = 459_529;
38    ///<https://wowlab.gg/inspect/spell/257622>
39    pub(crate) const TRICK_SHOTS: u32 = 257_622;
40    ///<https://wowlab.gg/inspect/spell/260242>
41    pub(crate) const PRECISE_SHOTS: u32 = 260_242;
42    ///<https://wowlab.gg/inspect/spell/288613>
43    pub(crate) const TRUESHOT: u32 = 288_613;
44    ///<https://wowlab.gg/inspect/spell/1277558>
45    pub(crate) const HEADSHOT: u32 = 1_277_558;
46    ///<https://wowlab.gg/inspect/spell/466872>
47    pub(crate) const SPOTTERS_MARK: u32 = 466_872;
48    ///<https://wowlab.gg/inspect/spell/269576>
49    pub(crate) const MASTER_MARKSMAN: u32 = 269_576;
50    ///<https://wowlab.gg/inspect/spell/466932>
51    pub(crate) const BLACK_ARROW: u32 = 466_932;
52    ///<https://wowlab.gg/inspect/spell/468572>
53    pub(crate) const BLACK_ARROW_DOT: u32 = 468_572;
54    ///<https://wowlab.gg/inspect/spell/378770>
55    pub(crate) const DEATHBLOW: u32 = 378_770;
56    ///<https://wowlab.gg/inspect/spell/466991>
57    pub(crate) const WITHERING_FIRE: u32 = 466_991;
58}
59pub(crate) mod TALENT {
60    ///<https://wowlab.gg/inspect/spell/466932>
61    pub(crate) const BLACK_ARROW: u32 = 466_932;
62    ///<https://wowlab.gg/inspect/spell/467749>
63    pub(crate) const BLEAK_ARROWS: u32 = 467_749;
64    ///<https://wowlab.gg/inspect/spell/1264291>
65    pub(crate) const BLIGHTED_QUIVER: u32 = 1_264_291;
66    ///<https://wowlab.gg/inspect/spell/343248>
67    pub(crate) const DEATHBLOW: u32 = 343_248;
68    ///<https://wowlab.gg/inspect/spell/470943>
69    pub(crate) const FEATHERED_FRENZY: u32 = 470_943;
70    ///<https://wowlab.gg/inspect/spell/378767>
71    pub(crate) const FOCUSED_AIM: u32 = 378_767;
72    ///<https://wowlab.gg/inspect/spell/471363>
73    pub(crate) const HEADSHOT: u32 = 471_363;
74    ///<https://wowlab.gg/inspect/spell/53351>
75    pub(crate) const KILL_SHOT_TALENT: u32 = 53351;
76    ///<https://wowlab.gg/inspect/spell/155228>
77    pub(crate) const LONE_WOLF: u32 = 155_228;
78    ///<https://wowlab.gg/inspect/spell/260309>
79    pub(crate) const MASTER_MARKSMAN: u32 = 260_309;
80    ///<https://wowlab.gg/inspect/spell/473385>
81    pub(crate) const NO_SCOPE: u32 = 473_385;
82    ///<https://wowlab.gg/inspect/spell/260240>
83    pub(crate) const PRECISE_SHOTS: u32 = 260_240;
84    ///<https://wowlab.gg/inspect/spell/469638>
85    pub(crate) const SOUL_DRINKER: u32 = 469_638;
86    ///<https://wowlab.gg/inspect/spell/1277565>
87    pub(crate) const THROUGH_THE_EYES: u32 = 1_277_565;
88    ///<https://wowlab.gg/inspect/spell/1277548>
89    pub(crate) const UNLOAD: u32 = 1_277_548;
90    ///<https://wowlab.gg/inspect/spell/459527>
91    pub(crate) const UNNATURAL_CAUSES: u32 = 459_527;
92    ///<https://wowlab.gg/inspect/spell/260243>
93    pub(crate) const VOLLEY: u32 = 260_243;
94    ///<https://wowlab.gg/inspect/spell/473523>
95    pub(crate) const WINDRUNNER_QUIVER: u32 = 473_523;
96    ///<https://wowlab.gg/inspect/spell/466990>
97    pub(crate) const WITHERING_FIRE: u32 = 466_990;
98}
99pub(crate) mod REPORTED_SPELL {
100    ///<https://wowlab.gg/inspect/spell/1264364>
101    pub(crate) const BLIGHTED_ARROW: u32 = 1_264_364;
102    ///<https://wowlab.gg/inspect/spell/1264357>
103    pub(crate) const SHOOT: u32 = 1_264_357;
104}
105pub(crate) mod HERO {
106    pub(crate) mod DARK_RANGER {
107        pub(crate) mod SPELL {
108            ///<https://wowlab.gg/inspect/spell/466930>
109            pub(crate) const BLACK_ARROW: u32 = 466_930;
110            ///<https://wowlab.gg/inspect/spell/468572>
111            pub(crate) const BLACK_ARROW_DOT_SPELL: u32 = 468_572;
112            ///<https://wowlab.gg/inspect/spell/466932>
113            pub(crate) const BLACK_ARROW_TALENT: u32 = 466_932;
114            ///<https://wowlab.gg/inspect/spell/468037>
115            pub(crate) const BLACK_ARROW_WITHERING_FIRE: u32 = 468_037;
116            ///<https://wowlab.gg/inspect/spell/467718>
117            pub(crate) const BLEAK_ARROWS: u32 = 467_718;
118            ///<https://wowlab.gg/inspect/spell/467749>
119            pub(crate) const BLEAK_ARROWS_TALENT: u32 = 467_749;
120            ///<https://wowlab.gg/inspect/spell/467914>
121            pub(crate) const BLEAK_POWDER: u32 = 467_914;
122            ///<https://wowlab.gg/inspect/spell/1264291>
123            pub(crate) const BLIGHTED_QUIVER_TALENT: u32 = 1_264_291;
124            ///<https://wowlab.gg/inspect/spell/1264289>
125            pub(crate) const CORPSECALLER_TALENT: u32 = 1_264_289;
126            ///<https://wowlab.gg/inspect/spell/1264345>
127            pub(crate) const DARK_MINION_SUMMON: u32 = 1_264_345;
128            ///<https://wowlab.gg/inspect/spell/1264690>
129            pub(crate) const PACT_OF_THE_HOLLOW_TALENT: u32 = 1_264_690;
130            ///<https://wowlab.gg/inspect/spell/469638>
131            pub(crate) const SOUL_DRINKER_TALENT: u32 = 469_638;
132            ///<https://wowlab.gg/inspect/spell/1277565>
133            pub(crate) const THROUGH_THE_EYES_TALENT: u32 = 1_277_565;
134            ///<https://wowlab.gg/inspect/spell/392060>
135            pub(crate) const WAILING_ARROW: u32 = 392_060;
136            ///<https://wowlab.gg/inspect/spell/392058>
137            pub(crate) const WAILING_ARROW_DAMAGE: u32 = 392_058;
138            ///<https://wowlab.gg/inspect/spell/1264290>
139            pub(crate) const WAILING_DEAD_TALENT: u32 = 1_264_290;
140            ///<https://wowlab.gg/inspect/spell/466990>
141            pub(crate) const WITHERING_FIRE_TALENT: u32 = 466_990;
142        }
143        pub(crate) mod AURA {
144            ///<https://wowlab.gg/inspect/spell/468572>
145            pub(crate) const BLACK_ARROW_DOT: u32 = 468_572;
146            ///<https://wowlab.gg/inspect/spell/378770>
147            pub(crate) const DEATHBLOW: u32 = 378_770;
148            ///<https://wowlab.gg/inspect/spell/467941>
149            pub(crate) const PHANTOM_PAIN: u32 = 467_941;
150            ///<https://wowlab.gg/inspect/spell/459808>
151            pub(crate) const WAILING_ARROW_BUFF: u32 = 459_808;
152            ///<https://wowlab.gg/inspect/spell/466991>
153            pub(crate) const WITHERING_FIRE: u32 = 466_991;
154        }
155    }
156    pub(crate) mod SENTINEL {
157        pub(crate) mod SPELL {
158            ///<https://wowlab.gg/inspect/spell/1253733>
159            pub(crate) const LUNAR_STORM_DAMAGE: u32 = 1_253_733;
160            ///<https://wowlab.gg/inspect/spell/1264949>
161            pub(crate) const MOONLIGHT_CHAKRAM: u32 = 1_264_949;
162            ///<https://wowlab.gg/inspect/spell/1266081>
163            pub(crate) const MOONLIGHT_CHAKRAM_DAMAGE: u32 = 1_266_081;
164            ///<https://wowlab.gg/inspect/spell/1266096>
165            pub(crate) const TWILIGHT_REQUIEM_DAMAGE: u32 = 1_266_096;
166        }
167        pub(crate) mod AURA {
168            ///<https://wowlab.gg/inspect/spell/1264946>
169            pub(crate) const MOONLIGHT_CHAKRAM_BUFF: u32 = 1_264_946;
170            ///<https://wowlab.gg/inspect/spell/1253836>
171            pub(crate) const SANCTIFIED_ARMAMENTS_DOT: u32 = 1_253_836;
172            ///<https://wowlab.gg/inspect/spell/1253601>
173            pub(crate) const SENTINELS_MARK: u32 = 1_253_601;
174            ///<https://wowlab.gg/inspect/spell/1253750>
175            pub(crate) const STARGAZER: u32 = 1_253_750;
176        }
177    }
178}
179static HERO_TREE_DARK_RANGER_SPELLS: &[(&str, u32)] = &[
180    ("BLACK_ARROW", 466_930),
181    ("BLACK_ARROW_DOT_SPELL", 468_572),
182    ("BLACK_ARROW_TALENT", 466_932),
183    ("BLACK_ARROW_WITHERING_FIRE", 468_037),
184    ("BLEAK_ARROWS", 467_718),
185    ("BLEAK_ARROWS_TALENT", 467_749),
186    ("BLEAK_POWDER", 467_914),
187    ("BLIGHTED_QUIVER_TALENT", 1_264_291),
188    ("CORPSECALLER_TALENT", 1_264_289),
189    ("DARK_MINION_SUMMON", 1_264_345),
190    ("PACT_OF_THE_HOLLOW_TALENT", 1_264_690),
191    ("SOUL_DRINKER_TALENT", 469_638),
192    ("THROUGH_THE_EYES_TALENT", 1_277_565),
193    ("WAILING_ARROW", 392_060),
194    ("WAILING_ARROW_DAMAGE", 392_058),
195    ("WAILING_DEAD_TALENT", 1_264_290),
196    ("WITHERING_FIRE_TALENT", 466_990),
197];
198static HERO_TREE_DARK_RANGER_AURAS: &[(&str, u32)] = &[
199    ("BLACK_ARROW_DOT", 468_572),
200    ("DEATHBLOW", 378_770),
201    ("PHANTOM_PAIN", 467_941),
202    ("WAILING_ARROW_BUFF", 459_808),
203    ("WITHERING_FIRE", 466_991),
204];
205static HERO_TREE_SENTINEL_SPELLS: &[(&str, u32)] = &[
206    ("LUNAR_STORM_DAMAGE", 1_253_733),
207    ("MOONLIGHT_CHAKRAM", 1_264_949),
208    ("MOONLIGHT_CHAKRAM_DAMAGE", 1_266_081),
209    ("TWILIGHT_REQUIEM_DAMAGE", 1_266_096),
210];
211static HERO_TREE_SENTINEL_AURAS: &[(&str, u32)] = &[
212    ("MOONLIGHT_CHAKRAM_BUFF", 1_264_946),
213    ("SANCTIFIED_ARMAMENTS_DOT", 1_253_836),
214    ("SENTINELS_MARK", 1_253_601),
215    ("STARGAZER", 1_253_750),
216];
217pub(crate) const AURA_UNNATURAL_CAUSES: LocalAuraIdx = LocalAuraIdx::new(0);
218pub(crate) const AURA_TRICK_SHOTS: LocalAuraIdx = LocalAuraIdx::new(1);
219pub(crate) const AURA_PRECISE_SHOTS: LocalAuraIdx = LocalAuraIdx::new(2);
220pub(crate) const AURA_TRUESHOT: LocalAuraIdx = LocalAuraIdx::new(3);
221pub(crate) const AURA_HEADSHOT: LocalAuraIdx = LocalAuraIdx::new(4);
222pub(crate) const AURA_SPOTTERS_MARK: LocalAuraIdx = LocalAuraIdx::new(5);
223pub(crate) const AURA_MASTER_MARKSMAN: LocalAuraIdx = LocalAuraIdx::new(6);
224pub(crate) const AURA_BLACK_ARROW: LocalAuraIdx = LocalAuraIdx::new(7);
225pub(crate) const AURA_BLACK_ARROW_DOT: LocalAuraIdx = LocalAuraIdx::new(8);
226pub(crate) const AURA_DEATHBLOW: LocalAuraIdx = LocalAuraIdx::new(9);
227pub(crate) const AURA_WITHERING_FIRE: LocalAuraIdx = LocalAuraIdx::new(10);
228pub(crate) const AURA_COUNT: usize = 11;
229const _: () = assert!(
230    AURA_COUNT == 11, "AURA index ABI: count changed -- update positional hook consumers"
231);
232pub(crate) const SPELL_AIMED_SHOT: LocalSpellIdx = LocalSpellIdx::new(0);
233pub(crate) const SPELL_RAPID_FIRE: LocalSpellIdx = LocalSpellIdx::new(1);
234pub(crate) const SPELL_ARCANE_SHOT: LocalSpellIdx = LocalSpellIdx::new(2);
235pub(crate) const SPELL_TRUESHOT: LocalSpellIdx = LocalSpellIdx::new(3);
236pub(crate) const SPELL_KILL_SHOT: LocalSpellIdx = LocalSpellIdx::new(4);
237pub(crate) const SPELL_MULTI_SHOT: LocalSpellIdx = LocalSpellIdx::new(5);
238pub(crate) const SPELL_STEADY_SHOT: LocalSpellIdx = LocalSpellIdx::new(6);
239pub(crate) const SPELL_VOLLEY: LocalSpellIdx = LocalSpellIdx::new(7);
240pub(crate) const SPELL_RAPID_FIRE_TICK: LocalSpellIdx = LocalSpellIdx::new(8);
241pub(crate) const SPELL_COUNT: usize = 9;
242const _: () = assert!(
243    SPELL_COUNT == 9,
244    "SPELL index ABI: count changed -- update positional hook consumers"
245);
246pub(crate) mod EFFECT {
247    ///<https://wowlab.gg/inspect/spell/193468>
248    pub(crate) const MASTERY_ABILITY_DAMAGE: (u32, u8) = (193_468, 2);
249    ///<https://wowlab.gg/inspect/spell/466930>
250    pub(crate) const BLACK_ARROW_DAMAGE: (u32, u8) = (466_930, 1);
251    ///<https://wowlab.gg/inspect/spell/466930>
252    pub(crate) const BLACK_ARROW_LOWER_PCT: (u32, u8) = (466_930, 2);
253    ///<https://wowlab.gg/inspect/spell/466930>
254    pub(crate) const BLACK_ARROW_UPPER_PCT: (u32, u8) = (466_930, 3);
255    ///<https://wowlab.gg/inspect/spell/53351>
256    pub(crate) const KILL_SHOT_DAMAGE: (u32, u8) = (53351, 1);
257    ///<https://wowlab.gg/inspect/spell/53351>
258    pub(crate) const KILL_SHOT_THRESHOLD: (u32, u8) = (53351, 2);
259    ///<https://wowlab.gg/inspect/spell/1264291>
260    pub(crate) const BLIGHTED_QUIVER_EXTRA: (u32, u8) = (1_264_291, 7);
261    ///<https://wowlab.gg/inspect/spell/468037>
262    pub(crate) const WITHERING_FIRE_ARROW: (u32, u8) = (468_037, 1);
263    ///<https://wowlab.gg/inspect/spell/466990>
264    pub(crate) const WITHERING_FIRE_COUNT: (u32, u8) = (466_990, 3);
265    ///<https://wowlab.gg/inspect/spell/343248>
266    pub(crate) const DEATHBLOW_AIMED_PCT: (u32, u8) = (343_248, 1);
267    ///<https://wowlab.gg/inspect/spell/343248>
268    pub(crate) const DEATHBLOW_RF_PCT: (u32, u8) = (343_248, 2);
269    ///<https://wowlab.gg/inspect/spell/469638>
270    pub(crate) const SOUL_DRINKER_AIMED_PCT: (u32, u8) = (469_638, 3);
271    ///<https://wowlab.gg/inspect/spell/469638>
272    pub(crate) const SOUL_DRINKER_RF_PCT: (u32, u8) = (469_638, 4);
273    ///<https://wowlab.gg/inspect/spell/185358>
274    pub(crate) const ARCANE_SHOT_DAMAGE: (u32, u8) = (185_358, 1);
275    ///<https://wowlab.gg/inspect/spell/1264364>
276    pub(crate) const DARK_MINION_BLIGHTED_ARROW_DAMAGE: (u32, u8) = (1_264_364, 1);
277    ///<https://wowlab.gg/inspect/spell/1264357>
278    pub(crate) const DARK_MINION_SHOOT_DAMAGE: (u32, u8) = (1_264_357, 1);
279    ///<https://wowlab.gg/inspect/spell/378767>
280    pub(crate) const FOCUSED_AIM_CDR_MS: (u32, u8) = (378_767, 1);
281    ///<https://wowlab.gg/inspect/spell/470943>
282    pub(crate) const FEATHERED_FRENZY_PCT: (u32, u8) = (470_943, 1);
283    ///<https://wowlab.gg/inspect/spell/1219616>
284    pub(crate) const SPOTTERS_MARK_CHANCE: (u32, u8) = (1_219_616, 1);
285    ///<https://wowlab.gg/inspect/spell/466872>
286    pub(crate) const SPOTTERS_MARK_PCT: (u32, u8) = (466_872, 1);
287    ///<https://wowlab.gg/inspect/spell/19434>
288    pub(crate) const AIMED_SHOT_DAMAGE: (u32, u8) = (19434, 1);
289    ///<https://wowlab.gg/inspect/spell/473523>
290    pub(crate) const WINDRUNNER_QUIVER_PCT: (u32, u8) = (473_523, 3);
291    ///<https://wowlab.gg/inspect/spell/260309>
292    pub(crate) const MASTER_MARKSMAN_PCT: (u32, u8) = (260_309, 1);
293}
294static REPORTED_SPELLS: &[(&str, u32)] = &[
295    ("blighted_arrow", 1_264_364),
296    ("shoot", 1_264_357),
297];
298static DECLARED_SPELL_IDS: &[u32] = &[
299    19434, 257_044, 185_358, 288_613, 53351, 257_620, 56641, 260_243, 257_045, 459_529,
300    257_622, 260_242, 288_613, 1_277_558, 466_872, 269_576, 466_932, 468_572, 378_770,
301    466_991, 75, 19434, 53351, 56641, 77443, 185_358, 193_468, 257_044, 257_045, 260_309,
302    263_585, 269_576, 288_613, 343_248, 378_767, 466_872, 466_930, 466_990, 468_037,
303    469_638, 470_943, 473_523, 1_219_616, 1_264_291, 1_264_357, 1_264_364, 1_264_364,
304    1_264_357, 466_930, 468_572, 466_932, 468_037, 467_718, 467_749, 467_914, 1_264_291,
305    1_264_289, 1_264_345, 1_264_690, 469_638, 1_277_565, 392_060, 392_058, 1_264_290,
306    466_990, 468_572, 378_770, 467_941, 459_808, 466_991, 1_253_733, 1_264_949,
307    1_266_081, 1_266_096, 1_264_946, 1_253_836, 1_253_601, 1_253_750,
308];
309static DECLARED_AURA_IDS: &[u32] = &[
310    459_529, 257_622, 260_242, 288_613, 1_277_558, 466_872, 269_576, 466_932, 468_572,
311    378_770, 466_991, 468_572, 378_770, 467_941, 459_808, 466_991, 1_264_946, 1_253_836,
312    1_253_601, 1_253_750,
313];
314static TALENTS: &[(&str, u32)] = &[
315    ("BLACK_ARROW", TALENT::BLACK_ARROW),
316    ("BLEAK_ARROWS", TALENT::BLEAK_ARROWS),
317    ("BLIGHTED_QUIVER", TALENT::BLIGHTED_QUIVER),
318    ("DEATHBLOW", TALENT::DEATHBLOW),
319    ("FEATHERED_FRENZY", TALENT::FEATHERED_FRENZY),
320    ("FOCUSED_AIM", TALENT::FOCUSED_AIM),
321    ("HEADSHOT", TALENT::HEADSHOT),
322    ("KILL_SHOT_TALENT", TALENT::KILL_SHOT_TALENT),
323    ("LONE_WOLF", TALENT::LONE_WOLF),
324    ("MASTER_MARKSMAN", TALENT::MASTER_MARKSMAN),
325    ("NO_SCOPE", TALENT::NO_SCOPE),
326    ("PRECISE_SHOTS", TALENT::PRECISE_SHOTS),
327    ("SOUL_DRINKER", TALENT::SOUL_DRINKER),
328    ("THROUGH_THE_EYES", TALENT::THROUGH_THE_EYES),
329    ("UNLOAD", TALENT::UNLOAD),
330    ("UNNATURAL_CAUSES", TALENT::UNNATURAL_CAUSES),
331    ("VOLLEY", TALENT::VOLLEY),
332    ("WINDRUNNER_QUIVER", TALENT::WINDRUNNER_QUIVER),
333    ("WITHERING_FIRE", TALENT::WITHERING_FIRE),
334];
335fn aura_unnatural_causes(
336    a: AuraDefinitionDraft,
337    data: &ResolvedGameData,
338) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
339    Ok(
340        a
341            .on_target()
342            .apply_base_from_data(data, 459_529)?
343            .max_stacks(
344                data
345                    .require_aura_max_stacks(
346                        wowlab_types::sim::SpellIdx::from_raw(459_529),
347                    )?,
348            ),
349    )
350}
351fn aura_trick_shots(
352    a: AuraDefinitionDraft,
353    data: &ResolvedGameData,
354) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
355    Ok(
356        a
357            .on_player()
358            .apply_base_from_data(data, 257_622)?
359            .max_stacks(
360                data
361                    .require_aura_max_stacks(
362                        wowlab_types::sim::SpellIdx::from_raw(257_622),
363                    )?,
364            ),
365    )
366}
367fn aura_precise_shots(
368    a: AuraDefinitionDraft,
369    data: &ResolvedGameData,
370) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
371    Ok(
372        a
373            .on_player()
374            .apply_base_from_data(data, 260_242)?
375            .max_stacks(
376                data
377                    .require_aura_max_stacks(
378                        wowlab_types::sim::SpellIdx::from_raw(260_242),
379                    )?,
380            ),
381    )
382}
383fn aura_trueshot(
384    a: AuraDefinitionDraft,
385    data: &ResolvedGameData,
386) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
387    Ok(
388        a
389            .on_player()
390            .apply_base_from_data(data, 288_613)?
391            .max_stacks(
392                data
393                    .require_aura_max_stacks(
394                        wowlab_types::sim::SpellIdx::from_raw(288_613),
395                    )?,
396            ),
397    )
398}
399fn aura_headshot(
400    a: AuraDefinitionDraft,
401    data: &ResolvedGameData,
402) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
403    Ok(
404        a
405            .on_target()
406            .apply_base_from_data(data, 1_277_558)?
407            .max_stacks(
408                data
409                    .require_aura_max_stacks(
410                        wowlab_types::sim::SpellIdx::from_raw(1_277_558),
411                    )?,
412            ),
413    )
414}
415fn aura_spotters_mark(
416    a: AuraDefinitionDraft,
417    data: &ResolvedGameData,
418) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
419    Ok(
420        a
421            .on_target()
422            .apply_base_from_data(data, 466_872)?
423            .max_stacks(
424                data
425                    .require_aura_max_stacks(
426                        wowlab_types::sim::SpellIdx::from_raw(466_872),
427                    )?,
428            ),
429    )
430}
431fn aura_master_marksman(
432    a: AuraDefinitionDraft,
433    data: &ResolvedGameData,
434) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
435    a.on_target()
436        .apply_base_from_data(data, 269_576)?
437        .max_stacks(
438            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(269_576))?,
439        )
440        .no_pandemic()
441        .periodic_residual_damage(
442            wowlab_engine_combat::validated_milliseconds(
443                data.period(wowlab_types::sim::SpellIdx::from_raw(269_576), 1),
444                269_576,
445                "periodic_residual_damage.tick_ms",
446            )?,
447        )
448        .apply_periodic_behavior_from_data(data, 269_576)
449}
450fn aura_black_arrow(
451    a: AuraDefinitionDraft,
452    data: &ResolvedGameData,
453) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
454    Ok(
455        a
456            .on_player()
457            .apply_base_from_data(data, 466_932)?
458            .max_stacks(
459                data
460                    .require_aura_max_stacks(
461                        wowlab_types::sim::SpellIdx::from_raw(466_932),
462                    )?,
463            ),
464    )
465}
466fn aura_black_arrow_dot(
467    a: AuraDefinitionDraft,
468    data: &ResolvedGameData,
469) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
470    Ok(
471        a
472            .on_target()
473            .apply_base_from_data(data, 468_572)?
474            .max_stacks(
475                data
476                    .require_aura_max_stacks(
477                        wowlab_types::sim::SpellIdx::from_raw(468_572),
478                    )?,
479            )
480            .unhasted_periodic(),
481    )
482}
483fn aura_deathblow(
484    a: AuraDefinitionDraft,
485    data: &ResolvedGameData,
486) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
487    Ok(
488        a
489            .on_player()
490            .apply_base_from_data(data, 378_770)?
491            .max_stacks(
492                data
493                    .require_aura_max_stacks(
494                        wowlab_types::sim::SpellIdx::from_raw(378_770),
495                    )?,
496            ),
497    )
498}
499fn aura_withering_fire(
500    a: AuraDefinitionDraft,
501    data: &ResolvedGameData,
502) -> Result<AuraDefinitionDraft, wowlab_engine_combat::BuilderError> {
503    a.on_player()
504        .duration_ms(
505            wowlab_engine_combat::validated_milliseconds(
506                f64::from(
507                    data
508                        .require_aura_duration_ms(
509                            wowlab_types::sim::SpellIdx::from_raw(288_613),
510                        )?,
511                ),
512                466_991,
513                "aura.duration_ms",
514            )?,
515        )
516        .apply_periodic_effect_from_data(data, 466_991)?
517        .apply_duration_behavior_from_data(data, 288_613)?
518        .apply_timing_modifiers_from_data(data, 466_991)?
519        .max_stacks(
520            data.require_aura_max_stacks(wowlab_types::sim::SpellIdx::from_raw(466_991))?,
521        )
522        .apply_periodic_behavior_from_data(data, 288_613)
523}
524fn spell_aimed_shot(
525    s: SpellDefinitionDraft,
526    data: &ResolvedGameData,
527) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
528    Ok(
529        s
530            .apply_base_from_data(data, 19434)?
531            .damage_flat(0.0)
532            .apply_aoe_from_data(data)
533            .on_cast(crate::hooks::marksmanship_hunter::aimed_shot_hook),
534    )
535}
536fn spell_rapid_fire(
537    s: SpellDefinitionDraft,
538    data: &ResolvedGameData,
539) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
540    Ok(
541        s
542            .apply_base_from_data(data, 257_044)?
543            .apply_aoe_from_data(data)
544            .channel(
545                wowlab_engine_combat::validated_channel_tick_count(
546                    data.base_points(wowlab_types::sim::SpellIdx::from_raw(257_044), 1),
547                    257_044,
548                    "channel.tick_count",
549                )?,
550            )
551            .channel_tick_direct_damage()
552            .channel_tick_timing(
553                wowlab_engine_combat::validated_milliseconds(
554                    data.period(wowlab_types::sim::SpellIdx::from_raw(257_044), 2),
555                    257_044,
556                    "channel.tick_interval_ms",
557                )?,
558                true,
559            )
560            .channel_tick_damage_ap_from_data(
561                wowlab_engine_domain::dbc::EffectLookup::new(
562                    data,
563                    wowlab_types::sim::EffectRef::new(
564                        wowlab_types::sim::SpellIdx::from_raw(257_045),
565                        1,
566                    ),
567                ),
568            )?
569            .channel_tick_gain(
570                data.base_points(wowlab_types::sim::SpellIdx::from_raw(263_585), 1),
571            )
572            .on_channel_tick(crate::hooks::marksmanship_hunter::rapid_fire_tick_hook)
573            .on_cast(crate::hooks::marksmanship_hunter::rapid_fire_hook),
574    )
575}
576fn spell_arcane_shot(
577    s: SpellDefinitionDraft,
578    data: &ResolvedGameData,
579) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
580    Ok(
581        s
582            .apply_base_from_data(data, 185_358)?
583            .damage_flat(0.0)
584            .apply_aoe_from_data(data)
585            .on_cast(crate::hooks::marksmanship_hunter::arcane_shot_hook),
586    )
587}
588fn spell_trueshot(
589    s: SpellDefinitionDraft,
590    data: &ResolvedGameData,
591) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
592    Ok(
593        s
594            .apply_base_from_data(data, 288_613)?
595            .applies_inferred_aura(AURA_TRUESHOT, 288_613)
596            .apply_aoe_from_data(data)
597            .on_cast(crate::hooks::marksmanship_hunter::trueshot_hook),
598    )
599}
600fn spell_kill_shot(
601    s: SpellDefinitionDraft,
602    data: &ResolvedGameData,
603) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
604    Ok(
605        s
606            .apply_base_from_data(data, 53351)?
607            .damage_flat(0.0)
608            .apply_aoe_from_data(data)
609            .on_cast(crate::hooks::marksmanship_hunter::kill_shot_hook)
610            .cost_free_when_aura(378_770),
611    )
612}
613fn spell_multi_shot(
614    s: SpellDefinitionDraft,
615    data: &ResolvedGameData,
616) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
617    Ok(s.apply_base_from_data(data, 257_620)?.apply_aoe_from_data(data))
618}
619fn spell_steady_shot(
620    s: SpellDefinitionDraft,
621    data: &ResolvedGameData,
622) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
623    Ok(
624        s
625            .apply_base_from_data(data, 56641)?
626            .gain(data.base_points(wowlab_types::sim::SpellIdx::from_raw(77443), 1))
627            .reduces_cd(
628                SPELL_AIMED_SHOT,
629                wowlab_engine_combat::validated_milliseconds(
630                    data.base_points(wowlab_types::sim::SpellIdx::from_raw(56641), 2),
631                    56641,
632                    "spell.reduces_cd.amount_ms",
633                )?,
634            )
635            .apply_aoe_from_data(data),
636    )
637}
638fn spell_volley(
639    s: SpellDefinitionDraft,
640    data: &ResolvedGameData,
641) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
642    Ok(s.apply_base_from_data(data, 260_243)?.apply_aoe_from_data(data))
643}
644fn spell_rapid_fire_tick(
645    s: SpellDefinitionDraft,
646    data: &ResolvedGameData,
647) -> Result<SpellDefinitionDraft, wowlab_engine_combat::BuilderError> {
648    Ok(s.apply_base_from_data(data, 257_045)?.damage_flat(0.0).apply_aoe_from_data(data))
649}
650pub(crate) fn build_combat_system(
651    params: &wowlab_engine_ports::HandlerParams<'_>,
652) -> Result<BuiltCombatSystem, wowlab_engine_ports::EngineError> {
653    let builder = BuiltCombatSystem::builder(params.stats.clone())
654        .spec_id(SpecId::Marksmanship)
655        .hero_talent_trees(DECLARED_METADATA.hero_talent_trees)
656        .mastery_spell(193_468)
657        .mastery_hook(crate::hooks::marksmanship_hunter::mastery)
658        .resource(
659            "focus",
660            params
661                .game_data
662                .power_max(2)
663                .ok_or_else(|| {
664                    wowlab_engine_ports::EngineError::spec_construction(
665                        "missing power-type power_max for type_id 2",
666                    )
667                })?,
668            params
669                .game_data
670                .power_regen_for_max(
671                    2,
672                    params
673                        .game_data
674                        .power_max(2)
675                        .ok_or_else(|| {
676                            wowlab_engine_ports::EngineError::spec_construction(
677                                "missing power-type power_max for type_id 2",
678                            )
679                        })?,
680                )
681                .ok_or_else(|| {
682                    wowlab_engine_ports::EngineError::spec_construction(
683                        "missing power-type power_regen_for_max for type_id 2",
684                    )
685                })?,
686        )
687        .resource_type_id(2)
688        .resource_start(
689            params
690                .game_data
691                .power_default(2)
692                .ok_or_else(|| {
693                    wowlab_engine_ports::EngineError::spec_construction(
694                        "missing power-type power_default for type_id 2",
695                    )
696                })?,
697        )
698        .aura(
699            "unnatural_causes",
700            AURA::UNNATURAL_CAUSES,
701            |a| aura_unnatural_causes(a, &params.game_data),
702        )
703        .aura(
704            "trick_shots",
705            AURA::TRICK_SHOTS,
706            |a| aura_trick_shots(a, &params.game_data),
707        )
708        .aura(
709            "precise_shots",
710            AURA::PRECISE_SHOTS,
711            |a| aura_precise_shots(a, &params.game_data),
712        )
713        .aura("trueshot", AURA::TRUESHOT, |a| aura_trueshot(a, &params.game_data))
714        .aura("headshot", AURA::HEADSHOT, |a| aura_headshot(a, &params.game_data))
715        .aura(
716            "spotters_mark",
717            AURA::SPOTTERS_MARK,
718            |a| aura_spotters_mark(a, &params.game_data),
719        )
720        .aura(
721            "master_marksman",
722            AURA::MASTER_MARKSMAN,
723            |a| aura_master_marksman(a, &params.game_data),
724        )
725        .aura(
726            "black_arrow",
727            AURA::BLACK_ARROW,
728            |a| aura_black_arrow(a, &params.game_data),
729        )
730        .aura(
731            "black_arrow_dot",
732            AURA::BLACK_ARROW_DOT,
733            |a| aura_black_arrow_dot(a, &params.game_data),
734        )
735        .aura("deathblow", AURA::DEATHBLOW, |a| aura_deathblow(a, &params.game_data))
736        .aura(
737            "withering_fire",
738            AURA::WITHERING_FIRE,
739            |a| aura_withering_fire(a, &params.game_data),
740        )
741        .spell(
742            "aimed_shot",
743            SPELL::AIMED_SHOT,
744            |s| spell_aimed_shot(s, &params.game_data),
745        )
746        .spell(
747            "rapid_fire",
748            SPELL::RAPID_FIRE,
749            |s| spell_rapid_fire(s, &params.game_data),
750        )
751        .spell(
752            "arcane_shot",
753            SPELL::ARCANE_SHOT,
754            |s| spell_arcane_shot(s, &params.game_data),
755        )
756        .spell("trueshot", SPELL::TRUESHOT, |s| spell_trueshot(s, &params.game_data))
757        .spell("kill_shot", SPELL::KILL_SHOT, |s| spell_kill_shot(s, &params.game_data))
758        .spell(
759            "multi_shot",
760            SPELL::MULTI_SHOT,
761            |s| spell_multi_shot(s, &params.game_data),
762        )
763        .spell(
764            "steady_shot",
765            SPELL::STEADY_SHOT,
766            |s| spell_steady_shot(s, &params.game_data),
767        )
768        .spell("volley", SPELL::VOLLEY, |s| spell_volley(s, &params.game_data))
769        .spell(
770            "rapid_fire_tick",
771            SPELL::RAPID_FIRE_TICK,
772            |s| spell_rapid_fire_tick(s, &params.game_data),
773        )
774        .auto_attack(|a| {
775            a.spell_id(75).swing_ms(3000).apply_base_from_data(&params.game_data)
776        })
777        .game_data(params.game_data.clone())
778        .talent_spell_ids(TALENTS)
779        .talent_selections(params.talent_selections)
780        .talent_companion_aura(TALENT::BLACK_ARROW, AURA_BLACK_ARROW)
781        .talent_companion_aura(TALENT::UNNATURAL_CAUSES, AURA_UNNATURAL_CAUSES)
782        .set_bonus_auras(params.set_bonus_auras)
783        .encounter(params.encounter.clone());
784    let builder = crate::generated::items::register_equipped(
785        builder,
786        &params.game_data,
787        params.equipped_items,
788    )?;
789
790    builder
791        .build(params.rotation)
792        .map_err(wowlab_engine_ports::EngineError::rotation_compile)
793}
794fn new_handler(
795    params: wowlab_engine_ports::HandlerParams<'_>,
796) -> Result<Box<dyn SpecHandler>, wowlab_engine_ports::EngineError> {
797    let handler = crate::composition::compose_handler(
798        build_combat_system,
799        &params,
800        crate::hooks::marksmanship_hunter::MarksmanshipHandler::try_new,
801    )?;
802
803    Ok(Box::new(handler))
804}
805static DECLARED_METADATA: DeclaredSpecMetadata = DeclaredSpecMetadata {
806    primary_resource: ResourceType::Focus,
807    secondary_resource: None,
808    spell_ids: DECLARED_SPELL_IDS,
809    aura_ids: DECLARED_AURA_IDS,
810    server_proc_entries: &[
811        DeclaredServerProcEntry {
812            spell_id: 260_242,
813            attributes: ProcAttributes::REQUIRE_SPELL_MODIFIER.bits()
814                | ProcAttributes::USE_STACKS_FOR_CHARGES.bits(),
815        },
816    ],
817    talents: TALENTS,
818    rotation_field_schema: &[],
819    metrics_plugin_id: None,
820    hero_talent_trees: &[
821        HeroTalentTreeDesc {
822            name: "Dark Ranger",
823            spells: HERO_TREE_DARK_RANGER_SPELLS,
824            auras: HERO_TREE_DARK_RANGER_AURAS,
825        },
826        HeroTalentTreeDesc {
827            name: "Sentinel",
828            spells: HERO_TREE_SENTINEL_SPELLS,
829            auras: HERO_TREE_SENTINEL_AURAS,
830        },
831    ],
832    reported_spells: REPORTED_SPELLS,
833    masked_passive_effects: &[],
834    passive_effect_overrides: &[],
835};
836pub(super) const SPEC_DESCRIPTOR: SpecDescriptor = SpecDescriptor {
837    spec_id: SpecId::Marksmanship,
838    display_name: "Marksmanship Hunter",
839    metadata: DECLARED_METADATA,
840    handler_factory: new_handler,
841};
842wowlab_engine_combat::smoke_test!(build_combat_system);