mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Snow footsteps
This commit is contained in:
parent
09a1974974
commit
9b759efe41
@ -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",
|
||||
|
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_1.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_1.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_2.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_2.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_3.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/footsteps/snow_step_3.wav
(Stored with Git LFS)
Binary file not shown.
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ pub enum SfxEvent {
|
||||
Idle,
|
||||
Swim,
|
||||
Run,
|
||||
SnowRun,
|
||||
Roll,
|
||||
Sneak,
|
||||
Climb,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user