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}