Skip to main content

wowlab_engine_combat/state/defs/
aura.rs

1use super::{
2    AuraOn, BuffEffect, CastHookFn, LocalSpellIdx, MAX_AURA_APPLICATION_EXCLUSIONS,
3    MAX_AURA_BUFF_EFFECTS, PeriodicData, SpellAuraInterruptFlags, SpellEffectRange,
4};
5use crate::state::AuraState;
6
7/// Membership of an aura in a numbered spell group and the rule governing the group.
8#[derive(Clone, Copy, Debug)]
9#[must_use]
10pub struct SpellGroup {
11    pub group_idx: u8,
12    pub rule: wowlab_types::combat::SpellGroupRule,
13}
14
15/// On-crit charge reduction for an auto-attack: roll `chance` to refund a charge of `target`.
16#[derive(Clone, Copy, Debug, PartialEq)]
17#[must_use]
18pub struct CritChargeReduction {
19    pub target: LocalSpellIdx,
20    pub chance: f64,
21}
22
23/// Per-tick stat update policy for an aura.
24#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
25#[non_exhaustive]
26pub enum DynamicTickAction {
27    #[default]
28    None,
29    Update,
30    Snapshot,
31}
32
33/// Whether an aura's periodic tick mutates its stack count.
34#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
35#[non_exhaustive]
36pub enum AuraTickBehavior {
37    #[default]
38    None,
39    Clip,
40    Refresh,
41}
42
43// docref:start auras-aura-data
44#[derive(Clone, Copy, Debug)]
45#[must_use]
46#[expect(
47    clippy::struct_excessive_bools,
48    reason = "runtime aura behavior preserves independent DBC flags"
49)]
50pub struct AuraData {
51    pub aura_id: u32,
52    pub name_idx: u16,
53    pub on: AuraOn,
54    pub propagates_to_pet: bool,
55    pub base_duration_ms: u32,
56    pub doses: u8,
57    pub max_stacks: u8,
58    pub pandemic: bool,
59    pub refresh_behavior: wowlab_types::data::RefreshBehavior,
60    pub duration_hasted: bool,
61    pub shapeshift_form: i32,
62    pub shapeshift_form_flags: i32,
63    /// `SpellShapeshiftForm.CombatRoundTime`; non-zero when the form imposes its own swing period.
64    pub shapeshift_combat_round_time_ms: u32,
65    pub effects: [Option<BuffEffect>; MAX_AURA_BUFF_EFFECTS],
66    pub periodic: Option<PeriodicData>,
67    pub spell_group: Option<SpellGroup>,
68    pub granted_aura_state: Option<AuraState>,
69    pub crowd_control: Option<wowlab_engine_domain::dbc::CrowdControlSemantic>,
70    pub is_snapshot: bool,
71    pub dynamic_tick_action: DynamicTickAction,
72    pub apply_at_max_stacks: bool,
73    pub reverse: bool,
74    pub freeze_stacks: bool,
75    pub tick_behavior: AuraTickBehavior,
76    pub tick_stack_change: u8,
77    pub async_stacks: bool,
78    pub periodic_damage_scales_with_stacks: bool,
79    pub interrupt_flags: SpellAuraInterruptFlags,
80    pub reapply_on_expire: bool,
81    pub application_excluded_auras: [u32; MAX_AURA_APPLICATION_EXCLUSIONS],
82    pub application_followup_aura_id: u32,
83    pub apply_effects: SpellEffectRange,
84    pub apply_profile_spell_id: u32,
85    pub on_consume: SpellEffectRange,
86    pub tick_effects: SpellEffectRange,
87    pub tick_profile_spell_id: u32,
88    pub expire_trigger_spell_id: u32,
89    pub expire_trigger_from_caster: bool,
90    pub on_expire: Option<CastHookFn>,
91    pub on_tick: Option<CastHookFn>,
92}
93// docref:end auras-aura-data
94
95impl AuraData {
96    /// Single-stack, non-periodic player buff carrying `effects` for `duration_ms`.
97    #[inline]
98    pub fn simple_player_buff(
99        aura_id: u32,
100        name_idx: u16,
101        duration_ms: u32,
102        effects: [Option<BuffEffect>; MAX_AURA_BUFF_EFFECTS],
103    ) -> Self {
104        Self {
105            aura_id,
106            name_idx,
107            on: AuraOn::Player,
108            propagates_to_pet: false,
109            base_duration_ms: duration_ms,
110            doses: 1,
111            max_stacks: 1,
112            pandemic: false,
113            refresh_behavior: wowlab_types::data::RefreshBehavior::Duration,
114            duration_hasted: false,
115            shapeshift_form: 0,
116            shapeshift_form_flags: 0,
117            shapeshift_combat_round_time_ms: 0,
118            effects,
119            periodic: None,
120            spell_group: None,
121            granted_aura_state: None,
122            crowd_control: None,
123            is_snapshot: false,
124            dynamic_tick_action: DynamicTickAction::None,
125            apply_at_max_stacks: false,
126            reverse: false,
127            freeze_stacks: false,
128            tick_behavior: AuraTickBehavior::None,
129            tick_stack_change: 1,
130            async_stacks: false,
131            periodic_damage_scales_with_stacks: false,
132            interrupt_flags: SpellAuraInterruptFlags::empty(),
133            reapply_on_expire: false,
134            application_excluded_auras: [0; MAX_AURA_APPLICATION_EXCLUSIONS],
135            application_followup_aura_id: 0,
136            apply_effects: SpellEffectRange::default(),
137            apply_profile_spell_id: 0,
138            on_consume: SpellEffectRange::default(),
139            tick_effects: SpellEffectRange::default(),
140            tick_profile_spell_id: 0,
141            expire_trigger_spell_id: 0,
142            expire_trigger_from_caster: false,
143            on_expire: None,
144            on_tick: None,
145        }
146    }
147}