Quadraped footsteps and songs in biomes

This commit is contained in:
jiminycrick 2020-11-11 00:51:14 -08:00
parent 27dc43fe18
commit a684bc90fd
12 changed files with 262 additions and 163 deletions

View File

@ -38,6 +38,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upscaling support - Upscaling support
- Added "Persist Combo from Combo Melee State" when rolling mid-combo - Added "Persist Combo from Combo Melee State" when rolling mid-combo
- You can no longer spam hammer and bow special when stamina is 0 - You can no longer spam hammer and bow special when stamina is 0
- Biome and site specific music system
- Ambient SFX emitted from terrain blocks
- Campfire SFX
- Wind SFX system
### Changed ### Changed

BIN
assets/voxygen/audio/ambient/wind.ogg (Stored with Git LFS)

Binary file not shown.

View File

@ -75,6 +75,17 @@
], ],
threshold: 0.25, threshold: 0.25,
), ),
QuadRun: (
files: [
"voxygen.audio.sfx.footsteps.stepgrass_1",
"voxygen.audio.sfx.footsteps.stepgrass_2",
"voxygen.audio.sfx.footsteps.stepgrass_3",
"voxygen.audio.sfx.footsteps.stepgrass_4",
"voxygen.audio.sfx.footsteps.stepgrass_5",
"voxygen.audio.sfx.footsteps.stepgrass_6",
],
threshold: 0.12,
),
SnowRun: ( SnowRun: (
files: [ files: [
"voxygen.audio.sfx.footsteps.snow_step_1", "voxygen.audio.sfx.footsteps.snow_step_1",
@ -83,6 +94,14 @@
], ],
threshold: 0.25, threshold: 0.25,
), ),
QuadSnowRun: (
files: [
"voxygen.audio.sfx.footsteps.snow_step_1",
"voxygen.audio.sfx.footsteps.snow_step_2",
"voxygen.audio.sfx.footsteps.snow_step_3",
],
threshold: 0.12,
),
ExperienceGained: ( ExperienceGained: (
files: [ files: [
// "voxygen.audio.sfx.character.experience_gained_1", // "voxygen.audio.sfx.character.experience_gained_1",
@ -214,7 +233,7 @@
], ],
threshold: 0.5, threshold: 0.5,
), ),
Attack(BasicMelee, Hammer): ( Attack(ComboMelee(Swing, 1), Hammer): (
files: [ files: [
"voxygen.audio.sfx.abilities.swing", "voxygen.audio.sfx.abilities.swing",
], ],
@ -254,7 +273,13 @@
], ],
threshold: 0.5, threshold: 0.5,
), ),
Attack(BasicMelee, Axe): ( Attack(ComboMelee(Swing, 1), Axe): (
files: [
"voxygen.audio.sfx.abilities.swing",
],
threshold: 0.7,
),
Attack(ComboMelee(Swing, 2), Axe): (
files: [ files: [
"voxygen.audio.sfx.abilities.swing", "voxygen.audio.sfx.abilities.swing",
], ],

View File

@ -1,139 +1,174 @@
// TODO: Re-add tunes that are not fitting general outside day/night situations // TODO: Re-add tunes that are not fitting general outside day/night situations
// TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack // TODO: Add an ambient-soundtrack that runs independently from the musical soundtrack
//Times: Some(Day), Some(Night), None
( //List of biomes currently: Grassland, Forest, Jungle, Desert, Snowland, Lake, Mountain
tracks: [ //Sites: Cave, Dungeon
(
title: "A Solemn Quest", (
path: "voxygen.audio.soundtrack.a_solemn_quest", tracks: [
length: 206.0, (
timing: Some(Day), title: "A Solemn Quest",
biomes: [ path: "voxygen.audio.soundtrack.a_solemn_quest",
(Lake, 1), length: 206.0,
(Grassland, 1), timing: Some(Night),
], biomes: [
site: None, (Jungle, 1),
artist: "Eden", (Desert, 1),
), (Grassland, 1),
( (Snowland, 1),
title: "Into The Dark Forest", (Mountain, 1),
path: "voxygen.audio.soundtrack.into_the_dark_forest", (Lake, 1),
length: 184.0, ],
timing: Some(Day), site: Some(Void),
biomes: [ artist: "Eden",
(Forest, 1), ),
(Jungle, 1), (
], title: "Into The Dark Forest",
site: None, path: "voxygen.audio.soundtrack.into_the_dark_forest",
artist: "Aeronic", length: 184.0,
), timing: Some(Night),
( biomes: [
title: "Field Grazing", (Forest, 1),
path: "voxygen.audio.soundtrack.field_grazing", (Jungle, 1),
length: 154.0, ],
timing: Some(Day), site: Some(Void),
biomes: [], artist: "Aeronic",
site: None, ),
artist: "Aeronic", (
), title: "Field Grazing",
//( path: "voxygen.audio.soundtrack.field_grazing",
// title: "Wandering Voices", length: 154.0,
// path: "voxygen.audio.soundtrack.wandering_voices", timing: Some(Day),
// length: 137.0, biomes: [
// timing: Some(Day), (Grassland, 1),
// biome: Some(Desert), ],
// site: None, site: Some(Void),
// artist: "Aeronic", artist: "Aeronic",
//), ),
//( (
// title: "Snowtop Volume", //Snow Region title: "Wandering Voices",
// path: "voxygen.audio.soundtrack.snowtop_volume", path: "voxygen.audio.soundtrack.wandering_voices",
// length: 89.0, length: 137.0,
// timing: Some(Day), timing: Some(Night),
// biome: Some(Desert), biomes: [],
// site: None, site: Some(Void),
// artist: "Aeronic", artist: "Aeronic",
//), ),
//( (
// title: "Mineral Deposits", title: "Snowtop Volume",
// path: "voxygen.audio.soundtrack.mineral_deposits", path: "voxygen.audio.soundtrack.snowtop_volume",
// length: 148.0, length: 89.0,
// timing: Some(Day), timing: None,
// biome: Some(Desert), biomes: [
// site: None, (Snowland, 1),
// artist: "Aeronic", (Mountain, 1),
//), ],
//( site: Some(Void),
// title: "Moonbeams", artist: "Aeronic",
// path: "voxygen.audio.soundtrack.moonbeams", ),
// length: 158.0, (
// timing: Some(Night), title: "Mineral Deposits",
// biome: Some(Desert), path: "voxygen.audio.soundtrack.mineral_deposits",
// site: None, length: 148.0,
// artist: "Aeronic", timing: None,
//), biomes: [],
//( site: Some(Cave),
// title: "Serene Meadows", artist: "Aeronic",
// path: "voxygen.audio.soundtrack.serene_meadows", ),
// length: 173.0, (
// timing: Some(Night), title: "Moonbeams",
// biome: Some(Desert), path: "voxygen.audio.soundtrack.moonbeams",
// site: None, length: 158.0,
// artist: "Aeronic", timing: Some(Night),
//), biomes: [],
///*( site: Some(Void),
// title: "Rest Assured", // Town/Shop artist: "Aeronic",
// path: "voxygen.audio.soundtrack.rest_assured", ),
// length: 185.0, (
// timing: Some(Day), title: "Serene Meadows",
// biome: Some(Desert), path: "voxygen.audio.soundtrack.serene_meadows",
// site: None, length: 173.0,
// artist: "badbbad", timing: Some(Night),
//),*/ biomes: [
//( (Forest, 1),
// title: "Just The Beginning", (Grassland, 1),
// path: "voxygen.audio.soundtrack.just_the_beginning", ],
// length: 188.0, site: Some(Void),
// timing: Some(Day), artist: "Aeronic",
// biome: Some(Desert), ),
// site: None, //(
// artist: "badbbad", // title: "Rest Assured", // Town/Shop
//), // path: "voxygen.audio.soundtrack.rest_assured",
//( // length: 185.0,
// title: "Campfire Stories", // timing: Some(Day),
// path: "voxygen.audio.soundtrack.campfire_stories", // biomes: [],
// length: 100.0, // site: Some(Void),
// timing: Some(Night), // artist: "badbbad",
// biome: Some(Desert), //),
// site: None, (
// artist: "badbbad", title: "Just The Beginning",
//), path: "voxygen.audio.soundtrack.just_the_beginning",
( length: 188.0,
title: "Limits", timing: Some(Day),
path: "voxygen.audio.soundtrack.limits", biomes: [
length: 203.0, (Grassland, 1),
timing: None, (Snowland, 1),
biomes: [], (Mountain, 1),
site: Some(Dungeon), ],
artist: "badbbad", site: Some(Void),
), artist: "badbbad",
( // Dungeon ),
title: "Down The Rabbit Hole", (
path: "voxygen.audio.soundtrack.down_the_rabbit_hole", title: "Campfire Stories",
length: 244.0, path: "voxygen.audio.soundtrack.campfire_stories",
timing: None, length: 100.0,
biomes: [], timing: Some(Night),
site: Some(Cave), biomes: [],
artist: "badbbad", site: Some(Void),
), artist: "badbbad",
//( ),
// title: "Between The Fairies", (
// path: "voxygen.audio.soundtrack.between_the_fairies", title: "Limits",
// length: 175.0, path: "voxygen.audio.soundtrack.limits",
// timing: None, length: 203.0,
// biomes: [], timing: None,
// site: Some(Cave), biomes: [
// artist: "badbbad", (Desert, 1),
//), (Lake, 1)
] ],
) site: Some(Void),
artist: "badbbad",
),
(
title: "Down The Rabbit Hole",
path: "voxygen.audio.soundtrack.down_the_rabbit_hole",
length: 244.0,
timing: None,
biomes: [],
site: Some(Cave),
artist: "badbbad",
),
( //Repeat for other site
title: "Down The Rabbit Hole",
path: "voxygen.audio.soundtrack.down_the_rabbit_hole",
length: 244.0,
timing: None,
biomes: [],
site: Some(Dungeon),
artist: "badbbad",
),
(
title: "Between The Fairies",
path: "voxygen.audio.soundtrack.between_the_fairies",
length: 175.0,
timing: Some(Night),
biomes: [
(Forest, 1),
(Lake, 1),
(Snowland, 1),
],
site: Some(Void),
artist: "badbbad",
)
]
)

View File

@ -858,7 +858,13 @@ impl Client {
} }
pub fn current_position(&self) -> Option<Vec3<f32>> { pub fn current_position(&self) -> Option<Vec3<f32>> {
Some(self.state.read_storage::<comp::Pos>().get(self.entity).cloned()?.0) Some(
self.state
.read_storage::<comp::Pos>()
.get(self.entity)
.cloned()?
.0,
)
} }
pub fn inventories(&self) -> ReadStorage<comp::Inventory> { self.state.read_storage() } pub fn inventories(&self) -> ReadStorage<comp::Inventory> { self.state.read_storage() }

View File

@ -6,5 +6,5 @@ pub enum SitesKind {
Cave, Cave,
Settlement, Settlement,
Castle, Castle,
None, Void,
} }

