wowlab_engine_combat/pipeline/
hooks.rs1use super::{
2 CombatCtx, DamageFlags, EffectExecution, FreeActionSource, HookCtx, LocalAuraIdx,
3 LocalSpellIdx, ScratchDisposition, SpellData, apply_aura, apply_aura_with_duration,
4 consume_aura_stack_by_id, drain_deferred_work, execute_effect_range, with_scratch,
5};
6
7pub(super) fn consume_cast_auras(
8 ctx: &mut CombatCtx<'_>,
9 override_aura_id: Option<u32>,
10 cooldown_bypass_aura_id: Option<u32>,
11 consume_aura_on_cast_id: u32,
12) {
13 if let Some(aura_id) = override_aura_id {
14 consume_aura_stack_by_id(&mut ctx.hook_ctx(), aura_id);
15 }
16
17 if let Some(aura_id) = cooldown_bypass_aura_id {
18 consume_aura_stack_by_id(&mut ctx.hook_ctx(), aura_id);
19 }
20
21 if consume_aura_on_cast_id != 0 {
22 consume_aura_stack_by_id(&mut ctx.hook_ctx(), consume_aura_on_cast_id);
23 }
24}
25
26pub(super) fn apply_cast_aura(
27 ctx: &mut CombatCtx<'_>,
28 aura_local: LocalAuraIdx,
29 duration_ms: Option<u32>,
30 flags: DamageFlags,
31) {
32 let source = ctx.source;
33 let hook = ctx.hook_ctx();
34 let mut hook = if flags.contains(DamageFlags::REFLECTED) {
35 hook.with_effect_target(source)
36 } else {
37 hook
38 };
39
40 if let Some(duration_ms) = duration_ms {
41 apply_aura_with_duration(&mut hook, aura_local, Some(duration_ms));
42 } else {
43 apply_aura(&mut hook, aura_local);
44 }
45}
46
47pub(super) fn process_followup_effects(
48 ctx: &mut CombatCtx<'_>,
49 spell: &SpellData,
50 flags: DamageFlags,
51) {
52 execute_effect_range(
53 ctx,
54 EffectExecution {
55 range: spell.followup_effects,
56 profile_spell_id: spell.spell_id,
57 flags,
58 },
59 );
60}
61
62pub(super) fn fire_expire_hooks(ctx: &mut CombatCtx<'_>) {
63 let CombatCtx {
64 state,
65 buf,
66 sink,
67 now,
68 rng,
69 source,
70 target,
71 } = ctx;
72 let mut aura_ctx = HookCtx::new(
73 crate::context::HookCtxServices {
74 state,
75 buf,
76 sink,
77 rng: *rng,
78 },
79 crate::context::HookCtxRequest::for_target(*now, *target).with_source(*source),
80 );
81
82 drain_deferred_work(&mut aura_ctx);
83}
84
85pub(super) fn fire_cast_hook(
86 ctx: &mut CombatCtx<'_>,
87 spell_local: LocalSpellIdx,
88 empower_rank: u8,
89) {
90 fire_cast_hook_with_source(ctx, spell_local, empower_rank, None);
91}
92
93pub(super) fn fire_cast_hook_with_source(
94 ctx: &mut CombatCtx<'_>,
95 spell_local: LocalSpellIdx,
96 empower_rank: u8,
97 free_action_source: Option<FreeActionSource>,
98) {
99 let hook = ctx
100 .state
101 .defs
102 .cast_hooks
103 .get(spell_local.as_usize())
104 .copied()
105 .flatten();
106 let driver_spell_id = ctx
107 .state
108 .defs
109 .spells
110 .get(spell_local.as_usize())
111 .map_or(0, |spell| spell.spell_id);
112
113 if let Some(hook_fn) = hook {
114 let hook_ctx = HookCtx::new(
115 crate::context::HookCtxServices {
116 state: ctx.state,
117 buf: ctx.buf,
118 sink: ctx.sink,
119 rng: ctx.rng,
120 },
121 crate::context::HookCtxRequest::for_target(ctx.now, ctx.target).with_source(ctx.source),
122 )
123 .with_driver_spell(driver_spell_id)
124 .with_empower_rank(empower_rank);
125 let mut hook_ctx = if let Some(source) = free_action_source {
126 hook_ctx.with_free_action_source(source)
127 } else {
128 hook_ctx
129 };
130
131 hook_fn(&mut hook_ctx);
132 }
133}
134
135pub(super) fn fire_player_cast_hooks(ctx: &mut CombatCtx<'_>, spell_id: u32, empower_rank: u8) {
136 let original = std::mem::take(&mut ctx.state.defs.player_cast_hooks);
137 let scratch = std::mem::take(&mut ctx.state.runtime.scratch.hooks);
138 let (original, scratch) = with_scratch(
139 original,
140 scratch,
141 ScratchDisposition::PreserveSource,
142 |entries| {
143 for hook_fn in entries.iter().copied() {
144 let mut hook_ctx = HookCtx::new(
145 crate::context::HookCtxServices {
146 state: ctx.state,
147 buf: ctx.buf,
148 sink: ctx.sink,
149 rng: ctx.rng,
150 },
151 crate::context::HookCtxRequest::for_target(ctx.now, ctx.target)
152 .with_source(ctx.source),
153 )
154 .with_driver_spell(spell_id)
155 .with_empower_rank(empower_rank);
156
157 hook_fn(&mut hook_ctx);
158 }
159 },
160 );
161
162 ctx.state.defs.player_cast_hooks = original;
163 ctx.state.runtime.scratch.hooks = scratch;
164}