Skip to main content

wowlab_engine_combat/systems/damage_pipeline/setup/
armor.rs

1#[cfg(test)]
2use wowlab_types::sim::EnemyIdx;
3use wowlab_types::{constants::HUNDRED, sim::ActorId};
4
5use super::DamageFlags;
6use crate::state::BuffEffect;
7#[cfg(test)]
8use crate::state::CombatInstance;
9
10pub(super) fn for_target(
11    view: crate::context::HookView<'_>,
12    source: ActorId,
13    flags: DamageFlags,
14) -> f64 {
15    let crate::context::HookView {
16        program,
17        instance: state,
18        target,
19        ..
20    } = view;
21
22    let Some(target) = target else {
23        return 0.0;
24    };
25
26    if !flags.contains(DamageFlags::PHYSICAL) || flags.contains(DamageFlags::PERIODIC) {
27        return 0.0;
28    }
29
30    let armor = program.enemy_definition(target).map_or(
31        0.0,
32        wowlab_engine_domain::encounter::EnemyActorDefinition::armor,
33    );
34
35    if armor <= 0.0 {
36        tracing::warn!("creature armor is non-positive; armor mitigation skipped");
37    }
38
39    if !program.damage.has_armor_bypass {
40        return armor * program.damage.target_armor_mult;
41    }
42
43    let mut bypass_pct = 0.0;
44
45    crate::systems::buffs::for_each_planned_actor_aura_effect(
46        crate::context::ActorView::new(program, state, ActorId::Enemy(target)),
47        crate::state::EffectFamily::ARMOR_BYPASS,
48        |key, _local, stacks, effect| {
49            if key.source() != source {
50                return;
51            }
52
53            if let BuffEffect::ArmorBypassFromCaster(percent) = effect {
54                bypass_pct += percent * stacks;
55            }
56        },
57    );
58
59    armor * program.damage.target_armor_mult * (1.0 - bypass_pct.clamp(0.0, HUNDRED) / HUNDRED)
60}
61
62#[cfg(test)]
63pub(super) fn for_fixture(
64    program: &crate::state::CombatProgram,
65    state: &CombatInstance,
66    flags: DamageFlags,
67) -> f64 {
68    for_target(
69        crate::HookView {
70            program,
71            instance: state,
72            target: state.current_target(),
73            now: wowlab_types::sim::SimTime::ZERO,
74        },
75        ActorId::Player,
76        flags,
77    )
78}
79
80#[cfg(test)]
81mod tests;