View File

@ -11,10 +11,9 @@ use channel::{MusicChannel, MusicChannelTag, SfxChannel, WindChannel};
use fader::Fader; use fader::Fader;
use soundcache::SoundCache; use soundcache::SoundCache;
use std::time::Duration; use std::time::Duration;
use tracing::warn; //use tracing::warn;
use common::assets; use common::assets;
//use cpal::traits::{DeviceTrait, HostTrait};
use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError}; use rodio::{source::Source, Decoder, OutputStream, OutputStreamHandle, StreamError};
use vek::*; use vek::*;
@ -32,6 +31,7 @@ pub struct Listener {
/// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to /// Voxygen's [`GlobalState`](../struct.GlobalState.html#structfield.audio) to
/// provide access to devices and playback control in-game /// provide access to devices and playback control in-game
pub struct AudioFrontend { pub struct AudioFrontend {
// The following is for the disabled device switcher
//pub device: String, //pub device: String,
//pub device_list: Vec<String>, //pub device_list: Vec<String>,
//pub audio_device: Option<Device>, //pub audio_device: Option<Device>,
@ -70,6 +70,7 @@ impl AudioFrontend {
}; };
Self { Self {
// The following is for the disabled device switcher
//device, //device,
//device_list: list_devices(), //device_list: list_devices(),
//audio_device, //audio_device,
@ -88,6 +89,7 @@ impl AudioFrontend {
/// Construct in `no-audio` mode for debugging /// Construct in `no-audio` mode for debugging
pub fn no_audio() -> Self { pub fn no_audio() -> Self {
Self { Self {
// The following is for the disabled device switcher
//device: "".to_string(), //device: "".to_string(),
//device_list: Vec::new(), //device_list: Vec::new(),
//audio_device: None, //audio_device: None,
@ -211,7 +213,7 @@ impl AudioFrontend {
fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> { fn get_wind_channel(&mut self, volume_multiplier: f32) -> Option<&mut WindChannel> {
if self.audio_stream.is_some() { if self.audio_stream.is_some() {
if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { if let Some(channel) = self.wind_channels.iter_mut().last() {
channel.set_volume(self.sfx_volume * volume_multiplier); channel.set_volume(self.sfx_volume * volume_multiplier);
return Some(channel); return Some(channel);
@ -223,7 +225,7 @@ impl AudioFrontend {
fn set_wind_volume(&mut self, volume_multiplier: f32) { fn set_wind_volume(&mut self, volume_multiplier: f32) {
if self.audio_stream.is_some() { if self.audio_stream.is_some() {
if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { if let Some(channel) = self.wind_channels.iter_mut().last() {
channel.set_volume(self.sfx_volume * volume_multiplier); channel.set_volume(self.sfx_volume * volume_multiplier);
} }
} }
@ -231,7 +233,7 @@ impl AudioFrontend {
fn get_wind_volume(&mut self) -> f32 { fn get_wind_volume(&mut self) -> f32 {
if self.audio_stream.is_some() { if self.audio_stream.is_some() {
if let Some(channel) = self.wind_channels.iter_mut().find(|_c| true) { if let Some(channel) = self.wind_channels.iter_mut().last() {
channel.get_volume() / self.sfx_volume channel.get_volume() / self.sfx_volume
} else { } else {
0.0 0.0
@ -344,6 +346,7 @@ impl AudioFrontend {
} }
} }
// The following is for the disabled device switcher
//// TODO: figure out how badly this will break things when it is called //// TODO: figure out how badly this will break things when it is called
//pub fn set_device(&mut self, name: String) { //pub fn set_device(&mut self, name: String) {
// self.device = name.clone(); // self.device = name.clone();
@ -351,6 +354,7 @@ impl AudioFrontend {
//} //}
} }
// The following is for the disabled device switcher
///// Returns the default audio device. ///// Returns the default audio device.
///// Does not return rodio Device struct in case our audio backend changes. ///// Does not return rodio Device struct in case our audio backend changes.
//pub fn get_default_device() -> Option<String> { //pub fn get_default_device() -> Option<String> {
@ -365,6 +369,7 @@ pub fn get_default_stream() -> Result<(OutputStream, OutputStreamHandle), Stream
rodio::OutputStream::try_default() rodio::OutputStream::try_default()
} }
// The following is for the disabled device switcher
///// Returns a stream on the specified device ///// Returns a stream on the specified device
//pub fn get_stream( //pub fn get_stream(
// device: &rodio::Device, // device: &rodio::Device,

View File

@ -26,7 +26,11 @@
//! path: "voxygen.audio.soundtrack.sleepy", //! path: "voxygen.audio.soundtrack.sleepy",
//! length: 400.0, //! length: 400.0,
//! timing: Some(Night), //! timing: Some(Night),
//! biome: Some(Forest), //! biome: [
//! (Forest, 1),
//! (Grassland, 2),
//! ],
//! site: None,
//! artist: "Elvis", //! artist: "Elvis",
//! ), //! ),
//! ``` //! ```
@ -129,8 +133,9 @@ impl MusicMgr {
//println!("chaos: {}", current_chunk.meta().chaos()); //println!("chaos: {}", current_chunk.meta().chaos());
//println!("alt: {}", current_chunk.meta().alt()); //println!("alt: {}", current_chunk.meta().alt());
//println!("temp: {}", current_chunk.meta().temp()); //println!("temp: {}", current_chunk.meta().temp());
//println!("tree_density: {}", current_chunk.meta().tree_density()); //println!("tree_density: {}",
//println!("humidity: {}", current_chunk.meta().humidity()); // current_chunk.meta().tree_density());
// println!("humidity: {}", current_chunk.meta().humidity());
//println!("cave_alt: {}", current_chunk.meta().cave_alt()); //println!("cave_alt: {}", current_chunk.meta().cave_alt());
//if let Some(position) = client.current_position() { //if let Some(position) = client.current_position() {
// println!("player_pos: {:?}", position); // println!("player_pos: {:?}", position);
@ -163,7 +168,7 @@ impl MusicMgr {
let mut rng = thread_rng(); let mut rng = thread_rng();
// Adds a bit of randomness between plays // Adds a bit of randomness between plays
let silence_between_tracks_seconds: f32 = rng.gen_range(30.0, 60.0); let silence_between_tracks_seconds: f32 = rng.gen_range(15.0, 60.0);
let game_time = (state.get_time_of_day() as u64 % 86400) as u32; 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); let current_period_of_day = Self::get_current_day_period(game_time);
@ -221,6 +226,7 @@ impl MusicMgr {
}); });
if let Ok(track) = new_maybe_track { if let Ok(track) = new_maybe_track {
println!("Now playing {:?}", track.title);
self.last_track = String::from(&track.title); self.last_track = String::from(&track.title);
self.began_playing = Instant::now(); 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;
@ -260,7 +266,7 @@ impl MusicMgr {
} else if player_alt < (terrain_alt - 20.0) { } else if player_alt < (terrain_alt - 20.0) {
SitesKind::Dungeon SitesKind::Dungeon
} else { } else {
SitesKind::None SitesKind::Void
} }
} }

View File

@ -88,12 +88,10 @@ impl EventMapper for MovementEventMapper {
vel.0, vel.0,
underfoot_block_kind, underfoot_block_kind,
), ),
Body::QuadrupedMedium(_) Body::QuadrupedMedium(_) | Body::QuadrupedSmall(_) | Body::QuadrupedLow(_) => {
| Body::QuadrupedSmall(_) Self::map_quadruped_movement_event(physics, vel.0, underfoot_block_kind)
| Body::QuadrupedLow(_) },
| Body::BirdMedium(_) Body::BirdMedium(_) | Body::BirdSmall(_) | Body::BipedLarge(_) => {
| Body::BirdSmall(_)
| Body::BipedLarge(_) => {
Self::map_non_humanoid_movement_event(physics, vel.0, underfoot_block_kind) Self::map_non_humanoid_movement_event(physics, vel.0, underfoot_block_kind)
}, },
_ => SfxEvent::Idle, // Ignore fish, etc... _ => SfxEvent::Idle, // Ignore fish, etc...
@ -234,6 +232,24 @@ impl MovementEventMapper {
} }
} }
/// Maps a limited set of movements for quadruped entities
fn map_quadruped_movement_event(
physics_state: &PhysicsState,
vel: Vec3<f32>,
underfoot_block_kind: BlockKind,
) -> SfxEvent {
if physics_state.in_liquid.is_some() && vel.magnitude() > 0.1 {
SfxEvent::Swim
} else if physics_state.on_ground && vel.magnitude() > 0.1 {
match underfoot_block_kind {
BlockKind::Snow => SfxEvent::QuadSnowRun,
_ => SfxEvent::QuadRun,
}
} else {
SfxEvent::Idle
}
}
/// Returns a relative volume value for a body type. This helps us emit sfx /// Returns a relative volume value for a body type. This helps us emit sfx
/// at a volume appropriate fot the entity we are emitting the event for /// at a volume appropriate fot the entity we are emitting the event for
fn get_volume_for_body_type(body: &Body) -> f32 { fn get_volume_for_body_type(body: &Body) -> f32 {

View File

@ -151,7 +151,9 @@ pub enum SfxEvent {
Idle, Idle,
Swim, Swim,
Run, Run,
QuadRun,
SnowRun, SnowRun,
QuadSnowRun,
Roll, Roll,
Sneak, Sneak,
Climb, Climb,

View File

@ -101,7 +101,7 @@ impl WindMgr {
{ {
volume_multiplier *= volume_multiplier; volume_multiplier *= volume_multiplier;
} }
if cam_pos.z < Self::get_current_terrain_alt(client) - 20.0 { if cam_pos.z < Self::get_current_terrain_alt(client) - 10.0 {
volume_multiplier = 0.0; volume_multiplier = 0.0;
} }

View File

@ -2303,7 +2303,7 @@ impl SimChunk {
pub fn get_biome(&self) -> BiomeKind { pub fn get_biome(&self) -> BiomeKind {
if self.alt < CONFIG.sea_level { if self.alt < CONFIG.sea_level {
BiomeKind::Ocean BiomeKind::Ocean
} else if self.humidity == 0.0 { } else if self.humidity == 0.5 {
BiomeKind::Lake BiomeKind::Lake
} else if self.temp < CONFIG.snow_temp { } else if self.temp < CONFIG.snow_temp {
BiomeKind::Snowland BiomeKind::Snowland