Skip to main content

wowlab_engine_content/hooks/assassination_rogue/
poisons.rs

1use wowlab_engine_combat::AuraOps as _;
2use wowlab_engine_combat::DamageOps as _;
3use wowlab_engine_combat::ResourceOps as _;
4use wowlab_engine_combat::{DamageFlags, HookCtx};
5use wowlab_engine_rng::proc_chance;
6use wowlab_types::constants::HUNDRED;
7
8use crate::generated::specs::assassination_rogue::{
9    AURA_AMPLIFYING_POISON_DEBUFF, AURA_DEADLY_POISON_DOT, AURA_DEATHMARK, AURA_ENVENOM,
10    AURA_KINGSBANE, AURA_KINGSBANE_RAMP, AURA_WOUND_POISON,
11};
12
13use super::config::sin_config;
14
15pub(super) fn proc_poisons(ctx: &mut HookCtx<'_>) {
16    let cfg = sin_config(ctx);
17    let envenom_bonus = if ctx.is_aura_active(AURA_ENVENOM) {
18        cfg.envenom_poison_bonus
19    } else {
20        0.0
21    };
22    let deadly_chance = (ctx.action_proc_chance(
23        crate::generated::specs::assassination_rogue::DAMAGE_AURA::DEADLY_POISON,
24    ) + envenom_bonus)
25        .clamp(0.0, 1.0);
26
27    if cfg.has_deadly_poison && proc_chance(ctx.rng(), deadly_chance) {
28        deal_deadly_poison(ctx);
29    }
30
31    let amplifying_chance = (ctx.action_proc_chance(
32        crate::generated::specs::assassination_rogue::DAMAGE_AURA::AMPLIFYING_POISON,
33    ) + envenom_bonus)
34        .clamp(0.0, 1.0);
35
36    if cfg.has_amplifying_poison && proc_chance(ctx.rng(), amplifying_chance) {
37        deal_amplifying_poison(ctx);
38    }
39
40    if ctx.is_aura_active(AURA_WOUND_POISON) {
41        let wound_chance = (ctx.action_proc_chance(
42            crate::generated::specs::assassination_rogue::DAMAGE_AURA::WOUND_POISON,
43        ) + envenom_bonus)
44            .clamp(0.0, 1.0);
45
46        if proc_chance(ctx.rng(), wound_chance) {
47            deal_wound_poison(ctx);
48        }
49    }
50}
51
52// Deathmark duplicates lethal-poison triggers while its DoT is active.
53const DEATHMARK_LETHAL_EXECUTIONS: u32 = 2;
54const MID2_WOUND_POISON_EXECUTIONS: u32 = 2;
55
56fn lethal_executions(ctx: &HookCtx<'_>) -> u32 {
57    if ctx.is_aura_active(AURA_DEATHMARK) {
58        DEATHMARK_LETHAL_EXECUTIONS
59    } else {
60        1
61    }
62}
63
64fn ramp_kingsbane(ctx: &mut HookCtx<'_>) {
65    if ctx.is_aura_active(AURA_KINGSBANE) {
66        ctx.apply_aura(AURA_KINGSBANE_RAMP);
67    }
68}
69
70pub(super) fn deal_deadly_poison(ctx: &mut HookCtx<'_>) {
71    for _ in 0..lethal_executions(ctx) {
72        if ctx.is_aura_active(AURA_DEADLY_POISON_DOT) {
73            let coef = ctx.effect_ap_coefficient(crate::generated::specs::assassination_rogue::DAMAGE_EFFECT::DEADLY_POISON_INSTANT_DMG);
74
75            ctx.deal_damage_ap(
76                crate::generated::specs::assassination_rogue::DAMAGE_SPELL::DEADLY_POISON_INSTANT,
77                coef,
78                DamageFlags::empty(),
79            );
80            dashing_scoundrel(ctx);
81        }
82
83        ctx.apply_aura(AURA_DEADLY_POISON_DOT);
84        ramp_kingsbane(ctx);
85    }
86}
87
88pub(super) fn deal_amplifying_poison(ctx: &mut HookCtx<'_>) {
89    let coef = ctx.effect_ap_coefficient(
90        crate::generated::specs::assassination_rogue::DAMAGE_EFFECT::AMPLIFYING_POISON_DMG,
91    );
92
93    for _ in 0..lethal_executions(ctx) {
94        ctx.deal_damage_ap(
95            crate::generated::specs::assassination_rogue::DAMAGE_EFFECT::AMPLIFYING_POISON_DMG
96                .action(),
97            coef,
98            DamageFlags::empty(),
99        );
100        ctx.apply_aura(AURA_AMPLIFYING_POISON_DEBUFF);
101        ramp_kingsbane(ctx);
102        dashing_scoundrel(ctx);
103    }
104}
105
106fn deal_wound_poison(ctx: &mut HookCtx<'_>) {
107    let cfg = sin_config(ctx);
108    let tier_executions = if cfg.mid2_4pc {
109        MID2_WOUND_POISON_EXECUTIONS
110    } else {
111        1
112    };
113    let coefficient = ctx.effect_ap_coefficient(
114        crate::generated::specs::assassination_rogue::DAMAGE_EFFECT::WOUND_POISON_DAMAGE,
115    );
116
117    for _ in 0..lethal_executions(ctx) * tier_executions {
118        ctx.deal_damage_ap(
119            crate::generated::specs::assassination_rogue::DAMAGE_REPORTED::WOUND_POISON_DAMAGE,
120            coefficient,
121            DamageFlags::empty(),
122        );
123        ramp_kingsbane(ctx);
124        dashing_scoundrel(ctx);
125    }
126}
127
128// Hook poison crits use sheet critical strike chance because hit results are unavailable.
129fn dashing_scoundrel(ctx: &mut HookCtx<'_>) {
130    let cfg = sin_config(ctx);
131
132    if cfg.dashing_scoundrel_energy <= 0.0 || !ctx.is_aura_active(AURA_ENVENOM) {
133        return;
134    }
135
136    let crit = ctx.buf().player().crit / HUNDRED;
137
138    if proc_chance(ctx.rng(), crit) {
139        ctx.gain_resource(cfg.dashing_scoundrel_energy);
140    }
141}
142
143// Seal Fate uses sheet critical strike chance because hit results are unavailable.
144pub(super) fn seal_fate(ctx: &mut HookCtx<'_>) {
145    let cfg = sin_config(ctx);
146
147    if cfg.seal_fate_chance <= 0.0 {
148        return;
149    }
150
151    let crit = ctx.buf().player().crit / HUNDRED;
152
153    if !proc_chance(ctx.rng(), crit * cfg.seal_fate_chance) {
154        return;
155    }
156
157    ctx.gain_secondary_resource(cfg.seal_fate_cp);
158
159    if cfg.deal_fate_cp > 0.0 {
160        ctx.gain_secondary_resource(cfg.deal_fate_cp);
161    }
162}