Skip to main content

azalea_entity/
effects.rs

1use std::{
2    collections::HashMap,
3    io::{self, Cursor, Write},
4};
5
6use azalea_buf::{AzBuf, BufReadError};
7use azalea_core::{attribute_modifier_operation::AttributeModifierOperation, bitset::FixedBitSet};
8use azalea_inventory::components::AttributeModifier;
9use azalea_registry::{
10    builtin::{Attribute, MobEffect},
11    identifier::Identifier,
12};
13
14/// Data about an active mob effect.
15#[derive(AzBuf, Clone, Debug, Default, PartialEq)]
16pub struct MobEffectData {
17    /// The effect's amplifier level, starting at 0 if present.
18    #[var]
19    pub amplifier: i32,
20    /// The effect's duration in ticks.
21    #[var]
22    pub duration: i32,
23
24    pub flags: MobEffectFlags,
25}
26
27#[derive(Clone, Debug, Default, PartialEq)]
28pub struct MobEffectFlags {
29    pub ambient: bool,
30    pub show_particles: bool,
31    pub show_icon: bool,
32    pub blend: bool,
33}
34
35impl AzBuf for MobEffectFlags {
36    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
37        let bitset = FixedBitSet::<8>::azalea_read(buf)?;
38        let ambient = bitset.index(0);
39        let show_particles = bitset.index(1);
40        let show_icon = bitset.index(2);
41        let blend = bitset.index(3);
42        Ok(Self {
43            ambient,
44            show_particles,
45            show_icon,
46            blend,
47        })
48    }
49    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
50        let mut bitset = FixedBitSet::<8>::new();
51        if self.ambient {
52            bitset.set(0);
53        }
54        if self.show_particles {
55            bitset.set(1);
56        }
57        if self.show_icon {
58            bitset.set(2);
59        }
60        if self.blend {
61            bitset.set(3);
62        }
63        bitset.azalea_write(buf)
64    }
65}
66
67/// The active mob effects on an entity.
68#[cfg_attr(feature = "bevy_ecs", derive(bevy_ecs::component::Component))]
69#[derive(Clone, Debug, Default)]
70pub struct ActiveEffects(pub HashMap<MobEffect, MobEffectData>);
71impl ActiveEffects {
72    pub fn insert(&mut self, effect: MobEffect, data: MobEffectData) -> Option<MobEffectData> {
73        self.0.insert(effect, data)
74    }
75
76    pub fn remove(&mut self, effect: MobEffect) -> Option<MobEffectData> {
77        self.0.remove(&effect)
78    }
79
80    /// Get the amplifier level for the effect, starting at 0.
81    pub fn get_level(&self, effect: MobEffect) -> Option<i32> {
82        self.0.get(&effect).map(|data| data.amplifier)
83    }
84
85    pub fn get(&self, effect: MobEffect) -> Option<&MobEffectData> {
86        self.0.get(&effect)
87    }
88
89    /// Returns the amplifier for dig speed (haste / conduit power), if present.
90    pub fn get_dig_speed_amplifier(&self) -> Option<i32> {
91        let haste_level = self
92            .get_level(MobEffect::Haste)
93            .map(|level| level + 1)
94            .unwrap_or_default();
95        let conduit_power_level = self
96            .get_level(MobEffect::ConduitPower)
97            .map(|level| level + 1)
98            .unwrap_or_default();
99
100        let effect_plus_one = i32::max(haste_level, conduit_power_level);
101        if effect_plus_one > 0 {
102            Some(effect_plus_one - 1)
103        } else {
104            None
105        }
106    }
107}
108
109pub fn attribute_modifier_for_effect(id: MobEffect) -> Option<(Attribute, AttributeTemplate)> {
110    Some(match id {
111        MobEffect::Speed => (
112            Attribute::MovementSpeed,
113            AttributeTemplate::new(
114                "effect.speed",
115                0.2f32 as f64,
116                AttributeModifierOperation::AddMultipliedTotal,
117            ),
118        ),
119        MobEffect::Slowness => (
120            Attribute::MovementSpeed,
121            AttributeTemplate::new(
122                "effect.slowness",
123                -0.15f32 as f64,
124                AttributeModifierOperation::AddMultipliedTotal,
125            ),
126        ),
127        MobEffect::Haste => (
128            Attribute::AttackSpeed,
129            AttributeTemplate::new(
130                "effect.haste",
131                0.1f32 as f64,
132                AttributeModifierOperation::AddMultipliedTotal,
133            ),
134        ),
135        MobEffect::MiningFatigue => (
136            Attribute::AttackSpeed,
137            AttributeTemplate::new(
138                "effect.mining_fatigue",
139                -0.1f32 as f64,
140                AttributeModifierOperation::AddMultipliedTotal,
141            ),
142        ),
143        MobEffect::Strength => (
144            Attribute::AttackDamage,
145            AttributeTemplate::new("effect.strength", 3.0, AttributeModifierOperation::AddValue),
146        ),
147        MobEffect::JumpBoost => (
148            Attribute::SafeFallDistance,
149            AttributeTemplate::new(
150                "effect.jump_boost",
151                1.0,
152                AttributeModifierOperation::AddValue,
153            ),
154        ),
155        MobEffect::Invisibility => (
156            Attribute::WaypointTransmitRange,
157            AttributeTemplate::new(
158                "effect.waypoint_transmit_range_hide",
159                -1.0,
160                AttributeModifierOperation::AddMultipliedTotal,
161            ),
162        ),
163        MobEffect::Weakness => (
164            Attribute::AttackDamage,
165            AttributeTemplate::new(
166                "effect.weakness",
167                -4.0,
168                AttributeModifierOperation::AddValue,
169            ),
170        ),
171        MobEffect::HealthBoost => (
172            Attribute::MaxHealth,
173            AttributeTemplate::new(
174                "effect.health_boost",
175                4.0,
176                AttributeModifierOperation::AddValue,
177            ),
178        ),
179        MobEffect::Absorption => (
180            Attribute::MaxAbsorption,
181            AttributeTemplate::new(
182                "effect.absorption",
183                4.0,
184                AttributeModifierOperation::AddValue,
185            ),
186        ),
187        MobEffect::Luck => (
188            Attribute::Luck,
189            AttributeTemplate::new("effect.luck", 1.0, AttributeModifierOperation::AddValue),
190        ),
191        MobEffect::Unluck => (
192            Attribute::Luck,
193            AttributeTemplate::new("effect.unluck", -1.0, AttributeModifierOperation::AddValue),
194        ),
195        _ => return None,
196    })
197}
198
199pub struct AttributeTemplate(AttributeModifier);
200impl AttributeTemplate {
201    pub fn new(id: &str, amount: f64, operation: AttributeModifierOperation) -> Self {
202        Self(AttributeModifier {
203            id: Identifier::from(id),
204            amount,
205            operation,
206        })
207    }
208    pub fn create(self, amplifier: i32) -> AttributeModifier {
209        AttributeModifier {
210            id: self.0.id,
211            amount: self.0.amount * (amplifier + 1) as f64,
212            operation: self.0.operation,
213        }
214    }
215}