1use wowlab_engine_domain::dbc::ResolvedGameDataEffectExt as _;
2use wowlab_types::{constants::HUNDRED, sim::SpellIdx};
3
4use crate::{
5 generated::specs::marksmanship_hunter::{EFFECT, HERO, REPORTED_SPELL, TALENT},
6 hooks::gated,
7};
8
9crate::hooks::define_spec_config! {
10pub(super) struct MarksmanshipConfig {
12 black_arrow: bool { provenance: "Dark Ranger Black Arrow talent 466932.", gate: black_arrow, source: true, transform: |value| value, },
13 ba_coef: f64 { provenance: "Black Arrow 466930 e1 AP coefficient.", gate: true, source: ap(EFFECT::BLACK_ARROW_DAMAGE), transform: |value| value, },
14 ba_lower_pct: f64 { provenance: "Black Arrow 466930 e2 lower health threshold.", gate: true, source: base(EFFECT::BLACK_ARROW_LOWER_PCT), transform: |value| value / HUNDRED, },
15 ba_upper_pct: f64 { provenance: "Black Arrow 466930 e3 upper health threshold.", gate: true, source: base(EFFECT::BLACK_ARROW_UPPER_PCT), transform: |value| value / HUNDRED, },
16 ks_coef: f64 { provenance: "Kill Shot 53351 e1 AP coefficient.", gate: true, source: ap(EFFECT::KILL_SHOT_DAMAGE), transform: |value| value, },
17 ks_threshold: f64 { provenance: "Kill Shot 53351 e2 execute threshold.", gate: true, source: base(EFFECT::KILL_SHOT_THRESHOLD), transform: |value| value / HUNDRED, },
18 kill_shot: bool { provenance: "Kill Shot talent selection.", gate: params.talent_picked(TALENT::KILL_SHOT_TALENT), source: true, transform: |value| value, },
19 deathblow: bool { provenance: "Deathblow is enabled by its talent or Black Arrow.", gate: deathblow_talent || black_arrow, source: true, transform: |value| value, },
20 aimed_deathblow_chance: f64 { provenance: "Deathblow 343248 e1 plus Soul Drinker 469638 e3.", gate: deathblow_talent, source: aimed_chance, transform: |value| value, },
21 rf_deathblow_chance: f64 { provenance: "Deathblow 343248 e2 plus Soul Drinker 469638 e4.", gate: deathblow_talent, source: rf_chance, transform: |value| value, },
22 withering_fire: bool { provenance: "Withering Fire talent 466990.", gate: params.talent_picked(HERO::DARK_RANGER::SPELL::WITHERING_FIRE_TALENT), source: true, transform: |value| value, },
23 wf_count: i32 { provenance: "Withering Fire e3 plus Blighted Quiver e7 volley count.", gate: true, source: wf_count, transform: |value| value, },
24 wf_arrow_coef: f64 { provenance: "Withering Fire arrow AP coefficient.", gate: true, source: ap(EFFECT::WITHERING_FIRE_ARROW), transform: |value| value, },
25 unload: bool { provenance: "Unload 1277548 selection.", gate: params.talent_picked(TALENT::UNLOAD), source: true, transform: |value| value, },
26 no_scope: bool { provenance: "No Scope 473385 selection.", gate: params.talent_picked(TALENT::NO_SCOPE), source: true, transform: |value| value, },
27 precise_shots: bool { provenance: "Precise Shots 260240 selection.", gate: params.talent_picked(TALENT::PRECISE_SHOTS), source: true, transform: |value| value, },
28 arcane_coef: f64 { provenance: "Arcane Shot 185358 e1 AP coefficient.", gate: true, source: ap(EFFECT::ARCANE_SHOT_DAMAGE), transform: |value| value, },
29 bleak_arrows: bool { provenance: "Bleak Arrows 467749 selection.", gate: params.talent_picked(HERO::DARK_RANGER::SPELL::BLEAK_ARROWS_TALENT), source: true, transform: |value| value, },
30 headshot: bool { provenance: "Headshot 471363 selection.", gate: params.talent_picked(TALENT::HEADSHOT), source: true, transform: |value| value, },
31 focused_aim_cdr_ms: u32 { provenance: "Focused Aim 378767 e1 cooldown reduction milliseconds.", gate: params.talent_picked(TALENT::FOCUSED_AIM), source: base(EFFECT::FOCUSED_AIM_CDR_MS), transform: wowlab_types::numeric::f64_to_u32_saturating_trunc, },
32 windrunner_quiver_chance: f64 { provenance: "Windrunner Quiver 473523 e3 retrigger chance.", gate: params.talent_picked(TALENT::WINDRUNNER_QUIVER), source: base(EFFECT::WINDRUNNER_QUIVER_PCT), transform: |value| value / HUNDRED, },
33 spotters_mark_chance: f64 { provenance: "Spotter's Mark 1219616 e1 chance.", gate: true, source: base(EFFECT::SPOTTERS_MARK_CHANCE), transform: |value| value / HUNDRED, },
34 spotters_mark_mult: f64 { provenance: "Spotter's Mark 466872 e1 Aimed Shot multiplier.", gate: true, source: base(EFFECT::SPOTTERS_MARK_PCT), transform: |value| 1.0 + value / HUNDRED, },
35 feathered_frenzy_mult: f64 { provenance: "Feathered Frenzy 470943 e1 mark-chance multiplier.", gate: params.talent_picked(TALENT::FEATHERED_FRENZY), source: base(EFFECT::FEATHERED_FRENZY_PCT), transform: |value| 1.0 + value / HUNDRED, fallback: 1.0, },
36 aimed_coef: f64 { provenance: "Aimed Shot 19434 e1 AP coefficient.", gate: true, source: ap(EFFECT::AIMED_SHOT_DAMAGE), transform: |value| value, },
37 master_marksman: bool { provenance: "Master Marksman 260309 selection.", gate: params.talent_picked(TALENT::MASTER_MARKSMAN), source: true, transform: |value| value, },
38 master_marksman_fraction: f64 { provenance: "Master Marksman banked damage fraction.", gate: true, source: base(EFFECT::MASTER_MARKSMAN_PCT), transform: |value| value / HUNDRED, },
39 corpsecaller: bool { provenance: "Corpsecaller 1264289 selection; RPPM-rolls a Dark Minion on Black Arrow `DoT` ticks (`sc_hunter.cpp:4727`).", gate: params.talent_picked(HERO::DARK_RANGER::SPELL::CORPSECALLER_TALENT), source: true, transform: |value| value, },
40 wailing_dead: bool { provenance: "Wailing Dead 1264290 selection; Trueshot summons a Dark Minion (`sc_hunter.cpp:6967`).", gate: params.talent_picked(HERO::DARK_RANGER::SPELL::WAILING_DEAD_TALENT), source: true, transform: |value| value, },
41 pact_of_the_hollow: bool { provenance: "Pact of the Hollow 1264690 selection; Aimed Shot commands every Dark Minion to fire Blighted Arrow (`sc_hunter.cpp:5682`).", gate: params.talent_picked(HERO::DARK_RANGER::SPELL::PACT_OF_THE_HOLLOW_TALENT), source: true, transform: |value| value, },
42 dark_minion_duration_ms: u32 { provenance: "Dark Minion summon 1264345 duration (`sc_hunter.cpp:4728`).", gate: true, source: dark_minion_duration_ms, transform: |value| value, },
43 dark_minion_shoot_cast_ms: u32 { provenance: "Dark Minion Shoot 1264357 cast time; the pet inherits no haste (`sc_hunter.cpp:1794`).", gate: true, source: dark_minion_shoot_cast_ms, transform: |value| value, },
44}
45accessor pub(super) fn marksmanship_config(ctx);
46register pub(super) fn derive_config(built, params) -> MarksmanshipConfig;
47prepare {
48 let data = ¶ms.game_data;
49 let base = |e: (u32, u8)| data.base_points(SpellIdx::from_raw(e.0), e.1);
50 let ap = |effect| data.effect_ap_coefficient(effect);
51
52 let black_arrow = params.talent_picked(HERO::DARK_RANGER::SPELL::BLACK_ARROW_TALENT);
53 let deathblow_talent = params.talent_picked(TALENT::DEATHBLOW);
54 let soul_drinker = params.talent_picked(HERO::DARK_RANGER::SPELL::SOUL_DRINKER_TALENT);
55
56 let (aimed_chance, rf_chance) = gated(deathblow_talent, || {
57 (
58 base(EFFECT::DEATHBLOW_AIMED_PCT) / HUNDRED
59 + gated(soul_drinker, || base(EFFECT::SOUL_DRINKER_AIMED_PCT) / HUNDRED),
60 base(EFFECT::DEATHBLOW_RF_PCT) / HUNDRED
61 + gated(soul_drinker, || base(EFFECT::SOUL_DRINKER_RF_PCT) / HUNDRED),
62 )
63 });
64
65 let wf_count = wowlab_types::numeric::f64_to_i32_saturating_trunc(base(EFFECT::WITHERING_FIRE_COUNT))
66 + gated(params.talent_picked(HERO::DARK_RANGER::SPELL::BLIGHTED_QUIVER_TALENT), || wowlab_types::numeric::f64_to_i32_saturating_trunc(base(EFFECT::BLIGHTED_QUIVER_EXTRA)));
67
68 let dark_minion_duration_ms = data
69 .aura_duration_ms(SpellIdx::from_raw(HERO::DARK_RANGER::SPELL::DARK_MINION_SUMMON))
70 .unwrap_or_default();
71 let dark_minion_shoot_cast_ms = data
72 .cast_time_ms(SpellIdx::from_raw(REPORTED_SPELL::SHOOT))
73 .unwrap_or_default();
74}
75auras {}
76finish |cfg| {
77 let _ = built;
78 cfg
79}
80}