Add new version of combat soundtrack, and change details of how transitions between tracks work.

This commit is contained in:
Avi Weinstock 2021-04-07 15:53:41 -04:00
parent 0e16c23707
commit f1b022cdee
17 changed files with 120 additions and 52 deletions

View File

@ -0,0 +1,6 @@
(
combat_nearby_radius: 40.0,
combat_health_factor: 1000,
combat_nearby_high_thresh: 4,
combat_nearby_low_thresh: 1,
)

View File

@ -374,21 +374,20 @@
artist: "badbbad",
)),
Segmented(
title: "Combat1",
title: "Barred Paths",
author: "DaforLynx",
timing: None,
biomes: [],
site: Some(Dungeon),
segments: [
("voxygen.audio.soundtrack.combat1.combat1-hi-loop", 54.0, State(Combat(High))),
("voxygen.audio.soundtrack.combat1.combat1-hi-start", 55.0, Transition(Explore, Combat(High))),
("voxygen.audio.soundtrack.combat1.combat1-lo-loop", 7.0, State(Combat(Low))),
("voxygen.audio.soundtrack.combat1.combat1-lo-start", 10.0, Transition(Explore, Combat(Low))),
("voxygen.audio.soundtrack.combat1.combat1-trans-hi-lo", 10.0, Transition(Combat(High), Combat(Low))),
("voxygen.audio.soundtrack.combat1.combat1-trans-lo-hi", 7.0, Transition(Combat(Low), Combat(High))),
// temporary until more assets exist:
("voxygen.audio.soundtrack.combat1.combat1-trans-hi-lo", 10.0, Transition(Combat(High), Explore)),
("voxygen.audio.soundtrack.combat1.combat1-lo-loop", 7.0, Transition(Combat(Low), Explore)),
("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-end", 6.0, Transition(Combat(High), Explore), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-loop", 54.0, State(Combat(High)), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-hi-start", 55.0, Transition(Explore, Combat(High)), Some(Combat(High))),
("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-end", 3.0, Transition(Combat(Low), Explore), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-loop", 7.0, State(Combat(Low)), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-lo-start", 10.0, Transition(Explore, Combat(Low)), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-trans-hi-lo", 10.0, Transition(Combat(High), Combat(Low)), None),
("voxygen.audio.soundtrack.barred_paths.barred_paths-trans-lo-hi", 7.0, Transition(Combat(Low), Combat(High)), None),
],
),
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -50,6 +50,7 @@ use common::{
terrain::{BiomeKind, SitesKind},
};
use common_sys::state::State;
use lazy_static::lazy_static;
use rand::{prelude::SliceRandom, thread_rng, Rng};
use serde::Deserialize;
use std::time::Instant;
@ -84,6 +85,11 @@ pub struct SoundtrackItem {
/// What the player is doing when the track is played (i.e. exploring,
/// combat)
activity: MusicActivity,
/// What activity to override the activity state with, if any (e.g. to make
/// a long combat intro also act like the loop for the purposes of outro
/// transitions)
#[serde(default)]
activity_override: Option<MusicActivityState>,
}
#[derive(Clone, Debug, Deserialize)]
@ -94,7 +100,7 @@ enum RawSoundtrackItem {
timing: Option<DayPeriod>,
biomes: Vec<(BiomeKind, u8)>,
site: Option<SitesKind>,
segments: Vec<(String, f32, MusicActivity)>,
segments: Vec<(String, f32, MusicActivity, Option<MusicActivityState>)>,
},
}
@ -146,7 +152,47 @@ pub struct MusicMgr {
/// being played twice in a row
last_track: String,
/// The previous track's activity kind, for transitions
last_activity: MusicActivityState,
last_activity: MusicActivity,
}
#[derive(Deserialize)]
struct MusicTransitionManifest {
/// Within what radius do enemies count towards combat music?
combat_nearby_radius: f32,
/// Each multiple of this factor that an enemy has health counts as an extra
/// enemy
combat_health_factor: u32,
/// How many nearby enemies trigger High combat music
combat_nearby_high_thresh: u32,
/// How many nearby enemies trigger Low combat music
combat_nearby_low_thresh: u32,
}
impl Default for MusicTransitionManifest {
fn default() -> MusicTransitionManifest {
MusicTransitionManifest {
combat_nearby_radius: 40.0,
combat_health_factor: 1000,
combat_nearby_high_thresh: 3,
combat_nearby_low_thresh: 1,
}
}
}
impl assets::Asset for MusicTransitionManifest {
type Loader = assets::RonLoader;
const EXTENSION: &'static str = "ron";
fn default_value(id: &str, e: assets::Error) -> Result<MusicTransitionManifest, assets::Error> {
warn!("Error loading MusicTransitionManifest {:?}: {:?}", id, e);
Ok(MusicTransitionManifest::default())
}
}
lazy_static! {
static ref MUSIC_TRANSITION_MANIFEST: AssetHandle<MusicTransitionManifest> =
AssetExt::load_expect("voxygen.audio.music_transition_manifest");
}
impl Default for MusicMgr {
@ -156,7 +202,7 @@ impl Default for MusicMgr {
began_playing: Instant::now(),
next_track_change: 0.0,
last_track: String::from("None"),
last_activity: MusicActivityState::Explore,
last_activity: MusicActivity::State(MusicActivityState::Explore),
}
}
}
@ -185,34 +231,41 @@ impl MusicMgr {
let positions = ecs.read_component::<Pos>();
let healths = ecs.read_component::<Health>();
let groups = ecs.read_component::<Group>();
let mtm = MUSIC_TRANSITION_MANIFEST.read();
if let Some(player_pos) = positions.get(player) {
const NEARBY_RADIUS: f32 = 50.0;
const HEALTH_FACTOR: u32 = 100;
let num_nearby_entities: u32 = (&entities, &positions, &healths, &groups)
.join()
.map(|(entity, pos, health, group)| {
if entity != player
&& group == &ENEMY
&& (player_pos.0 - pos.0).magnitude_squared() < NEARBY_RADIUS.powf(2.0)
&& (player_pos.0 - pos.0).magnitude_squared()
< mtm.combat_nearby_radius.powf(2.0)
{
(health.maximum() / HEALTH_FACTOR).max(1)
(health.maximum() / mtm.combat_health_factor).max(1)
} else {
0
}
})
.sum();
if num_nearby_entities > 2 {
if num_nearby_entities >= mtm.combat_nearby_high_thresh {
activity_state = Combat(CombatIntensity::High);
} else if num_nearby_entities >= 1 {
} else if num_nearby_entities >= mtm.combat_nearby_low_thresh {
activity_state = Combat(CombatIntensity::Low);
}
trace!(
"in audio maintain: {:?} {:?}",
activity_state,
num_nearby_entities
);
}
let activity = if self.last_activity != activity_state {
MusicActivity::Transition(self.last_activity, activity_state)
} else {
MusicActivity::State(activity_state)
let activity = match self.last_activity {
MusicActivity::State(prev) if prev != activity_state => {
MusicActivity::Transition(prev, activity_state)
},
MusicActivity::Transition(_, next) => MusicActivity::State(next),
_ => MusicActivity::State(activity_state),
};
let interrupt = matches!(activity, MusicActivity::Transition(_, _));
@ -221,9 +274,13 @@ impl MusicMgr {
&& !self.soundtrack.read().tracks.is_empty()
&& (self.began_playing.elapsed().as_secs_f32() > self.next_track_change || interrupt)
{
trace!("in audio maintain: {:?} {:?}", self.last_activity, activity);
if let Ok(()) = self.play_random_track(audio, state, client, &activity) {
self.last_activity = activity_state;
trace!(
"pre-play_random_track: {:?} {:?}",
self.last_activity,
activity
);
if let Ok(next_activity) = self.play_random_track(audio, state, client, &activity) {
self.last_activity = next_activity;
}
}
}
@ -234,7 +291,7 @@ impl MusicMgr {
state: &State,
client: &Client,
activity: &MusicActivity,
) -> Result<(), ()> {
) -> Result<MusicActivity, ()> {
let mut rng = thread_rng();
// Adds a bit of randomness between plays
@ -254,7 +311,7 @@ impl MusicMgr {
// too many constraints. Returning Err(()) signals that we couldn't find
// an appropriate track for the current state, and hence the state
// machine for the activity shouldn't be updated.
let mut res = Ok(());
let mut res = Ok(*activity);
let soundtrack = self.soundtrack.read();
// First, filter out tracks not matching the timing, site, and biome
let mut maybe_tracks = soundtrack
@ -339,16 +396,15 @@ impl MusicMgr {
);
if let Ok(track) = new_maybe_track {
if let Some(state) = track.activity_override {
res = Ok(MusicActivity::State(state));
}
//println!("Now playing {:?}", track.title);
self.last_track = String::from(&track.title);
self.began_playing = Instant::now();
self.next_track_change = track.length + silence_between_tracks_seconds;
let tag = if matches!(
activity,
MusicActivity::State(MusicActivityState::Explore)
| MusicActivity::Transition(_, MusicActivityState::Explore)
) {
let tag = if matches!(activity, MusicActivity::State(MusicActivityState::Explore)) {
MusicChannelTag::Exploration
} else {
MusicChannelTag::Combat
@ -398,7 +454,7 @@ impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
site,
segments,
} => {
for (path, length, activity) in segments.into_iter() {
for (path, length, activity, activity_override) in segments.into_iter() {
soundtracks.tracks.push(SoundtrackItem {
title: title.clone(),
path,
@ -407,6 +463,7 @@ impl assets::Compound for SoundtrackCollection<SoundtrackItem> {
biomes: biomes.clone(),
site,
activity,
activity_override,
});
}
},