Skip to main content

wowlab_engine_content/hooks/subtlety_rogue/
trickster.rs

1use wowlab_engine_combat::DamageOps as _;
2use wowlab_engine_combat::AuraOps as _;
3use wowlab_engine_combat::{DamageFlags, HookCtx};
4use wowlab_engine_rng::proc_chance;
5
6use crate::generated::specs::subtlety_rogue::{
7    AURA_COUP_DE_GRACE, AURA_DISORIENTING_STRIKES, AURA_ESCALATING_BLADE, AURA_FAZED,
8    AURA_FLAWLESS_FORM, AURA_UNSEEN_BLADE_CD,
9};
10
11use super::config::SubtletyConfig;
12
13const ESCALATING_BLADE_MAX: i32 = 4;
14
15/// Unseen Blade proc off Backstab/Shadowstrike: once per 20s window, bypassed by Disorienting Strikes charges.
16pub(super) fn trigger_unseen_blade(
17    ctx: &mut HookCtx<'_>,
18    cfg: &SubtletyConfig,
19) {
20    if !cfg.unseen_blade {
21        return;
22    }
23
24    let disoriented = ctx.aura_stacks(AURA_DISORIENTING_STRIKES);
25
26    if ctx.is_aura_active(AURA_UNSEEN_BLADE_CD) && disoriented == 0 {
27        return;
28    }
29
30    deal_unseen_blade(ctx, cfg);
31
32    if cfg.flashing_steel_chance > 0.0 && proc_chance(ctx.rng(), cfg.flashing_steel_chance) {
33        deal_unseen_blade(ctx, cfg);
34    }
35
36    if disoriented > 0 {
37        ctx.consume_aura_stack(AURA_DISORIENTING_STRIKES);
38    } else {
39        ctx.apply_aura(AURA_UNSEEN_BLADE_CD);
40    }
41}
42
43fn deal_unseen_blade(ctx: &mut HookCtx<'_>, cfg: &SubtletyConfig) {
44    ctx.deal_damage_ap(
45        crate::generated::specs::subtlety_rogue::DAMAGE_SPELL::UNSEEN_BLADE,
46        cfg.unseen_blade_coef,
47        DamageFlags::empty(),
48    );
49    ctx.apply_aura(AURA_FAZED);
50
51    if cfg.flawless_form {
52        ctx.apply_aura(AURA_FLAWLESS_FORM);
53    }
54
55    if cfg.coup_de_grace {
56        ctx.apply_aura(AURA_ESCALATING_BLADE);
57
58        if ctx.aura_stacks(AURA_ESCALATING_BLADE) >= ESCALATING_BLADE_MAX {
59            ctx.apply_aura(AURA_COUP_DE_GRACE);
60        }
61    }
62}
63
64/// Coup de Grace: empowered Eviscerate's three hits plus Shadowed-Finisher bonus hits.
65pub(super) fn deal_coup_de_grace(
66    ctx: &mut HookCtx<'_>,
67    cfg: &SubtletyConfig,
68    cp: f64,
69    fw_active: bool,
70) {
71    let cdg_cp = cp + cfg.cdg_bonus_cp;
72    let hits = [
73        (
74            crate::generated::specs::subtlety_rogue::DAMAGE_SPELL::COUP_DE_GRACE_DAMAGE_1,
75            crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_DAMAGE_1,
76        ),
77        (
78            crate::generated::specs::subtlety_rogue::DAMAGE_SPELL::COUP_DE_GRACE_DAMAGE_2,
79            crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_DAMAGE_2,
80        ),
81        (
82            crate::generated::specs::subtlety_rogue::DAMAGE_SPELL::COUP_DE_GRACE_DAMAGE_3,
83            crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_DAMAGE_3,
84        ),
85    ];
86    let bonuses = [
87        (crate::generated::specs::subtlety_rogue::DAMAGE_REPORTED::CDG_BONUS_1, crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_BONUS_1),
88        (crate::generated::specs::subtlety_rogue::DAMAGE_REPORTED::CDG_BONUS_2, crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_BONUS_2),
89        (crate::generated::specs::subtlety_rogue::DAMAGE_REPORTED::CDG_BONUS_3, crate::generated::specs::subtlety_rogue::DAMAGE_EFFECT::CDG_BONUS_3),
90    ];
91
92    for (i, (spell, eff)) in hits.into_iter().enumerate() {
93        let coef = ctx.effect_ap_coefficient(eff);
94
95        ctx.deal_damage_ap(spell, coef * cdg_cp, DamageFlags::PHYSICAL);
96
97        if fw_active && cfg.shadowed_finishers_pct > 0.0 {
98            // #t(rust_unchecked_indexing) bonuses and hits have identical lengths
99            let (bonus_id, bonus_effect) = bonuses[i];
100            let bonus_coef = ctx.effect_ap_coefficient(bonus_effect);
101
102            ctx.deal_damage_ap(
103                bonus_id,
104                bonus_coef * cfg.shadowed_finishers_pct * cdg_cp,
105                DamageFlags::empty(),
106            );
107        }
108    }
109
110    ctx.expire_aura(AURA_ESCALATING_BLADE);
111
112    if cfg.flawless_form && ctx.is_aura_active(AURA_FAZED) {
113        ctx.apply_aura_n(AURA_FLAWLESS_FORM, cfg.cdg_flawless_stacks);
114    }
115}