mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Docs, make adding event mappers easier for sfx, remove placeholder
sounds.
This commit is contained in:
parent
467c154582
commit
6a1cec8860
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Added inventory, armour and weapon saving
|
||||
- Show where screenshots are saved to in the chat
|
||||
- Added basic auto walk
|
||||
- Added weapon/attack sound effects
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -23,64 +23,6 @@
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(DashMelee, Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_03",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_04",
|
||||
],
|
||||
threshold: 1.2,
|
||||
),
|
||||
Attack(TripleStrike(First), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_03",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_04",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(TripleStrike(Second), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_03",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(TripleStrike(Third), Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_03",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(BasicRanged, Bow): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.bow_attack_01",
|
||||
"voxygen.audio.sfx.weapon.bow_attack_02",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(BasicMelee, Hammer): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_low_03",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(BasicMelee, Staff): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_01",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_02",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_03",
|
||||
"voxygen.audio.sfx.weapon.whoosh_normal_04",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Wield(Sword): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.sword_out",
|
||||
|
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_01.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_01.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_02.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_02.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/sword_in.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/sword_in.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/sword_out.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/sword_out.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_01.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_01.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_02.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_02.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_03.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/sword_triple_strike_03.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_01.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_01.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_02.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_02.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_03.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_low_03.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_01.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_01.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_02.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_02.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_03.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_03.wav
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_04.wav
(Stored with Git LFS)
BIN
assets/voxygen/audio/sfx/weapon/whoosh_normal_04.wav
(Stored with Git LFS)
Binary file not shown.
@ -1,7 +1,9 @@
|
||||
/// event_mapper::combat watches the combat state of entities and emits
|
||||
/// associated sfx events
|
||||
/// EventMapper::Combat watches the combat states of surrounding entities' and
|
||||
/// emits sfx related to weapons and attacks/abilities
|
||||
use crate::audio::sfx::{SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR};
|
||||
|
||||
use super::EventMapper;
|
||||
|
||||
use common::{
|
||||
comp::{
|
||||
item::{Item, ItemKind, ToolCategory},
|
||||
@ -36,14 +38,8 @@ pub struct CombatEventMapper {
|
||||
event_history: HashMap<EcsEntity, PreviousEntityState>,
|
||||
}
|
||||
|
||||
impl CombatEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
event_history: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, state: &State, player_entity: EcsEntity, triggers: &SfxTriggers) {
|
||||
impl EventMapper for CombatEventMapper {
|
||||
fn maintain(&mut self, state: &State, player_entity: EcsEntity, triggers: &SfxTriggers) {
|
||||
let ecs = state.ecs();
|
||||
|
||||
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
|
||||
@ -89,6 +85,14 @@ impl CombatEventMapper {
|
||||
|
||||
self.cleanup(player_entity);
|
||||
}
|
||||
}
|
||||
|
||||
impl CombatEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
event_history: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// As the player explores the world, we track the last event of the nearby
|
||||
/// entities to determine the correct SFX item to play next based on
|
||||
@ -105,11 +109,10 @@ impl CombatEventMapper {
|
||||
});
|
||||
}
|
||||
|
||||
/// When specific entity movements are detected, the associated sound (if
|
||||
/// any) needs to satisfy two conditions to be allowed to play:
|
||||
/// 1. An sfx.ron entry exists for the movement (we need to know which sound
|
||||
/// file(s) to play) 2. The sfx has not been played since it's timeout
|
||||
/// threshold has elapsed, which prevents firing every tick
|
||||
/// Ensures that:
|
||||
/// 1. An sfx.ron entry exists for an SFX event
|
||||
/// 2. The sfx has not been played since it's timeout threshold has elapsed,
|
||||
/// which prevents firing every tick
|
||||
fn should_emit(
|
||||
previous_state: &PreviousEntityState,
|
||||
sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
|
||||
|
@ -98,7 +98,7 @@ fn maps_basic_melee() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_triple_strike() {
|
||||
fn matches_ability_stage() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
@ -131,6 +131,50 @@ fn maps_triple_strike() {
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
SfxEvent::Attack(CharacterAbilityType::TripleStrike, ToolCategory::Sword)
|
||||
SfxEvent::Attack(
|
||||
CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First),
|
||||
ToolCategory::Sword
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_different_ability_stage() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.sword.starter_sword"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::TripleStrike(states::triple_strike::Data {
|
||||
base_damage: 10,
|
||||
stage: states::triple_strike::Stage::Second,
|
||||
stage_time_active: Duration::default(),
|
||||
stage_exhausted: false,
|
||||
initialized: true,
|
||||
transition_style: states::triple_strike::TransitionStyle::Hold(
|
||||
states::triple_strike::HoldingState::Released,
|
||||
),
|
||||
}),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: true,
|
||||
},
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_ne!(
|
||||
result,
|
||||
SfxEvent::Attack(
|
||||
CharacterAbilityType::TripleStrike(states::triple_strike::Stage::First),
|
||||
ToolCategory::Sword
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -10,18 +10,22 @@ use progression::ProgressionEventMapper;
|
||||
|
||||
use super::SfxTriggers;
|
||||
|
||||
trait EventMapper {
|
||||
fn maintain(&mut self, state: &State, player_entity: specs::Entity, triggers: &SfxTriggers);
|
||||
}
|
||||
|
||||
pub struct SfxEventMapper {
|
||||
progression: ProgressionEventMapper,
|
||||
movement: MovementEventMapper,
|
||||
combat: CombatEventMapper,
|
||||
mappers: Vec<Box<dyn EventMapper>>,
|
||||
}
|
||||
|
||||
impl SfxEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
progression: ProgressionEventMapper::new(),
|
||||
combat: CombatEventMapper::new(),
|
||||
movement: MovementEventMapper::new(),
|
||||
mappers: vec![
|
||||
Box::new(CombatEventMapper::new()),
|
||||
Box::new(MovementEventMapper::new()),
|
||||
Box::new(ProgressionEventMapper::new()),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,8 +35,8 @@ impl SfxEventMapper {
|
||||
player_entity: specs::Entity,
|
||||
triggers: &SfxTriggers,
|
||||
) {
|
||||
self.progression.maintain(state, player_entity, triggers);
|
||||
self.movement.maintain(state, player_entity, triggers);
|
||||
self.combat.maintain(state, player_entity, triggers);
|
||||
for mapper in &mut self.mappers {
|
||||
mapper.maintain(state, player_entity, triggers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
/// event_mapper::movement watches all local entities movements and determines
|
||||
/// which sfx to emit, and the position at which the sound should be emitted
|
||||
/// from
|
||||
use crate::audio::sfx::{SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR};
|
||||
/// EventMapper::Movement watches the movement states of surrounding entities,
|
||||
/// and triggers sfx related to running, climbing and gliding, at a volume
|
||||
/// proportionate to the extity's size
|
||||
use super::EventMapper;
|
||||
|
||||
use crate::audio::sfx::{SfxTriggerItem, SfxTriggers, SFX_DIST_LIMIT_SQR};
|
||||
use common::{
|
||||
comp::{Body, CharacterState, PhysicsState, Pos, Vel},
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
@ -34,14 +35,8 @@ pub struct MovementEventMapper {
|
||||
event_history: HashMap<EcsEntity, PreviousEntityState>,
|
||||
}
|
||||
|
||||
impl MovementEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
event_history: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maintain(&mut self, state: &State, player_entity: EcsEntity, triggers: &SfxTriggers) {
|
||||
impl EventMapper for MovementEventMapper {
|
||||
fn maintain(&mut self, state: &State, player_entity: EcsEntity, triggers: &SfxTriggers) {
|
||||
let ecs = state.ecs();
|
||||
|
||||
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
|
||||
@ -101,6 +96,14 @@ impl MovementEventMapper {
|
||||
|
||||
self.cleanup(player_entity);
|
||||
}
|
||||
}
|
||||
|
||||
impl MovementEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
event_history: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// As the player explores the world, we track the last event of the nearby
|
||||
/// entities to determine the correct SFX item to play next based on
|
||||
|
@ -1,122 +0,0 @@
|
||||
/// event_mapper::progression watches the the current player's level
|
||||
/// and experience and emits associated SFX
|
||||
use crate::audio::sfx::SfxTriggers;
|
||||
|
||||
use common::{
|
||||
comp::Stats,
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
state::State,
|
||||
};
|
||||
use specs::WorldExt;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct ProgressionState {
|
||||
level: u32,
|
||||
exp: u32,
|
||||
}
|
||||
|
||||
impl Default for ProgressionState {
|
||||
fn default() -> Self { Self { level: 1, exp: 0 } }
|
||||
}
|
||||
|
||||
pub struct ProgressionEventMapper {
|
||||
state: ProgressionState,
|
||||
}
|
||||
|
||||
impl ProgressionEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: ProgressionState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maintain(
|
||||
&mut self,
|
||||
state: &State,
|
||||
player_entity: specs::Entity,
|
||||
triggers: &SfxTriggers,
|
||||
) {
|
||||
let ecs = state.ecs();
|
||||
|
||||
// level and exp changes
|
||||
let next_state =
|
||||
ecs.read_storage::<Stats>()
|
||||
.get(player_entity)
|
||||
.map_or(self.state.clone(), |stats| ProgressionState {
|
||||
level: stats.level.level(),
|
||||
exp: stats.exp.current(),
|
||||
});
|
||||
|
||||
if &self.state != &next_state {
|
||||
if let Some(mapped_event) = self.map_event(&next_state) {
|
||||
let sfx_trigger_item = triggers.get_trigger(&mapped_event);
|
||||
|
||||
if sfx_trigger_item.is_some() {
|
||||
ecs.read_resource::<EventBus<SfxEventItem>>()
|
||||
.emit_now(SfxEventItem::at_player_position(mapped_event));
|
||||
}
|
||||
}
|
||||
|
||||
self.state = next_state;
|
||||
}
|
||||
}
|
||||
|
||||
fn map_event(&mut self, next_state: &ProgressionState) -> Option<SfxEvent> {
|
||||
let sfx_event = if next_state.level > self.state.level {
|
||||
Some(SfxEvent::LevelUp)
|
||||
} else if next_state.exp > self.state.exp {
|
||||
Some(SfxEvent::ExperienceGained)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
sfx_event
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use common::event::SfxEvent;
|
||||
|
||||
#[test]
|
||||
fn no_change_returns_none() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState::default();
|
||||
|
||||
assert_eq!(mapper.map_event(&next_client_state), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_level_returns_levelup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 2, exp: 0 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::LevelUp)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_exp_returns_expup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 1, exp: 100 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::ExperienceGained)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level_up_and_gained_exp_prioritises_levelup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 2, exp: 100 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::LevelUp)
|
||||
);
|
||||
}
|
||||
}
|
75
voxygen/src/audio/sfx/event_mapper/progression/mod.rs
Normal file
75
voxygen/src/audio/sfx/event_mapper/progression/mod.rs
Normal file
@ -0,0 +1,75 @@
|
||||
/// EventMapper::Progress watches the player entity's stats
|
||||
/// and triggers sfx for gaining experience and levelling up
|
||||
use super::EventMapper;
|
||||
|
||||
use crate::audio::sfx::SfxTriggers;
|
||||
|
||||
use common::{
|
||||
comp::Stats,
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
state::State,
|
||||
};
|
||||
use specs::WorldExt;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
struct ProgressionState {
|
||||
level: u32,
|
||||
exp: u32,
|
||||
}
|
||||
|
||||
impl Default for ProgressionState {
|
||||
fn default() -> Self { Self { level: 1, exp: 0 } }
|
||||
}
|
||||
|
||||
pub struct ProgressionEventMapper {
|
||||
state: ProgressionState,
|
||||
}
|
||||
|
||||
impl EventMapper for ProgressionEventMapper {
|
||||
fn maintain(&mut self, state: &State, player_entity: specs::Entity, triggers: &SfxTriggers) {
|
||||
let ecs = state.ecs();
|
||||
|
||||
let next_state = ecs.read_storage::<Stats>().get(player_entity).map_or(
|
||||
ProgressionState::default(),
|
||||
|stats| ProgressionState {
|
||||
level: stats.level.level(),
|
||||
exp: stats.exp.current(),
|
||||
},
|
||||
);
|
||||
|
||||
if &self.state != &next_state {
|
||||
if let Some(mapped_event) = self.map_event(&next_state) {
|
||||
let sfx_trigger_item = triggers.get_trigger(&mapped_event);
|
||||
|
||||
if sfx_trigger_item.is_some() {
|
||||
ecs.read_resource::<EventBus<SfxEventItem>>()
|
||||
.emit_now(SfxEventItem::at_player_position(mapped_event));
|
||||
}
|
||||
}
|
||||
|
||||
self.state = next_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgressionEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: ProgressionState::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_event(&mut self, next_state: &ProgressionState) -> Option<SfxEvent> {
|
||||
let sfx_event = if next_state.level > self.state.level {
|
||||
Some(SfxEvent::LevelUp)
|
||||
} else if next_state.exp > self.state.exp {
|
||||
Some(SfxEvent::ExperienceGained)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
sfx_event
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod tests;
|
43
voxygen/src/audio/sfx/event_mapper/progression/tests.rs
Normal file
43
voxygen/src/audio/sfx/event_mapper/progression/tests.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use super::*;
|
||||
use common::event::SfxEvent;
|
||||
|
||||
#[test]
|
||||
fn no_change_returns_none() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState::default();
|
||||
|
||||
assert_eq!(mapper.map_event(&next_client_state), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_level_returns_levelup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 2, exp: 0 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::LevelUp)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_exp_returns_expup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 1, exp: 100 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::ExperienceGained)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn level_up_and_gained_exp_prioritises_levelup() {
|
||||
let mut mapper = ProgressionEventMapper::new();
|
||||
let next_client_state = ProgressionState { level: 2, exp: 100 };
|
||||
|
||||
assert_eq!(
|
||||
mapper.map_event(&next_client_state),
|
||||
Some(SfxEvent::LevelUp)
|
||||
);
|
||||
}
|
@ -1,6 +1,85 @@
|
||||
/// The Sfx Manager manages individual sfx event system, listens for
|
||||
/// SFX events and plays the sound at the requested position, or the current
|
||||
/// player position
|
||||
//! Manages individual sfx event system, listens for sfx events, and requests
|
||||
//! playback at the requested position and volume
|
||||
//!
|
||||
//! Veloren's sfx are managed through a configuration which lives in the
|
||||
//! codebase under `/assets/voxygen/audio/sfx.ron`.
|
||||
//!
|
||||
//! Each entry in the configuration consists of an
|
||||
//! [SfxEvent](../../../veloren_common/event/enum.SfxEvent.html) item, with some
|
||||
//! additional information to allow playback:
|
||||
//! - `files` - the paths to the `.wav` files to be played for the sfx. minus
|
||||
//! the file extension. This can be a single item if the same sound can be
|
||||
//! played each time, or a list of files from which one is chosen at random to
|
||||
//! be played.
|
||||
//! - `threshold` - the time that the system should wait between successive
|
||||
//! plays.
|
||||
//!
|
||||
//! The following snippet details some entries in the configuration and how they
|
||||
//! map to the sound files:
|
||||
//! ```ignore
|
||||
//! Run: (
|
||||
//! 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.25, // wait 0.25s between plays
|
||||
//! ),
|
||||
//! Wield(Sword): ( // depends on the player's weapon
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.weapon.sword_out",
|
||||
//! ],
|
||||
//! threshold: 0.5,
|
||||
//! ),
|
||||
//! ...
|
||||
//! ```
|
||||
//!
|
||||
//! These items (for example, the `Wield(Sword)` occasionally depend on some
|
||||
//! property which varies in game. The
|
||||
//! [SfxEvent](../../../veloren_common/event/enum.SfxEvent.html) documentation
|
||||
//! provides links to those variables, some examples are provided her for longer
|
||||
//! items:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! // An inventory action
|
||||
//! Inventory(Dropped): (
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.footsteps.stepgrass_4",
|
||||
//! ],
|
||||
//! threshold: 0.5,
|
||||
//! ),
|
||||
//! // An inventory action which depends upon the item
|
||||
//! Inventory(Consumed(Apple)): (
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.inventory.consumable.apple",
|
||||
//! ],
|
||||
//! threshold: 0.5
|
||||
//! ),
|
||||
//! // An attack ability which depends on the weapon
|
||||
//! Attack(DashMelee, Sword): (
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_01",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_02",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_03",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_04",
|
||||
//! ],
|
||||
//! threshold: 1.2,
|
||||
//! ),
|
||||
//! // A multi-stage attack ability which depends on the weapon
|
||||
//! Attack(TripleStrike(First), Sword): (
|
||||
//! files: [
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_01",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_02",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_03",
|
||||
//! "voxygen.audio.sfx.weapon.whoosh_normal_04",
|
||||
//! ],
|
||||
//! threshold: 0.5,
|
||||
//! ),
|
||||
//! ```
|
||||
|
||||
mod event_mapper;
|
||||
|
||||
use crate::audio::AudioFrontend;
|
||||
|
Loading…
Reference in New Issue
Block a user