1use wowlab_engine_macros::LowerData;
2use wowlab_types::game::CdrEffect;
3
4use super::{BuilderDamageDef, BuilderSpellEffect, BuilderTriggerProgramPredicate};
5use crate::{
6 builder::lower::{self, BuilderToRuntimeCtx, InfoCtx},
7 state::LocalAuraIdx,
8};
9
10#[derive(Clone, Debug, LowerData)]
11#[expect(
12 clippy::struct_excessive_bools,
13 reason = "lowered spell behavior preserves independent DBC flags"
14)]
15#[lower(
16 data = "crate::state::SpellData",
17 ctx = "BuilderToRuntimeCtx<'_>",
18 extra(
19 behavior = lower::spell_behavior,
20 damage_policy = lower::spell_damage_policy,
21 cost = lower::spell_cost,
22 cooldown = lower::spell_cooldown,
23 channel = lower::spell_channel,
24 targeting = lower::spell_targeting,
25 requirements = lower::spell_requirements,
26 overrides = lower::spell_override,
27 followup_effects = lower::spell_followup_effects,
28 empower_cast_time_offset = lower::spell_empower_cast_time_offset,
29 empower_rank_count = lower::spell_empower_rank_count,
30 ),
31 info = "wowlab_types::game::SpellInfo",
32 info_ctx = "InfoCtx<'_>",
33 info_fields(
34 spell_id,
35 name = lower::spell_name,
36 slug = lower::spell_slug,
37 cast_time_ms,
38 start_recovery_category = lower::spell_info_start_recovery_category,
39 off_gcd = lower::spell_info_off_gcd,
40 gcd_ms,
41 is_pet = lower::spell_info_is_pet,
42 breaks_stealth = lower::spell_info_breaks_stealth,
43 resource_cost = lower::spell_info_resource_cost,
44 resource_gain = lower::spell_info_resource_gain,
45 secondary_resource_cost = lower::spell_info_secondary_resource_cost,
46 secondary_resource_gain = lower::spell_info_secondary_resource_gain,
47 damage = lower::spell_damage_info,
48 applies_aura_id = lower::spell_applies_aura_id,
49 cooldown = lower::spell_cooldown_info,
50 cdr_effects = lower::spell_cdr_effects_info,
51 ),
52 finalize = "crate::builder::spell_builder::SpellDefinitionDraft",
53 finalize_method = "from_draft",
54 finalize_args(
55 spell_id: u32,
56 name: String,
57 travel: crate::travel::SpellTravelData,
58 cooldown: Option<CooldownDef>,
59 damage_effect: crate::state::DamageEffectRef,
60 channel_tick_spell_id: u32,
61 ),
62)]
63pub(crate) struct BuilderSpellDef {
64 #[lower(copy)]
65 pub(crate) spell_id: u32,
66 #[lower(name_idx = lower::resolve_name_idx)]
67 pub(crate) name: String,
68 #[lower(copy)]
69 pub(crate) cast_time_ms: u32,
70 #[lower(skip)]
71 pub(crate) empower_cast_times_ms: Vec<u32>,
72 #[lower(copy)]
73 pub(crate) max_empower_aura_id: u32,
74 #[lower(skip)]
75 pub(crate) cooldown_hasted: bool,
76 #[lower(copy)]
77 pub(crate) gcd_haste_type: wowlab_types::combat::GcdHasteType,
78 #[lower(skip)]
79 pub(crate) start_recovery_category: Option<wowlab_types::data::CooldownCategoryId>,
80 #[lower(skip)]
81 pub(crate) usable_while_casting: bool,
82 #[lower(skip)]
83 pub(crate) usable_while_moving: bool,
84 #[lower(skip)]
85 pub(crate) explicit_target_mask: u32,
86 #[lower(skip)]
87 pub(crate) required_explicit_target_mask: u32,
88 #[lower(skip)]
89 pub(crate) shapeshift_required_mask: u64,
90 #[lower(skip)]
91 pub(crate) shapeshift_excluded_mask: u64,
92 #[lower(skip)]
93 pub(crate) caster_aura_spell: i32,
94 #[lower(skip)]
95 pub(crate) caster_aura_state: Option<crate::state::AuraState>,
96 #[lower(skip)]
97 pub(crate) exclude_caster_aura_spell: i32,
98 #[lower(skip)]
99 pub(crate) exclude_caster_aura_state: Option<crate::state::AuraState>,
100 #[lower(skip)]
101 pub(crate) target_aura_spell: i32,
102 #[lower(skip)]
103 pub(crate) target_aura_state: Option<crate::state::AuraState>,
104 #[lower(skip)]
105 pub(crate) exclude_target_aura_spell: i32,
106 #[lower(skip)]
107 pub(crate) exclude_target_aura_state: Option<crate::state::AuraState>,
108 #[lower(copy)]
109 pub(crate) travel: crate::travel::SpellTravelData,
110 #[lower(copy)]
111 pub(crate) gcd_ms: u32,
112 #[lower(skip)]
113 pub(crate) cooldown: Option<CooldownDef>,
114 #[lower(skip)]
115 pub(crate) resource_cost: f64,
116 #[lower(skip)]
117 pub(crate) optional_resource_cost: f64,
118 #[lower(skip)]
119 pub(crate) resource_cost_pct: wowlab_types::data::ResourceCostPercent,
120 #[lower(skip)]
121 pub(crate) maximum_resource_cost_pct: wowlab_types::data::ResourceCostPercent,
122 #[lower(skip)]
123 pub(crate) optional_resource_cost_pct: wowlab_types::data::ResourceCostPercent,
124 #[lower(skip)]
125 pub(crate) resource_gain: f64,
126 #[lower(skip)]
127 pub(crate) secondary_resource_cost: f64,
128 #[lower(skip)]
129 pub(crate) secondary_optional_resource_cost: f64,
130 #[lower(skip)]
131 pub(crate) secondary_resource_gain: f64,
132 #[lower(skip)]
133 pub(crate) health_cost: f64,
134 #[lower(skip)]
135 pub(crate) health_cost_pct: f64,
136 #[lower(skip)]
137 pub(crate) health_max_cost_pct: f64,
138 #[lower(skip)]
139 pub(crate) health_optional_cost: f64,
140 #[lower(skip)]
141 pub(crate) health_optional_cost_pct: wowlab_types::data::ResourceCostPercent,
142 #[lower(convert = lower::spell_damage)]
143 pub(crate) damage: BuilderDamageDef,
144 #[lower(skip)]
145 pub(crate) damage_may_crit: bool,
146 #[lower(copy)]
147 pub(crate) damage_attribute_flags: crate::DamageFlags,
148 #[lower(copy)]
149 pub(crate) damage_effect: crate::state::DamageEffectRef,
150 #[lower(copy)]
151 pub(crate) base_points: f64,
152 #[lower(copy)]
153 pub(crate) applies_aura: Option<LocalAuraIdx>,
154 #[lower(skip)]
155 pub(crate) followup_effects: Vec<BuilderSpellEffect>,
156 #[lower(skip)]
157 pub(crate) trigger_program_predicates: Vec<BuilderTriggerProgramPredicate>,
158 #[lower(skip)]
159 pub(crate) infer_data_damage: bool,
160 #[lower(skip)]
161 pub(crate) cdr_effects: Vec<CdrEffect>,
162 #[lower(skip)]
163 pub(crate) is_pet: bool,
164 #[lower(skip)]
165 pub(crate) requires_unshifted: bool,
166 #[lower(skip)]
167 pub(crate) allow_while_unshifted: bool,
168 #[lower(skip)]
169 pub(crate) requires_stealth: bool,
170 #[lower(skip)]
171 pub(crate) requires_behind_target: bool,
172 #[lower(skip)]
173 pub(crate) requires_main_hand: bool,
174 #[lower(skip)]
175 pub(crate) requires_off_hand: bool,
176 #[lower(skip)]
177 pub(crate) equipped_item_requirement: Option<wowlab_types::data::EquippedItemRequirement>,
178 #[lower(skip)]
179 pub(crate) breaks_stealth: bool,
180 #[lower(skip)]
181 pub(crate) aoe_max_targets: u8,
182 #[lower(skip)]
183 pub(crate) aoe_reduced_targets: u8,
184 #[lower(skip)]
185 pub(crate) aoe_full_targets: u8,
186 #[lower(skip)]
187 pub(crate) aoe_base_mult: f64,
188 #[lower(skip)]
189 pub(crate) chain_targeting: bool,
190 #[lower(skip)]
191 pub(crate) chain_multiplier: f64,
192 #[lower(skip)]
193 pub(crate) split: bool,
194 #[lower(skip)]
195 pub(crate) is_aoe: bool,
196 #[lower(skip)]
197 pub(crate) is_channel: bool,
198 #[lower(skip)]
199 pub(crate) channel_tick_count: u8,
200 #[lower(skip)]
201 pub(crate) channel_tick_interval_ms: u32,
202 #[lower(skip)]
203 pub(crate) channel_tick_zero: bool,
204 #[lower(skip)]
205 pub(crate) channel_tick_is_periodic: bool,
206 #[lower(skip)]
207 pub(crate) channel_hasted_ticks: bool,
208 #[lower(skip)]
209 pub(crate) channel_duration_hasted: bool,
210 #[lower(skip)]
211 pub(crate) channel_tick_damage: BuilderDamageDef,
212 #[lower(skip)]
213 pub(crate) channel_tick_may_crit: bool,
214 #[lower(skip)]
215 pub(crate) channel_tick_spell_id: u32,
216 #[lower(skip)]
217 pub(crate) channel_tick_damage_alt: BuilderDamageDef,
218 #[lower(skip)]
219 pub(crate) channel_tick_damage_alt_may_crit: bool,
220 #[lower(skip)]
221 pub(crate) channel_tick_damage_alt_spell_id: u32,
222 #[lower(skip)]
223 pub(crate) channel_tick_damage_aura: u32,
224 #[lower(skip)]
225 pub(crate) channel_tick_cost: f64,
226 #[lower(skip)]
227 pub(crate) channel_tick_cost_alt: f64,
228 #[lower(skip)]
229 pub(crate) channel_tick_cost_aura: u32,
230 #[lower(skip)]
231 pub(crate) channel_tick_effects: Vec<BuilderSpellEffect>,
232 #[lower(skip)]
233 pub(crate) channel_complete_effects: Vec<BuilderSpellEffect>,
234 #[lower(skip)]
235 pub(crate) channel_gcd_on_start: bool,
236 #[lower(skip)]
237 pub(crate) channel_apply_lag: bool,
238 #[lower(skip)]
239 pub(crate) gating_aura_id: u32,
240 #[lower(skip)]
241 pub(crate) gating_aura_min_stacks: u8,
242 #[lower(skip)]
243 pub(crate) cost_bypass_aura_id: u32,
244 #[lower(skip)]
245 pub(crate) consume_aura_on_cast_id: u32,
246 #[lower(skip)]
247 pub(crate) cooldown_bypass_aura_id: u32,
248 #[lower(skip)]
249 pub(crate) execute_below_pct: f64,
250 #[lower(skip)]
251 pub(crate) instant_cast_aura_id: u32,
252 #[lower(skip)]
253 pub(crate) override_aura_id: u32,
254 #[lower(skip)]
255 pub(crate) override_spell_id: u32,
256 #[lower(skip)]
257 pub(crate) override_aura_min_stacks: u8,
258 #[lower(skip)]
259 pub(crate) override_shares_base_cooldown: bool,
260 #[lower(skip)]
261 pub(crate) override_preserves_aura: bool,
262 #[lower(skip)]
263 pub(crate) guaranteed_crit: bool,
264}
265
266#[derive(Clone, Debug)]
267pub(crate) struct CooldownDef {
268 pub(crate) duration_secs: f64,
269 pub(crate) category: Option<wowlab_types::data::CooldownCategoryId>,
270 pub(crate) category_duration_secs: f64,
271 pub(crate) charge_category: Option<wowlab_types::data::CooldownCategoryId>,
272 pub(crate) max_charges: u8,
273 pub(crate) recharge_secs: f64,
274}