wowlab_engine_content/hooks/subtlety_rogue/
trickster.rs1use wowlab_engine_combat::DamageOps as _;
2use wowlab_engine_combat::AuraOps as _;
3use wowlab_engine_combat::{DamageFlags, HookCtx};
4use wowlab_engine_rng::proc_chance;
5use wowlab_types::sim::SpellIdx;
6
7use crate::generated::specs::subtlety_rogue::{
8 AURA_COUP_DE_GRACE, AURA_DISORIENTING_STRIKES, AURA_ESCALATING_BLADE, AURA_FAZED,
9 AURA_FLAWLESS_FORM, AURA_UNSEEN_BLADE_CD, EFFECT, HERO, REPORTED_SPELL,
10};
11
12use super::config::SubtletyConfig;
13
14const ESCALATING_BLADE_MAX: i32 = 4;
15
16pub(super) fn trigger_unseen_blade(
18 ctx: &mut HookCtx<'_>,
19 cfg: &SubtletyConfig,
20) {
21 if !cfg.unseen_blade {
22 return;
23 }
24
25 let disoriented = ctx.aura_stacks(AURA_DISORIENTING_STRIKES.raw());
26
27 if ctx.is_aura_active(AURA_UNSEEN_BLADE_CD.raw()) && disoriented == 0 {
28 return;
29 }
30
31 deal_unseen_blade(ctx, cfg);
32
33 if cfg.flashing_steel_chance > 0.0 && proc_chance(ctx.rng(), cfg.flashing_steel_chance) {
34 deal_unseen_blade(ctx, cfg);
35 }
36
37 if disoriented > 0 {
38 ctx.consume_aura_stack(AURA_DISORIENTING_STRIKES.raw());
39 } else {
40 ctx.apply_aura(AURA_UNSEEN_BLADE_CD.raw());
41 }
42}
43
44fn deal_unseen_blade(ctx: &mut HookCtx<'_>, cfg: &SubtletyConfig) {
45 ctx.deal_damage_ap(
46 HERO::TRICKSTER::SPELL::UNSEEN_BLADE,
47 cfg.unseen_blade_coef,
48 DamageFlags::empty(),
49 );
50 ctx.apply_aura(AURA_FAZED.raw());
51
52 if cfg.flawless_form {
53 ctx.apply_aura(AURA_FLAWLESS_FORM.raw());
54 }
55
56 if cfg.coup_de_grace {
57 ctx.apply_aura(AURA_ESCALATING_BLADE.raw());
58
59 if ctx.aura_stacks(AURA_ESCALATING_BLADE.raw()) >= ESCALATING_BLADE_MAX {
60 ctx.apply_aura(AURA_COUP_DE_GRACE.raw());
61 }
62 }
63}
64
65pub(super) fn deal_coup_de_grace(
67 ctx: &mut HookCtx<'_>,
68 cfg: &SubtletyConfig,
69 cp: f64,
70 fw_active: bool,
71) {
72 let cdg_cp = cp + cfg.cdg_bonus_cp;
73 let hits = [
74 (
75 HERO::TRICKSTER::SPELL::COUP_DE_GRACE_DAMAGE_1,
76 EFFECT::CDG_DAMAGE_1,
77 ),
78 (
79 HERO::TRICKSTER::SPELL::COUP_DE_GRACE_DAMAGE_2,
80 EFFECT::CDG_DAMAGE_2,
81 ),
82 (
83 HERO::TRICKSTER::SPELL::COUP_DE_GRACE_DAMAGE_3,
84 EFFECT::CDG_DAMAGE_3,
85 ),
86 ];
87 let bonuses = [
88 (REPORTED_SPELL::CDG_BONUS_1, EFFECT::CDG_BONUS_1),
89 (REPORTED_SPELL::CDG_BONUS_2, EFFECT::CDG_BONUS_2),
90 (REPORTED_SPELL::CDG_BONUS_3, EFFECT::CDG_BONUS_3),
91 ];
92
93 for (i, (spell, eff)) in hits.into_iter().enumerate() {
94 let coef = ctx.game_data().ap_coef(SpellIdx::from_raw(eff.0), eff.1);
95
96 ctx.deal_damage_ap(spell, coef * cdg_cp, DamageFlags::PHYSICAL);
97
98 if fw_active && cfg.shadowed_finishers_pct > 0.0 {
99 let (bonus_id, bonus_effect) = bonuses[i];
101 let bonus_coef = ctx
102 .game_data()
103 .ap_coef(SpellIdx::from_raw(bonus_effect.0), bonus_effect.1);
104
105 ctx.deal_damage_ap(
106 bonus_id,
107 bonus_coef * cfg.shadowed_finishers_pct * cdg_cp,
108 DamageFlags::empty(),
109 );
110 }
111 }
112
113 ctx.expire_aura(AURA_ESCALATING_BLADE.raw());
114
115 if cfg.flawless_form && ctx.is_aura_active(AURA_FAZED.raw()) {
116 ctx.apply_aura_n(AURA_FLAWLESS_FORM.raw(), cfg.cdg_flawless_stacks);
117 }
118}