Skip to main content

wowlab_engine_combat/systems/damage_pipeline/
leech.rs

1//! Leech healing produced by finalized outgoing damage.
2
3use 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}