aboutsummaryrefslogtreecommitdiff
path: root/azalea-entity/src/effects.rs
blob: ae7ae8a1e26357aff2e4f19014a00e1427b14671 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use std::{
    collections::HashMap,
    io::{self, Cursor, Write},
};

use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
use azalea_core::bitset::FixedBitSet;
use azalea_registry::builtin::MobEffect;
use bevy_ecs::component::Component;

/// Data about an active mob effect.
#[derive(AzBuf, Clone, Debug, Default, PartialEq)]
pub struct MobEffectData {
    /// The effect's amplifier level, starting at 0 if present.
    #[var]
    pub amplifier: u32,
    #[var]
    pub duration_ticks: u32,

    pub flags: MobEffectFlags,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct MobEffectFlags {
    pub ambient: bool,
    pub show_particles: bool,
    pub show_icon: bool,
    pub blend: bool,
}

impl AzaleaRead for MobEffectFlags {
    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
        let bitset = FixedBitSet::<8>::azalea_read(buf)?;
        let ambient = bitset.index(0);
        let show_particles = bitset.index(1);
        let show_icon = bitset.index(2);
        let blend = bitset.index(3);
        Ok(Self {
            ambient,
            show_particles,
            show_icon,
            blend,
        })
    }
}

impl AzaleaWrite for MobEffectFlags {
    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
        let mut bitset = FixedBitSet::<8>::new();
        if self.ambient {
            bitset.set(0);
        }
        if self.show_particles {
            bitset.set(1);
        }
        if self.show_icon {
            bitset.set(2);
        }
        if self.blend {
            bitset.set(3);
        }
        bitset.azalea_write(buf)
    }
}

/// An ECS component that stores the active mob effects on an entity.
#[derive(Clone, Component, Debug, Default)]
pub struct ActiveEffects(pub HashMap<MobEffect, MobEffectData>);
impl ActiveEffects {
    pub fn insert(&mut self, effect: MobEffect, data: MobEffectData) {
        self.0.insert(effect, data);
    }

    pub fn remove(&mut self, effect: MobEffect) -> Option<MobEffectData> {
        self.0.remove(&effect)
    }

    /// Get the amplifier level for the effect, starting at 0.
    pub fn get_level(&self, effect: MobEffect) -> Option<u32> {
        self.0.get(&effect).map(|data| data.amplifier)
    }

    pub fn get(&self, effect: MobEffect) -> Option<&MobEffectData> {
        self.0.get(&effect)
    }

    /// Returns the amplifier for dig speed (haste / conduit power), if present.
    pub fn get_dig_speed_amplifier(&self) -> Option<u32> {
        let haste_level = self
            .get_level(MobEffect::Haste)
            .map(|level| level + 1)
            .unwrap_or_default();
        let conduit_power_level = self
            .get_level(MobEffect::ConduitPower)
            .map(|level| level + 1)
            .unwrap_or_default();

        let effect_plus_one = u32::max(haste_level, conduit_power_level);
        if effect_plus_one > 0 {
            Some(effect_plus_one - 1)
        } else {
            None
        }
    }
}