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