Snow footsteps

This commit is contained in:
jiminycrick 2020-11-06 00:05:29 -08:00
parent 09a1974974
commit 9b759efe41
11 changed files with 113 additions and 154 deletions

View File

@ -75,6 +75,14 @@
],
threshold: 0.25,
),
SnowRun: (
files: [
"voxygen.audio.sfx.footsteps.snow_step_1",
"voxygen.audio.sfx.footsteps.snow_step_2",
"voxygen.audio.sfx.footsteps.snow_step_3",
],
threshold: 0.25,
),
ExperienceGained: (
files: [
// "voxygen.audio.sfx.character.experience_gained_1",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -42,6 +42,7 @@ make_case_elim!(
Wood = 0x40,
Leaves = 0x41,
// 0x42 <= x < 0x50 is reserved for future tree parts
Snow = 0x50,
// Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we
// often want to experiment with new kinds of block without allocating them a

View File

@ -45,7 +45,7 @@ use common::{
state::State,
terrain::{BiomeKind, SitesKind},
};
use rand::{prelude::SliceRandom, thread_rng};
use rand::{prelude::SliceRandom, thread_rng, Rng};
use serde::Deserialize;
use std::time::Instant;
use tracing::warn;
@ -64,7 +64,7 @@ pub struct SoundtrackItem {
title: String,
path: String,
/// Length of the track in seconds
length: f64,
length: f32,
/// Whether this track should play during day or night
timing: Option<DayPeriod>,
biomes: Vec<(BiomeKind, u8)>,
@ -93,13 +93,10 @@ enum PlayState {
pub struct MusicMgr {
soundtrack: SoundtrackCollection,
began_playing: Instant,
//began_fading: Instant,
next_track_change: f64,
next_track_change: f32,
/// The title of the last track played. Used to prevent a track
/// being played twice in a row
last_track: String,
/*last_biome: BiomeKind,
*playing: PlayState, */
}
impl MusicMgr {
@ -108,61 +105,51 @@ impl MusicMgr {
Self {
soundtrack: Self::load_soundtrack_items(),
began_playing: Instant::now(),
//began_fading: Instant::now(),
next_track_change: 0.0,
last_track: String::from("None"),
/*last_biome: BiomeKind::Void,
*playing: PlayState::Stopped, */
}
}
/// Checks whether the previous track has completed. If so, sends a
/// request to play the next (random) track
pub fn maintain(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) {
// Gets the current player biome
//let current_biome: BiomeKind = match client.current_chunk() {
// Some(chunk) => chunk.meta().biome(),
// _ => self.last_biome,
if let Some(current_chunk) = client.current_chunk() {
println!("biome: {:?}", current_chunk.meta().biome());
println!("chaos: {}", current_chunk.meta().chaos());
println!("alt: {}", current_chunk.meta().alt());
println!("temp: {}", current_chunk.meta().temp());
println!("tree_density: {}", current_chunk.meta().tree_density());
println!("humidity: {}", current_chunk.meta().humidity());
println!("cave_alt: {}", current_chunk.meta().cave_alt());
//if let Some(position) = client.current_position() {
// println!("player_pos: {:?}", position);
}
//let player_position = match client.current_position() {
// Some(pos) => pos,
// None => Vec3::default(),
//};
//if let Some(current_chunk) = client.current_chunk() {
// println!("biome: {:?}", current_chunk.meta().biome());
// println!("chaos: {}", current_chunk.meta().chaos());
// println!("alt: {}", current_chunk.meta().alt());
// println!("temp: {}", current_chunk.meta().temp());
// println!("tree_density: {}",
// current_chunk.meta().tree_density());
// println!("humidity: {}", current_chunk.meta().humidity());
// println!("cave_alt: {}", current_chunk.meta().cave_alt());
// if let Some(position) = client.current_position() {
// println!("player_alt: {}", position[2]);
// }
//}
//let block_position = Vec3::new(
// player_position[0],
// player_position[1],
// player_position[2] - 1.0,
//)
//.map(|x| x as i32);
//let block_kind = match state.get_block(block_position) {
// Some(block) => block.kind(),
// None => BlockKind::Air,
//};
//println!("BlockKind: {:?}", block_kind);
if audio.music_enabled()
&& !self.soundtrack.tracks.is_empty()
&& self.began_playing.elapsed().as_secs_f64() > self.next_track_change
// || self.playing == PlayState::Stopped)
// && self.playing != PlayState::FadingOut
&& self.began_playing.elapsed().as_secs_f32() > self.next_track_change
{
self.play_random_track(audio, state, client);
// self.playing = PlayState::Playing;
//} else if current_biome != self.last_biome && self.playing == PlayState::Playing {
// audio.fade_out_exploration_music();
// self.began_fading = Instant::now();
// self.playing = PlayState::FadingOut;
//} else if self.began_fading.elapsed().as_secs_f64() > 5.0
// && self.playing == PlayState::FadingOut
//{
// audio.stop_exploration_music();
// self.playing = PlayState::Stopped;
}
//self.last_biome = current_biome;
}
fn play_random_track(&mut self, audio: &mut AudioFrontend, state: &State, client: &Client) {
//const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 45.0;
const SILENCE_BETWEEN_TRACKS_SECONDS: f64 = 5.0;
let silence_between_tracks_seconds: f32 = thread_rng().gen_range(30.0, 60.0);
let game_time = (state.get_time_of_day() as u64 % 86400) as u32;
let current_period_of_day = Self::get_current_day_period(game_time);
@ -217,7 +204,7 @@ impl MusicMgr {
if let Ok(track) = new_maybe_track {
self.last_track = String::from(&track.title);
self.began_playing = Instant::now();
self.next_track_change = track.length + SILENCE_BETWEEN_TRACKS_SECONDS;
self.next_track_change = track.length + silence_between_tracks_seconds;
audio.play_exploration_music(&track.path);
}

View File

@ -71,6 +71,7 @@ impl EventMapper for BlockEventMapper {
// Condition that must be true to play
cond: fn(&State) -> bool,
}
let sounds: &[BlockSounds] = &[
BlockSounds {
blocks: |boi| &boi.leaves,
@ -108,7 +109,6 @@ impl EventMapper for BlockEventMapper {
sfx: SfxEvent::Frog,
volume: 0.8,
cond: |st| st.get_day_period().is_dark(),
//cond: |_| true,
},
//BlockSounds {
// blocks: |boi| &boi.flowers,
@ -153,86 +153,34 @@ impl EventMapper for BlockEventMapper {
// Get the positions of the blocks of type sounds
let blocks = (sounds.blocks)(&chunk_data.blocks_of_interest);
//let mut my_blocks = blocks.to_vec();
//// Reduce the number of bird calls from trees
//if sounds.sfx == SfxEvent::Birdcall {
// my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect();
// //blocks = blocks.to_vec().choose_multiple(&mut thread_rng(), 6).cloned().collect::<Vec<vek::Vec3<i32>>>().as_slice();
//} else if sounds.sfx == SfxEvent::Cricket {
// my_blocks = my_blocks.choose_multiple(&mut thread_rng(), 6).cloned().collect();
//}
let absolute_pos: Vec3<i32> =
Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32));
// Iterate through each individual block
for block in blocks {
if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl) && thread_rng().gen_bool(0.999) {
continue;
}
if (sounds.sfx == SfxEvent::Birdcall || sounds.sfx == SfxEvent::Owl)
&& thread_rng().gen_bool(0.999)
{
continue;
}
let block_pos: Vec3<i32> = absolute_pos + block;
let state = self.history.entry(block_pos).or_default();
// Convert to f32 for sfx emitter
//let block_pos = Vec3::new(
// block_pos[0] as f32,
// block_pos[1] as f32,
// block_pos[2] as f32,
//);
let block_pos = block_pos.map(|x| x as f32);
if Self::should_emit(state, triggers.get_key_value(&sounds.sfx)) {
// If the camera is within SFX distance
if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR {
sfx_emitter.emit(SfxEventItem::new(sounds.sfx.clone(), Some(block_pos), Some(sounds.volume)));
sfx_emitter.emit(SfxEventItem::new(
sounds.sfx.clone(),
Some(block_pos),
Some(sounds.volume),
));
state.time = Instant::now();
state.event = sounds.sfx.clone();
}
}
}
//// If the timer for this block is over the spacing
//// and the block is in the history
//if self.history.contains_key(&block_pos) {
// if self
// .history
// .get(&block_pos)
// .unwrap() // can't fail as the key is in the hashmap
// .elapsed()
// .as_secs_f32()
// > sounds.spacing
// {
// // Reset timer for this block
// self.history.insert(block_pos, Instant::now());
// // Convert to f32 for distance_squared function
// let block_pos = Vec3::new(
// block_pos[0] as f32,
// block_pos[1] as f32,
// block_pos[2] as f32,
// );
// // If the camera is within SFX distance
// if (block_pos.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR {
// // Emit the sound
// let sfx_trigger_item = triggers.get_trigger(&sounds.sfx);
// if sfx_trigger_item.is_some() {
// ecs.read_resource::<EventBus<SfxEventItem>>().emit_now(
// SfxEventItem::new(
// sounds.sfx.clone(),
// Some(block_pos),
// Some(sounds.volume),
// ),
// );
// }
// }
// }
//} else {
// // Start the timer for this block
// self.history.insert(block_pos, Instant::now());
//}
//}
});
}
}
@ -260,21 +208,4 @@ impl BlockEventMapper {
false
}
}
//fn map_event(&mut self, blocktype: BlockEmitter) -> Option<SfxEvent> {
// if self.timer.elapsed().as_secs_f32() > 1.0 {
// self.timer = Instant::now();
// let sfx_event = match blocktype {
// BlockEmitter::Leaves => Some(SfxEvent::LevelUp),
// BlockEmitter::Grass => Some(SfxEvent::Roll),
// BlockEmitter::Embers => Some(SfxEvent::Roll),
// BlockEmitter::Beehives => Some(SfxEvent::Roll),
// BlockEmitter::Reeds => Some(SfxEvent::Roll),
// BlockEmitter::Flowers => Some(SfxEvent::Roll),
// };
// sfx_event
// } else {
// None
// }
//}
}

View File

@ -10,7 +10,7 @@ use common::{
comp::{Body, CharacterState, PhysicsState, Pos, Vel},
event::EventBus,
state::State,
terrain::TerrainChunk,
terrain::{BlockKind, TerrainChunk},
};
use hashbrown::HashMap;
use specs::{Entity as EcsEntity, Join, WorldExt};
@ -69,38 +69,53 @@ impl EventMapper for MovementEventMapper {
.filter(|(_, e_pos, ..)| (e_pos.0.distance_squared(cam_pos)) < SFX_DIST_LIMIT_SQR)
{
if let Some(character) = character {
let state = self.event_history.entry(entity).or_default();
let internal_state = self.event_history.entry(entity).or_default();
// Get the underfoot block
let block_position = Vec3::new(pos.0.x, pos.0.y, pos.0.z - 1.0).map(|x| x as i32);
let underfoot_block_kind = match state.get_block(block_position) {
Some(block) => block.kind(),
None => BlockKind::Air,
};
let mapped_event = match body {
Body::Humanoid(_) => Self::map_movement_event(character, physics, state, vel.0),
Body::Humanoid(_) => Self::map_movement_event(
character,
physics,
internal_state,
vel.0,
underfoot_block_kind,
),
Body::QuadrupedMedium(_)
| Body::QuadrupedSmall(_)
| Body::QuadrupedLow(_)
| Body::BirdMedium(_)
| Body::BirdSmall(_)
| Body::BipedLarge(_) => Self::map_non_humanoid_movement_event(physics, vel.0),
| Body::BipedLarge(_) => {
Self::map_non_humanoid_movement_event(physics, vel.0, underfoot_block_kind)
},
_ => SfxEvent::Idle, // Ignore fish, etc...
};
// Check for SFX config entry for this movement
if Self::should_emit(state, triggers.get_key_value(&mapped_event)) {
if Self::should_emit(internal_state, triggers.get_key_value(&mapped_event)) {
sfx_emitter.emit(SfxEventItem::new(
mapped_event.clone(),
Some(pos.0),
Some(Self::get_volume_for_body_type(body)),
));
state.time = Instant::now();
internal_state.time = Instant::now();
}
// update state to determine the next event. We only record the time (above) if
// it was dispatched
state.event = mapped_event;
state.on_ground = physics.on_ground;
internal_state.event = mapped_event;
internal_state.on_ground = physics.on_ground;
if physics.in_fluid.is_some() {
state.in_water = true;
internal_state.in_water = true;
} else {
state.in_water = false;
internal_state.in_water = false;
}
}
}
@ -162,11 +177,10 @@ impl MovementEventMapper {
physics_state: &PhysicsState,
previous_state: &PreviousEntityState,
vel: Vec3<f32>,
underfoot_block_kind: BlockKind,
) -> SfxEvent {
// Match run / roll / swim state
if physics_state.in_fluid.is_some()
//&& physics_state.in_fluid.unwrap() < 2.0 // To control different sound based on depth
&& vel.magnitude() > 0.1
if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1
|| !previous_state.in_water && physics_state.in_fluid.is_some()
{
return SfxEvent::Swim;
@ -178,7 +192,10 @@ impl MovementEventMapper {
} else if matches!(character_state, CharacterState::Sneak) {
SfxEvent::Sneak
} else {
SfxEvent::Run
match underfoot_block_kind {
BlockKind::Snow => SfxEvent::SnowRun,
_ => SfxEvent::Run,
}
};
}
@ -198,9 +215,18 @@ impl MovementEventMapper {
}
/// Maps a limited set of movements for other non-humanoid entities
fn map_non_humanoid_movement_event(physics_state: &PhysicsState, vel: Vec3<f32>) -> SfxEvent {
if physics_state.on_ground && vel.magnitude() > 0.1 {
SfxEvent::Run
fn map_non_humanoid_movement_event(
physics_state: &PhysicsState,
vel: Vec3<f32>,
underfoot_block_kind: BlockKind,
) -> SfxEvent {
if physics_state.in_fluid.is_some() && vel.magnitude() > 0.1 {
return SfxEvent::Swim;
} else if physics_state.on_ground && vel.magnitude() > 0.1 {
match underfoot_block_kind {
BlockKind::Snow => SfxEvent::SnowRun,
_ => SfxEvent::Run,
}
} else {
SfxEvent::Idle
}

View File

@ -146,6 +146,7 @@ pub enum SfxEvent {
Idle,
Swim,
Run,
SnowRun,
Roll,
Sneak,
Climb,

View File

@ -1,7 +1,7 @@
use crate::{
column::{ColumnGen, ColumnSample},
util::{RandomField, Sampler, SmallCache},
IndexRef,
IndexRef, CONFIG,
};
use common::terrain::{
structure::{self, StructureBlock},
@ -67,6 +67,7 @@ impl<'a> BlockGen<'a> {
// marble_small,
rock,
// temp,
temp,
// humidity,
stone_col,
..
@ -128,7 +129,9 @@ impl<'a> BlockGen<'a> {
let col = Lerp::lerp(sub_surface_color, surface_color, grass_factor);
// Surface
Some(Block::new(
if grass_factor > 0.7 {
if temp < CONFIG.snow_temp + 0.031 {
BlockKind::Snow
} else if grass_factor > 0.7 {
BlockKind::Grass
} else {
BlockKind::Earth

View File

@ -2303,13 +2303,15 @@ impl SimChunk {
pub fn get_biome(&self) -> BiomeKind {
if self.alt < CONFIG.sea_level {
BiomeKind::Ocean
} else if self.alt > 450.0 && self.chaos > 0.4 && self.tree_density < 0.7 {
BiomeKind::Mountain
} else if self.temp > CONFIG.desert_temp && self.humidity < 0.1 {
BiomeKind::Desert
} else if self.humidity == 0.0 {
BiomeKind::Lake
} else if self.temp < CONFIG.snow_temp {
BiomeKind::Snowland
} else if self.tree_density > 0.65 && self.humidity > 0.9 && self.temp > 0.8 {
} else if self.alt > 450.0 && self.chaos > 0.35 && self.tree_density < 0.7 {
BiomeKind::Mountain
} else if self.temp > CONFIG.desert_temp && self.humidity < 0.6 {
BiomeKind::Desert
} else if self.tree_density > 0.65 && self.humidity > 0.7 && self.temp > 0.8 {
BiomeKind::Jungle
} else if self.tree_density > 0.65 {
BiomeKind::Forest