wowlab_engine_content/hooks/elemental_shaman/
config.rs1use wowlab_engine_domain::dbc::ResolvedGameDataEffectExt as _;
2use wowlab_engine_ports::HandlerParams;
3use wowlab_types::constants::HUNDRED;
4
5use crate::{
6 generated::specs::elemental_shaman::{DAMAGE_EFFECT, EFFECT, SET_BONUS, TALENT},
7 hooks::gated,
8};
9
10use super::bugs::BUG_STORMWELL_TEMPEST_MAELSTROM;
11
12pub(super) const ELEMENTAL_BLAST_COST: f64 = 90.0;
13
14#[derive(Clone, Copy, Debug, Default)]
15pub(super) struct ElementalRuntime {
16 pub(super) stormkeeper_faded_during_ascendance: bool,
17}
18
19crate::hooks::define_spec_config! {
20 pub(super) struct ElementalConfig {
21 earthquake_ground: Option<wowlab_engine_combat::GroundEffectId> { provenance: "Finalized Earthquake ground-effect plan.", gate: !params.game_data.is_empty(), source: Some(built.register_ground_effect(wowlab_engine_combat::GroundEffectDefinition::from_driver(DAMAGE_EFFECT::EARTHQUAKE_TIMING.action(), DAMAGE_EFFECT::EARTHQUAKE_TIMING, DAMAGE_EFFECT::EARTHQUAKE_DAMAGE, DAMAGE_EFFECT::EARTHQUAKE_DAMAGE).flags(wowlab_engine_combat::DamageFlags::PERIODIC))?), transform: |value| value },
22 supercharge_chance: f64 { provenance: "Supercharge effect proc chance.", gate: params.talent_picked(TALENT::SUPERCHARGE), source: effect_fraction(EFFECT::SUPERCHARGE_CHANCE), transform: |value| value },
23 feedback_loop_chance: f64 { provenance: "Feedback Loop rank-three bonus chance.", gate: params.talent_picked(TALENT::FEEDBACK_LOOP_3), source: effect_fraction(EFFECT::FEEDBACK_LOOP_BONUS), transform: |value| value },
24 fusion_of_elements_mult: f64 { provenance: "Fusion of Elements effect damage fraction.", gate: params.talent_picked(TALENT::FUSION_OF_ELEMENTS), source: effect_fraction(EFFECT::FUSION_OF_ELEMENTS_BONUS), transform: |value| value },
25 eb_overload_mult: f64 { provenance: "Mountains Will Fall Elemental Blast overload fraction.", gate: params.talent_picked(TALENT::MOUNTAINS_WILL_FALL), source: effect_fraction(EFFECT::MOUNTAINS_WILL_FALL_BONUS), transform: |value| value },
26 aftershock_chance: f64 { provenance: "Aftershock effect refund chance.", gate: params.talent_picked(TALENT::AFTERSHOCK), source: effect_fraction(EFFECT::AFTERSHOCK_CHANCE), transform: |value| value },
27 potm_chance: f64 { provenance: "Power of the Maelstrom effect proc chance.", gate: params.talent_picked(TALENT::POWER_OF_THE_MAELSTROM), source: effect_fraction(EFFECT::POWER_OF_THE_MAELSTROM_CHANCE), transform: |value| value },
28 stormwell_tempest_maelstrom: f64 { provenance: "Live bug: Tempest applying a new Stormkeeper via Arc Discharge triggers Stormwell's Maelstrom grant.", gate: params.talent_picked(TALENT::STORMWELL) && params.talent_picked(TALENT::ARC_DISCHARGE), source: params.game_data.effect_base_points(EFFECT::STORMWELL_SK_MAELSTROM), transform: |value| value },
29 stormwell_tempest_bug: bool { provenance: "Frozen live-bug selection for Stormwell's Tempest Maelstrom grant.", gate: params.bugs.enabled(&BUG_STORMWELL_TEMPEST_MAELSTROM), source: true, transform: |value| value },
30 tempest_chance_on_blast: f64 { provenance: "Tempest and Awakening Storms per-point chances folded across Elemental Blast cost.", gate: true, source: tempest_chance_on_blast(params), transform: |value| value },
31 eb_overload: bool { provenance: "Mountains Will Fall enables Elemental Blast overloads.", gate: params.talent_picked(TALENT::MOUNTAINS_WILL_FALL), source: true, transform: |value| value },
32 master_of_the_elements: bool { provenance: "Master of the Elements enables its spender window.", gate: params.talent_picked(TALENT::MASTER_OF_THE_ELEMENTS), source: true, transform: |value| value },
33 arc_discharge: bool { provenance: "Arc Discharge enables its overload rider.", gate: params.talent_picked(TALENT::ARC_DISCHARGE), source: true, transform: |value| value },
34 unlimited_power: bool { provenance: "Unlimited Power enables haste stacking.", gate: params.talent_picked(TALENT::UNLIMITED_POWER), source: true, transform: |value| value },
35 lightning_rod_mult: f64 { provenance: "Lightning Rod effect damage fraction.", gate: params.talent_picked(TALENT::LIGHTNING_ROD), source: effect_fraction(EFFECT::LIGHTNING_ROD_PERCENT), transform: |value| value },
36 summon_storm_elemental: bool { provenance: "Fury of the Storms plus Primal Elementalist enables the primal Storm Elemental.", gate: params.talent_picked(TALENT::FURY_OF_THE_STORMS) && params.talent_picked(TALENT::PRIMAL_ELEMENTALIST), source: true, transform: |value| value },
37 summon_fire_elemental: bool { provenance: "Call of Fire plus Primal Elementalist enables the primal Fire Elemental.", gate: params.talent_picked(TALENT::CALL_OF_FIRE) && params.talent_picked(TALENT::PRIMAL_ELEMENTALIST), source: true, transform: |value| value },
38 tww3_stormbringer_2pc: bool { provenance: "The TWW3 Stormbringer two-piece grants Tempest on Ascendance.", gate: params.set_bonus_auras.contains(&SET_BONUS::TWW3_STORMBRINGER_2PC), source: true, transform: |value| value },
39 tww3_stormbringer_4pc: bool { provenance: "TWW3 Stormbringer four-piece enables its tier rider.", gate: params.set_bonus_auras.contains(&SET_BONUS::TWW3_STORMBRINGER_4PC), source: true, transform: |value| value },
40 mid2_4pc: bool { provenance: "MID2 Elemental four-piece enables Flowing Elements when Stormkeeper or Ascendance fades.", gate: params.set_bonus_auras.contains(&SET_BONUS::MID2_ELEMENTAL_4PC), source: true, transform: |value| value },
41 }
42 accessor pub(super) fn elemental_config(ctx);
43 register pub(super) fn register_elemental_config(built, params) -> Result<(), wowlab_engine_ports::EngineError>;
44 prepare {
45 let effect_fraction = |effect| params.game_data.effect_percent(effect);
46 }
47 auras {}
48 finish |cfg| {
49 built.set_spec_config(cfg);
50 built.set_spec_runtime(ElementalRuntime::default());
51 Ok(())
52 }
53}
54
55fn tempest_chance_on_blast(params: &HandlerParams<'_>) -> f64 {
56 let data = ¶ms.game_data;
57 let tempest = gated(params.talent_picked(TALENT::TEMPEST_TALENT), || {
58 data.effect_base_points(EFFECT::TEMPEST_TALENT_CHANCE) / HUNDRED / HUNDRED
59 });
60 let awakening = gated(params.talent_picked(TALENT::AWAKENING_STORMS), || {
61 data.effect_base_points(EFFECT::AWAKENING_STORMS_CHANCE) / HUNDRED / HUNDRED
62 });
63 let tempest_per_point = tempest + awakening;
64
65 if tempest_per_point > 0.0 {
66 1.0 - (1.0 - tempest_per_point).powf(ELEMENTAL_BLAST_COST)
67 } else {
68 0.0
69 }
70}