all_is_cubes/
fluff.rs

1//! Momentary decorative and informative effects produced by the game world, such as sound and
2//! particles.
3
4use crate::math::{GridAab, PositiveSign, ps32, zo32};
5
6#[cfg(doc)]
7use crate::block::BlockAttributes;
8#[cfg(doc)]
9use crate::op::Operation;
10use crate::sound::SoundDef;
11#[cfg(doc)]
12use crate::space::{Space, SpaceFluff};
13use crate::universe;
14
15// -------------------------------------------------------------------------------------------------
16
17/// Momentary decorative and informative effects produced by the game world, such as sound and
18/// particles.
19///
20/// Each [`Fluff`] value represents the beginning of such an effect. It does not specify
21/// anything about the exact duration; the intent is that they should all be negligibly
22/// short.
23///
24/// Some fluff refers to events happening in a [`Space`]. In that case, the position and extent
25/// is communicated separately via [`SpaceFluff`].
26///
27/// Currently, all `Fluff` is an item from a fixed list. In the future, it will be able
28/// to refer to audio and visual assets defined in a `Universe`.
29#[derive(Debug, Clone, Hash, Eq, PartialEq)]
30#[non_exhaustive]
31pub enum Fluff {
32    /// A standard beep/“bell” sound, as might be used for a notification or error.
33    Beep,
34
35    /// A sound suitable for “something was activated or done”, e.g. a button was clicked.
36    Happened,
37
38    /// Something went wrong with the operation of a block present as placed in a [`Space`].
39    BlockFault(BlockFault),
40
41    /// Sound and visual effect from a block having been placed in the game world
42    /// by player action, without any more specific overriding styling.
43    PlaceBlockGeneric,
44
45    /// Collision between a block and a moving object.
46    #[non_exhaustive]
47    BlockImpact {
48        /// Closing velocity in m/s.
49        velocity: PositiveSign<f32>,
50    },
51}
52
53/// A subcategory of [`Fluff`]: something went wrong with the operation of a block as placed in a
54/// [`Space`].
55///
56/// This is not intended for display to all players but as an editor's diagnostic tool.
57#[derive(Debug, Clone, Hash, Eq, PartialEq)]
58#[non_exhaustive]
59pub enum BlockFault {
60    /// The block would have executed its [`BlockAttributes::tick_action`] operation,
61    /// but it was prevented due to the operation or transaction preconditions not being met
62    /// in the given region.
63    TickPrecondition(GridAab),
64
65    /// The block would have executed its [`BlockAttributes::tick_action`] operation,
66    /// but another tick action conflicted with it in the given region.
67    /// This may occur as a normal consequence of e.g. moving structures colliding with each other.
68    TickConflict(GridAab),
69}
70
71// -------------------------------------------------------------------------------------------------
72
73impl Fluff {
74    /// Returns the sound that should be played and the amplitude multiplier with which it should be
75    /// played.
76    ///
77    /// Whether or not this sound should be spatialized depends on the context in which the
78    /// [`Fluff`] was delivered.
79    ///
80    /// TODO: The return value shouldn’t be `'static` but a `Handle`; this is a development
81    /// placeholder.
82    pub fn sound(&self) -> Option<(&'static SoundDef, f32)> {
83        // TODO: these constants should be universe contents instead
84        const BEEP: SoundDef = SoundDef {
85            duration: zo32(0.08),
86            frequency: ps32(636.6),
87            amplitude: zo32(0.1),
88        };
89        const HAPPENED: SoundDef = SoundDef {
90            duration: zo32(0.005),
91            frequency: ps32(318.3),
92            amplitude: zo32(0.2),
93        };
94        const THUMP: SoundDef = SoundDef {
95            duration: zo32(0.02),
96            frequency: ps32(79.6),
97            amplitude: zo32(1.0), // modulated by collision info
98        };
99
100        match self {
101            Fluff::Beep => Some((&BEEP, 1.0)),
102            Fluff::Happened | Fluff::PlaceBlockGeneric => Some((&HAPPENED, 1.0)),
103            Fluff::BlockFault(_) => None,
104            // TODO: Should produce THUMP but there is not yet a way to implement the volume variation
105            Fluff::BlockImpact { velocity } => {
106                let velocity: f32 = velocity.into_inner();
107                // TODO: Use the correct scaling here.
108                // The amplitude of the sound should be proportional to the initial displacement
109                // of the vibrating surfaces, but how does that initial displacement scale?
110                let amplitude = (velocity * 0.01).clamp(0.0, 1.0);
111                Some((&THUMP, amplitude))
112            }
113        }
114    }
115}
116
117impl universe::VisitHandles for Fluff {
118    fn visit_handles(&self, _: &mut dyn universe::HandleVisitor) {
119        match self {
120            Fluff::Beep => {}
121            Fluff::Happened => {}
122            Fluff::BlockFault(_) => {}
123            Fluff::PlaceBlockGeneric => {}
124            Fluff::BlockImpact { velocity: _ } => {}
125        }
126    }
127}