Skip to main content

steel_core/behavior/blocks/building/
amethyst_block.rs

1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::{blocks::BlockRef, sound_events::BLOCK_AMETHYST_BLOCK_CHIME};
5use steel_utils::{BlockPos, BlockStateId};
6
7use crate::{
8    behavior::{BlockBehavior, BlockPlaceContext},
9    entity::projectile::Projectile,
10    world::{ClipHitResult, World},
11};
12
13/// Vanilla `AmethystBlock` behavior shared by amethyst blocks and clusters.
14#[block_behavior]
15pub struct AmethystBlock {
16    block: BlockRef,
17}
18
19impl AmethystBlock {
20    /// Creates an amethyst block behavior.
21    #[must_use]
22    pub const fn new(block: BlockRef) -> Self {
23        Self { block }
24    }
25
26    fn projectile_hit_pitch(random_fraction: f32) -> f32 {
27        0.5 + random_fraction * 1.2
28    }
29
30    pub(super) fn play_projectile_hit_sound(world: &World, pos: BlockPos) {
31        let pitch = Self::projectile_hit_pitch(rand::random());
32        world.play_block_sound(&BLOCK_AMETHYST_BLOCK_CHIME, pos, 1.0, pitch, None);
33    }
34}
35
36impl BlockBehavior for AmethystBlock {
37    fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
38        Some(self.block.default_state())
39    }
40
41    fn on_projectile_hit(
42        &self,
43        _state: BlockStateId,
44        world: &Arc<World>,
45        hit: &ClipHitResult,
46        _projectile: &dyn Projectile,
47    ) {
48        Self::play_projectile_hit_sound(world, hit.block_pos);
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::AmethystBlock;
55
56    #[test]
57    fn projectile_chime_pitch_matches_vanilla_range() {
58        assert!((AmethystBlock::projectile_hit_pitch(0.0) - 0.5).abs() < f32::EPSILON);
59        assert!(AmethystBlock::projectile_hit_pitch(0.999_999) < 1.7);
60    }
61}