Skip to main content

wowlab_engine_content/hooks/elemental_shaman/
elementals.rs

1use wowlab_engine_combat::DamageOps as _;
2use wowlab_engine_combat::GuardianOps as _;
3use wowlab_engine_combat::AuraOps as _;
4use wowlab_engine_combat::{DamageFlags, GuardianAbility, GuardianEvent, GuardianSpec, HookCtx};
5use wowlab_engine_domain::dbc::ResolvedGameDataEffectExt as _;
6use wowlab_types::{constants::HUNDRED};
7
8use crate::generated::specs::elemental_shaman::{
9    AURA_FIRE_ELEMENTAL, AURA_STORM_ELEMENTAL, AURA_WIND_GUST, EFFECT, SPELL,
10};
11
12pub(super) const STORM_ELEMENTAL_GUARDIAN_TAG: u32 = 262_001;
13const FIRE_ELEMENTAL_GUARDIAN_TAG: u32 = 262_002;
14const STORM_ELEMENTAL_DURATION_MS: u32 = 14_400;
15const FIRE_ELEMENTAL_DURATION_MS: u32 = 24_000;
16const PRIMAL_ELEMENTAL_OWNER_SP_MULT: f64 = 1.8;
17const STORM_ELEMENTAL_ACTION_MS: u32 = 2_000;
18const STORM_ELEMENTAL_FIRST_ACTION_MS: u32 = 500;
19const STORM_ELEMENTAL_MAX_ACTIONS: u16 = 7;
20const STORMFURY_TICKS: i32 = 4;
21const FIRE_ELEMENTAL_ACTION_MS: u32 = 2_500;
22const FIRE_ELEMENTAL_FIRST_ACTION_MS: u32 = 100;
23const FIRE_ELEMENTAL_MAX_ACTIONS: u16 = 11;
24
25fn storm_elemental_action(ctx: &mut HookCtx<'_>, event: GuardianEvent) {
26    match event.action_index {
27        0 => {
28            let coef = ctx
29                .game_data()
30                .effect_sp_coefficient(EFFECT::CALL_LIGHTNING_DAMAGE)
31                * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
32
33            ctx.deal_damage_sp(SPELL::CALL_LIGHTNING, coef, DamageFlags::PET);
34        }
35        1 => {
36            let coef = ctx
37                .game_data()
38                .effect_sp_coefficient(EFFECT::STORMFURY_DAMAGE)
39                * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
40            let charged = 1.0
41                + ctx
42                    .game_data()
43                    .effect_base_points(EFFECT::CALL_LIGHTNING_DAMAGE_BONUS)
44                    / HUNDRED;
45            let ramp = 1.0 + ctx.game_data().effect_base_points(EFFECT::STORMFURY_RAMP) / HUNDRED;
46
47            for tick in 1_i32..=STORMFURY_TICKS {
48                ctx.deal_damage_sp(
49                    SPELL::STORMFURY,
50                    coef * charged * ramp.powi(tick),
51                    DamageFlags::PET,
52                );
53            }
54        }
55        _ => {
56            let coef = ctx
57                .game_data()
58                .effect_sp_coefficient(EFFECT::WIND_GUST_DAMAGE)
59                * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
60            let charged = 1.0
61                + ctx
62                    .game_data()
63                    .effect_base_points(EFFECT::CALL_LIGHTNING_DAMAGE_BONUS)
64                    / HUNDRED;
65
66            ctx.deal_damage_sp(SPELL::WIND_GUST, coef * charged, DamageFlags::PET);
67        }
68    }
69}
70
71fn storm_elemental_demise(ctx: &mut HookCtx<'_>, _event: GuardianEvent) {
72    ctx.expire_aura(AURA_WIND_GUST.raw());
73    ctx.expire_aura(AURA_STORM_ELEMENTAL.raw());
74}
75
76fn fire_elemental_demise(ctx: &mut HookCtx<'_>, _event: GuardianEvent) {
77    ctx.expire_aura(AURA_FIRE_ELEMENTAL.raw());
78}
79
80fn fire_elemental_action(ctx: &mut HookCtx<'_>, event: GuardianEvent) {
81    if event.action_index == 0 {
82        let meteor = ctx.game_data().effect_sp_coefficient(EFFECT::METEOR_DAMAGE)
83            * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
84        let immolate = ctx
85            .game_data()
86            .effect_sp_coefficient(EFFECT::IMMOLATE_DAMAGE)
87            * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
88
89        ctx.deal_damage_sp(SPELL::METEOR, meteor, DamageFlags::PET);
90        ctx.deal_damage_sp(SPELL::IMMOLATE, immolate, DamageFlags::PET);
91    } else {
92        let blast = ctx
93            .game_data()
94            .effect_sp_coefficient(EFFECT::FIRE_BLAST_DAMAGE)
95            * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
96
97        ctx.deal_damage_sp(SPELL::FIRE_BLAST, blast, DamageFlags::PET);
98    }
99
100    let tick = ctx
101        .game_data()
102        .effect_sp_coefficient(EFFECT::IMMOLATE_PERIODIC_DAMAGE)
103        * PRIMAL_ELEMENTAL_OWNER_SP_MULT;
104
105    ctx.deal_damage_sp(SPELL::IMMOLATE, tick, DamageFlags::PET);
106}
107
108pub(super) fn summon_storm_elemental(ctx: &mut HookCtx<'_>) {
109    ctx.apply_aura(AURA_STORM_ELEMENTAL.raw());
110    let _ = ctx.summon_guardian(
111        GuardianSpec::new_inheriting_owner(
112            STORM_ELEMENTAL_GUARDIAN_TAG,
113            STORM_ELEMENTAL_DURATION_MS,
114        )
115        .ability(
116            GuardianAbility::new(STORM_ELEMENTAL_ACTION_MS, storm_elemental_action)
117                .first_action_delay(STORM_ELEMENTAL_FIRST_ACTION_MS)
118                .hasted_actions()
119                .max_actions(STORM_ELEMENTAL_MAX_ACTIONS)
120                .ends_guardian(),
121        )
122        .on_demise(storm_elemental_demise),
123    );
124}
125
126pub(super) fn summon_fire_elemental(ctx: &mut HookCtx<'_>) {
127    ctx.apply_aura(AURA_FIRE_ELEMENTAL.raw());
128    let _ = ctx.summon_guardian(
129        GuardianSpec::new_inheriting_owner(FIRE_ELEMENTAL_GUARDIAN_TAG, FIRE_ELEMENTAL_DURATION_MS)
130            .ability(
131                GuardianAbility::new(FIRE_ELEMENTAL_ACTION_MS, fire_elemental_action)
132                    .first_action_delay(FIRE_ELEMENTAL_FIRST_ACTION_MS)
133                    .hasted_actions()
134                    .max_actions(FIRE_ELEMENTAL_MAX_ACTIONS)
135                    .ends_guardian(),
136            )
137            .on_demise(fire_elemental_demise),
138    );
139}