Skip to main content

steel_core/entity/
combat_rules.rs

1use crate::enchantment_helper::{self, EnchantmentDamageContext};
2use crate::entity::LivingEntity;
3
4use super::damage::DamageSource;
5
6const MAX_ARMOR: f32 = 20.0;
7const ARMOR_PROTECTION_DIVIDER: f32 = 25.0;
8const BASE_ARMOR_TOUGHNESS: f32 = 2.0;
9const MIN_ARMOR_RATIO: f32 = 0.2;
10
11/// Returns vanilla `CombatRules.getDamageAfterAbsorb`.
12pub(super) fn get_damage_after_absorb(
13    victim: &(impl LivingEntity + ?Sized),
14    damage: f32,
15    source: &DamageSource,
16    total_armor: f32,
17    armor_toughness: f32,
18) -> f32 {
19    let toughness = BASE_ARMOR_TOUGHNESS + armor_toughness / 4.0;
20    let real_armor =
21        (total_armor - damage / toughness).clamp(total_armor * MIN_ARMOR_RATIO, MAX_ARMOR);
22    let armor_fraction = real_armor / ARMOR_PROTECTION_DIVIDER;
23    let mut modified_armor_fraction = armor_fraction;
24
25    if let Some(world) = victim.level()
26        && let Some(direct_entity) = source
27            .direct_entity_id
28            .and_then(|entity_id| world.get_entity_by_id(entity_id))
29    {
30        let context =
31            EnchantmentDamageContext::from_damage_source(&world, victim.entity_type(), source);
32        direct_entity.with_weapon_item(&mut |weapon| {
33            if let Some(weapon) = weapon {
34                modified_armor_fraction = enchantment_helper::modify_armor_effectiveness(
35                    weapon,
36                    &context,
37                    armor_fraction,
38                )
39                .clamp(0.0, 1.0);
40            }
41        });
42    }
43
44    damage * (1.0 - modified_armor_fraction)
45}
46
47/// Returns vanilla `CombatRules.getDamageAfterMagicAbsorb`.
48pub(super) fn get_damage_after_magic_absorb(damage: f32, total_magic_armor: f32) -> f32 {
49    let real_armor = total_magic_armor.clamp(0.0, MAX_ARMOR);
50    damage * (1.0 - real_armor / ARMOR_PROTECTION_DIVIDER)
51}
52
53#[cfg(test)]
54mod tests {
55    use super::get_damage_after_magic_absorb;
56
57    #[test]
58    fn magic_absorb_clamps_protection_to_vanilla_range() {
59        assert_eq!(
60            get_damage_after_magic_absorb(10.0, -1.0).to_bits(),
61            10.0_f32.to_bits()
62        );
63        assert_eq!(
64            get_damage_after_magic_absorb(10.0, 5.0).to_bits(),
65            8.0_f32.to_bits()
66        );
67        assert_eq!(
68            get_damage_after_magic_absorb(10.0, 25.0).to_bits(),
69            (10.0_f32 * (1.0 - 20.0_f32 / 25.0)).to_bits()
70        );
71    }
72}