wowlab_engine_combat/systems/damage_pipeline/
leech.rs1use wowlab_engine_telemetry::DamageEvent;
4use wowlab_types::{
5 constants::HUNDRED,
6 sim::{ActorId, SpellIdx},
7};
8
9use super::school_of;
10use crate::{
11 context::CombatCtx,
12 state::BuffEffect,
13 systems::{HealRequest, buffs, deal_heal},
14};
15
16pub(super) fn apply_leech_healing(
17 ctx: &mut CombatCtx<'_>,
18 event: &DamageEvent,
19 actual_damage: f64,
20) {
21 if actual_damage <= f64::EPSILON || matches!(ctx.source, ActorId::Enemy(_)) {
22 return;
23 }
24
25 let mut leech_percent = ctx.state.config.base_stats.stats.leech;
26
27 buffs::for_each_active_actor_aura_effect(ctx.view().for_actor(ctx.source), |stacks, effect| {
28 if let BuffEffect::LeechPercent(percent) = effect {
29 leech_percent += percent * stacks;
30 }
31 });
32 let spell = SpellIdx::from_raw(event.spell_id);
33 let health_leech_fraction = (1..=ctx.state.config.game_data.max_effect_index(spell))
34 .find(|&effect_index| {
35 wowlab_engine_domain::dbc::spell_effect_is(
36 ctx.state.config.game_data.effect_type(spell, effect_index),
37 wowlab_engine_domain::dbc::SpellEffectKind::HealthLeech,
38 )
39 })
40 .map_or(0.0, |effect_index| {
41 let amplitude = ctx.state.config.game_data.amplitude(spell, effect_index);
42
43 buffs::active_effect_amplitude(ctx.view().for_actor(ctx.source), spell, amplitude)
44 .max(0.0)
45 });
46 let fraction = leech_percent.max(0.0) / HUNDRED + health_leech_fraction;
47
48 if fraction <= f64::EPSILON {
49 return;
50 }
51
52 let school = school_of(ctx.state, event.spell_id);
53 let _ = deal_heal(
54 ctx.state,
55 ctx.buf,
56 ctx.rng,
57 HealRequest {
58 source: ctx.source,
59 target: ctx.source,
60 base: actual_damage * fraction,
61 percent_of_max: 0.0,
62 school,
63 periodic: event.is_periodic,
64 may_crit: false,
65 at: ctx.now,
66 },
67 );
68}