Skip to main content

wowlab_engine_gamedata/game_data/
props.rs

1//! Spell/aura/power descriptor types resolved from game data.
2
3/// Kind of damage carried by a [`ResolvedDamageDef`].
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5#[non_exhaustive]
6pub enum ResolvedDamageKind {
7    Ap,
8    Sp,
9    Flat,
10    Weapon,
11    WeaponPercent,
12    NormalizedWeapon,
13}
14
15/// Equipped weapon used while resolving a DBC damage payload.
16#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
17#[non_exhaustive]
18pub enum ResolvedDamageWeapon {
19    #[default]
20    MainHand,
21    OffHand,
22}
23
24/// Auto-resolved damage descriptor for a spell.
25#[derive(Clone, Copy, Debug)]
26pub struct ResolvedDamageDef {
27    pub kind: ResolvedDamageKind,
28    pub coefficient: f64,
29    pub base_points: f64,
30    pub is_physical: bool,
31    pub effect_index: u8,
32    pub weapon: ResolvedDamageWeapon,
33}
34
35/// Spell-level properties resolved from game data.
36#[derive(Clone, Debug, Default)]
37#[expect(
38    clippy::struct_excessive_bools,
39    reason = "this flat DBC transfer object preserves independent spell flags"
40)]
41pub struct SpellProps {
42    pub attributes: Vec<i32>,
43    /// Raw `SpellMisc.DefenseType`; `2` is melee and `3` is ranged.
44    pub defense_type: i32,
45    /// Raw `SpellCategories.DispelType`; zero means the aura is not dispellable.
46    pub dispel_type: i32,
47    /// Raw `SpellCategories.Mechanic`; zero means the spell has no mechanic tag.
48    pub mechanic: i32,
49    pub can_empower: bool,
50    pub empower_stages: Vec<wowlab_types::data::EmpowerStage>,
51    pub equipped_item_requirement: Option<wowlab_types::data::EquippedItemRequirement>,
52    pub shapeshift_required_mask: u64,
53    pub shapeshift_excluded_mask: u64,
54    pub caster_aura_spell: i32,
55    pub caster_aura_state: i32,
56    pub exclude_caster_aura_spell: i32,
57    pub exclude_caster_aura_state: i32,
58    pub target_aura_spell: i32,
59    pub target_aura_state: i32,
60    pub exclude_target_aura_spell: i32,
61    pub exclude_target_aura_state: i32,
62    /// Primary `SpellAuraInterruptFlags` word.
63    pub aura_interrupt_flags: u32,
64    /// DBC `SpellInterrupts.InterruptFlags`.
65    pub spell_interrupt_flags: u32,
66    /// Primary DBC channel-interrupt flag word.
67    pub channel_interrupt_flags: u32,
68    pub cost: f64,
69    pub optional_cost: f64,
70    pub cost_pct: wowlab_types::data::ResourceCostPercent,
71    pub max_cost_pct: wowlab_types::data::ResourceCostPercent,
72    pub optional_cost_pct: wowlab_types::data::ResourceCostPercent,
73    pub gain: f64,
74    /// Flat health paid by the caster.
75    pub health_cost: f64,
76    /// Percent of caster maximum health paid by the caster.
77    pub health_cost_pct: f64,
78    /// Additional percent of maximum health spent up to the caster's current health.
79    pub health_max_cost_pct: f64,
80    /// Additional flat health spent up to the caster's current health.
81    pub health_optional_cost: f64,
82    /// Additional percentage health spent up to the caster's current health.
83    pub health_optional_cost_pct: wowlab_types::data::ResourceCostPercent,
84    /// 1-based DBC power-cost entry backing `cost` (`0` = none); cost modifiers route by entry.
85    pub primary_cost_entry: u8,
86    /// 1-based DBC power-cost entry backing `secondary_cost` (`0` = none).
87    pub secondary_cost_entry: u8,
88    pub secondary_cost: f64,
89    pub secondary_optional_cost: f64,
90    pub secondary_gain: f64,
91    pub cooldown_ms: i32,
92    pub cooldown_category: Option<wowlab_types::data::CooldownCategoryId>,
93    pub category_cooldown_ms: i32,
94    pub charge_category: Option<wowlab_types::data::CooldownCategoryId>,
95    pub cast_time_ms: i32,
96    pub duration_ms: i32,
97    pub max_stacks: i32,
98    pub max_charges: i32,
99    pub charge_cd_ms: i32,
100    pub start_recovery_category: Option<wowlab_types::data::CooldownCategoryId>,
101    pub gcd_ms: i32,
102    /// DBC projectile speed in yards per second.
103    pub projectile_speed: f64,
104    /// DBC launch delay in seconds.
105    pub launch_delay_s: f64,
106    /// Inclusive hostile minimum range in yards.
107    pub hostile_min_range: f64,
108    /// Inclusive hostile maximum range in yards.
109    pub hostile_max_range: f64,
110    /// Resolved spell/effect radius in yards.
111    pub radius: f64,
112    /// Resolved chain jump distance in yards.
113    pub chain_target_range: f64,
114    /// Resolved `SpellTargetRestrictions.MaxTargets`; zero means uncapped.
115    pub max_affected_targets: u8,
116    /// Cone half-angle in radians.
117    pub cone_half_angle: f64,
118    /// The DBC missile speed is a fixed travel delay rather than yards/second.
119    pub fixed_travel_time: bool,
120    pub ignores_line_of_sight: bool,
121    pub explicit_target_mask: u32,
122    /// Subset of `explicit_target_mask` whose absence must fail the cast.
123    pub required_explicit_target_mask: u32,
124    pub cooldown_hasted: bool,
125    pub gcd_haste_type: wowlab_types::combat::GcdHasteType,
126    pub hasted_ticks: bool,
127    pub duration_hasted: bool,
128    /// Spell attribute 285: effect points resolve from live mastery and the effect coefficient.
129    pub mastery_affects_points: bool,
130    pub cannot_crit: bool,
131    pub requires_unshifted: bool,
132    pub allow_while_unshifted: bool,
133    pub requires_stealth: bool,
134    /// Content-authored equivalent of `TrinityCore`'s behind-target custom attribute.
135    pub requires_behind_target: bool,
136    pub treat_as_periodic: bool,
137    pub treat_as_area_effect: bool,
138    pub does_not_break_stealth: bool,
139    pub usable_while_casting: bool,
140    pub usable_while_moving: bool,
141    pub asynchronous_stacks: bool,
142    pub disable_player_damage_multiplier: bool,
143    pub disable_target_damage_multiplier: bool,
144    pub disable_positive_target_damage_multiplier: bool,
145    pub requires_main_hand: bool,
146    pub requires_off_hand: bool,
147    pub refresh_behavior: wowlab_types::data::RefreshBehavior,
148    pub rolling_periodic: bool,
149    pub tick_may_crit: bool,
150    pub tick_on_application: bool,
151    /// `SpellAuraOptions.ProcChance` in percent points; 0 when the spell has no proc data.
152    pub proc_chance_pct: i32,
153    /// `SpellAuraOptions.ProcCharges`; zero means the proc aura has unlimited charges.
154    pub proc_charges: i32,
155    /// Raw `SpellProcEntry.AttributesMask` from server-side proc metadata.
156    pub proc_attributes: u32,
157    /// Multiplicative proc-chance modifier minus one; `-0.3` represents a final `0.7x` multiplier.
158    pub proc_chance_multiplier_delta: f64,
159    /// Combined `SpellAuraOptions.ProcTypeMask_0/1` event mask.
160    pub proc_type_mask: u64,
161    /// `SpellAuraOptions.ProcCategoryRecovery` internal cooldown in milliseconds.
162    pub proc_category_recovery_ms: i32,
163    /// Base real-procs-per-minute rate; zero when this spell uses fixed proc chance.
164    pub rppm_base_rate: f64,
165    /// Raw `SpellProcsPerMinute.Flags` retained for semantics not yet modeled.
166    pub rppm_flags: i32,
167    /// `SpellProcsPerMinuteMod.Type == 1` requests haste scaling.
168    pub rppm_haste_scales: bool,
169    /// `SpellProcsPerMinuteMod.Type == 2` requests crit scaling.
170    pub rppm_crit_scales: bool,
171    /// Passive affected-spell hit-chance modifier components.
172    pub hit_chance_flat: f64,
173    pub hit_chance_multiplier: f64,
174    /// Passive affected-spell target-resistance modifier components.
175    pub target_resistance_flat: f64,
176    pub target_resistance_multiplier: f64,
177    /// Passive affected-aura dispel-resistance modifier components.
178    pub dispel_resistance_flat: f64,
179    pub dispel_resistance_multiplier: f64,
180}
181
182pub(crate) const fn normalize_spell_modifier_defaults(mut props: SpellProps) -> SpellProps {
183    if props.hit_chance_multiplier.to_bits() == 0
184        && props.target_resistance_multiplier.to_bits() == 0
185        && props.dispel_resistance_multiplier.to_bits() == 0
186    {
187        props.hit_chance_multiplier = 1.0;
188        props.target_resistance_multiplier = 1.0;
189        props.dispel_resistance_multiplier = 1.0;
190    }
191
192    props
193}
194
195pub(crate) fn neutral_spell_props() -> SpellProps {
196    normalize_spell_modifier_defaults(SpellProps::default())
197}
198
199/// Aura-level properties resolved from game data.
200#[derive(Clone, Debug, Default)]
201pub struct AuraProps {
202    pub duration_ms: i32,
203    /// Positive DBC doses after passive modifiers; stacks added per aura application.
204    pub doses: i32,
205    pub max_stacks: i32,
206    pub tick_period_ms: i32,
207    pub pandemic: bool,
208}
209
210/// Power-type properties resolved from `game.power_types`, keyed by `power_type_enum`.
211#[derive(Clone, Debug, Default)]
212pub struct PowerTypeProps {
213    pub display_modifier: f64,
214    pub max_base_power: f64,
215    pub default_power: f64,
216    pub regen_combat: f64,
217    pub regen_percent_of_max: f64,
218    pub auto_attack_gain_percent: f64,
219    pub cost_percent: f64,
220}
221
222pub(crate) const fn default_aura_props() -> AuraProps {
223    AuraProps {
224        duration_ms: 0,
225        doses: 1,
226        max_stacks: 1,
227        tick_period_ms: 0,
228        pandemic: false,
229    }
230}