mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add initial attack sfx code with bow shot sounds.
This commit is contained in:
parent
54960142e2
commit
d5cc5c8537
@ -23,6 +23,15 @@
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Attack(Bow(BasicBow)): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.bow_attack_01",
|
||||
"voxygen.audio.sfx.weapon.bow_attack_02",
|
||||
"voxygen.audio.sfx.weapon.bow_attack_03",
|
||||
"voxygen.audio.sfx.weapon.bow_attack_04",
|
||||
],
|
||||
threshold: 0.5,
|
||||
),
|
||||
Wield(Sword(BasicSword)): (
|
||||
files: [
|
||||
"voxygen.audio.sfx.weapon.sword_out",
|
||||
|
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_01.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_01.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_02.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_02.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_03.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_03.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_04.wav
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/audio/sfx/weapon/bow_attack_04.wav
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -39,6 +39,7 @@ pub enum SfxEvent {
|
||||
Fall,
|
||||
ExperienceGained,
|
||||
LevelUp,
|
||||
Attack(ToolKind),
|
||||
Wield(ToolKind),
|
||||
Unwield(ToolKind),
|
||||
Inventory(InventoryUpdateEvent),
|
||||
|
179
voxygen/src/audio/sfx/event_mapper/combat/mod.rs
Normal file
179
voxygen/src/audio/sfx/event_mapper/combat/mod.rs
Normal file
@ -0,0 +1,179 @@
|
||||
/// event_mapper::combat watches the combat state of entities and emits
|
||||
/// associated sfx events
|
||||
use crate::audio::sfx::{SfxTriggerItem, SfxTriggers};
|
||||
|
||||
use common::{
|
||||
comp::{
|
||||
item::{Item, ItemKind},
|
||||
CharacterState, ItemConfig, Loadout, Pos,
|
||||
},
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
state::State,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{Entity as EcsEntity, Join, WorldExt};
|
||||
use std::time::{Duration, Instant};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PreviousEntityState {
|
||||
event: SfxEvent,
|
||||
time: Instant,
|
||||
weapon_drawn: bool,
|
||||
}
|
||||
|
||||
impl Default for PreviousEntityState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
const SFX_DIST_LIMIT_SQR: f32 = 20000.0;
|
||||
let ecs = state.ecs();
|
||||
|
||||
let sfx_event_bus = ecs.read_resource::<EventBus<SfxEventItem>>();
|
||||
let mut sfx_emitter = sfx_event_bus.emitter();
|
||||
|
||||
let player_position = ecs
|
||||
.read_storage::<Pos>()
|
||||
.get(player_entity)
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, pos, loadout, character) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
ecs.read_storage::<Loadout>().maybe(),
|
||||
ecs.read_storage::<CharacterState>().maybe(),
|
||||
)
|
||||
.join()
|
||||
.filter(|(_, e_pos, ..)| {
|
||||
(e_pos.0.distance_squared(player_position)) < SFX_DIST_LIMIT_SQR
|
||||
})
|
||||
{
|
||||
if let Some(character) = character {
|
||||
let state = self
|
||||
.event_history
|
||||
.entry(entity)
|
||||
.or_insert_with(|| PreviousEntityState::default());
|
||||
|
||||
let mapped_event = Self::map_event(character, state, loadout);
|
||||
|
||||
// Check for SFX config entry for this movement
|
||||
if Self::should_emit(state, triggers.get_key_value(&mapped_event)) {
|
||||
sfx_emitter.emit(SfxEventItem::new(mapped_event, Some(pos.0), None));
|
||||
|
||||
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.weapon_drawn = Self::weapon_drawn(character);
|
||||
}
|
||||
}
|
||||
|
||||
self.cleanup(player_entity);
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// their activity. `cleanup` will remove entities from event tracking if
|
||||
/// they have not triggered an event for > n seconds. This prevents
|
||||
/// stale records from bloating the Map size.
|
||||
fn cleanup(&mut self, player: EcsEntity) {
|
||||
const TRACKING_TIMEOUT: u64 = 10;
|
||||
|
||||
let now = Instant::now();
|
||||
self.event_history.retain(|entity, event| {
|
||||
now.duration_since(event.time) < Duration::from_secs(TRACKING_TIMEOUT)
|
||||
|| entity.id() == player.id()
|
||||
});
|
||||
}
|
||||
|
||||
/// 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
|
||||
fn should_emit(
|
||||
previous_state: &PreviousEntityState,
|
||||
sfx_trigger_item: Option<(&SfxEvent, &SfxTriggerItem)>,
|
||||
) -> bool {
|
||||
if let Some((event, item)) = sfx_trigger_item {
|
||||
if &previous_state.event == event {
|
||||
previous_state.time.elapsed().as_secs_f64() >= item.threshold
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn map_event(
|
||||
character_state: &CharacterState,
|
||||
previous_state: &PreviousEntityState,
|
||||
loadout: Option<&Loadout>,
|
||||
) -> SfxEvent {
|
||||
if let Some(active_loadout) = loadout {
|
||||
if let Some(ItemConfig {
|
||||
item:
|
||||
Item {
|
||||
kind: ItemKind::Tool(data),
|
||||
..
|
||||
},
|
||||
..
|
||||
}) = active_loadout.active_item
|
||||
{
|
||||
// Check for attacking states
|
||||
if character_state.is_attack() {
|
||||
return SfxEvent::Attack(data.kind);
|
||||
} else {
|
||||
if let Some(wield_event) = match (
|
||||
previous_state.weapon_drawn,
|
||||
character_state.is_dodge(),
|
||||
Self::weapon_drawn(character_state),
|
||||
) {
|
||||
(false, false, true) => Some(SfxEvent::Wield(data.kind)),
|
||||
(true, false, false) => Some(SfxEvent::Unwield(data.kind)),
|
||||
_ => None,
|
||||
} {
|
||||
return wield_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SfxEvent::Idle
|
||||
}
|
||||
|
||||
/// This helps us determine whether we should be emitting the Wield/Unwield
|
||||
/// events. For now, consider either CharacterState::Wielding or
|
||||
/// ::Equipping to mean the weapon is drawn. This will need updating if the
|
||||
/// animations change to match the wield_duration associated with the weapon
|
||||
fn weapon_drawn(character: &CharacterState) -> bool {
|
||||
character.is_wield()
|
||||
|| match character {
|
||||
CharacterState::Equipping { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] mod tests;
|
98
voxygen/src/audio/sfx/event_mapper/combat/tests.rs
Normal file
98
voxygen/src/audio/sfx/event_mapper/combat/tests.rs
Normal file
@ -0,0 +1,98 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{
|
||||
item::tool::{AxeKind, BowKind, ToolKind},
|
||||
CharacterState, ItemConfig, Loadout,
|
||||
},
|
||||
event::SfxEvent,
|
||||
states,
|
||||
};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn maps_wield_while_equipping() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.starter_axe"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::Equipping(states::equipping::Data {
|
||||
time_left: Duration::from_millis(10),
|
||||
}),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
},
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Wield(ToolKind::Axe(AxeKind::BasicAxe)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_unwield() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.starter_bow"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::default(),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: true,
|
||||
},
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Unwield(ToolKind::Bow(BowKind::BasicBow)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_basic_melee() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.starter_axe"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = CombatEventMapper::map_event(
|
||||
&CharacterState::BasicMelee(states::basic_melee::Data {
|
||||
buildup_duration: Duration::default(),
|
||||
recover_duration: Duration::default(),
|
||||
base_healthchange: 1,
|
||||
range: 1.0,
|
||||
max_angle: 1.0,
|
||||
exhausted: false,
|
||||
}),
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: true,
|
||||
},
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Attack(ToolKind::Axe(AxeKind::BasicAxe)));
|
||||
}
|
@ -1,23 +1,27 @@
|
||||
mod combat;
|
||||
mod movement;
|
||||
mod progression;
|
||||
|
||||
use common::state::State;
|
||||
|
||||
use combat::CombatEventMapper;
|
||||
use movement::MovementEventMapper;
|
||||
use progression::ProgressionEventMapper;
|
||||
|
||||
use super::SfxTriggers;
|
||||
|
||||
pub struct SfxEventMapper {
|
||||
progression_event_mapper: ProgressionEventMapper,
|
||||
movement_event_mapper: MovementEventMapper,
|
||||
progression: ProgressionEventMapper,
|
||||
movement: MovementEventMapper,
|
||||
combat: CombatEventMapper,
|
||||
}
|
||||
|
||||
impl SfxEventMapper {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
progression_event_mapper: ProgressionEventMapper::new(),
|
||||
movement_event_mapper: MovementEventMapper::new(),
|
||||
progression: ProgressionEventMapper::new(),
|
||||
combat: CombatEventMapper::new(),
|
||||
movement: MovementEventMapper::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,9 +31,8 @@ impl SfxEventMapper {
|
||||
player_entity: specs::Entity,
|
||||
triggers: &SfxTriggers,
|
||||
) {
|
||||
self.progression_event_mapper
|
||||
.maintain(state, player_entity, triggers);
|
||||
self.movement_event_mapper
|
||||
.maintain(state, player_entity, triggers);
|
||||
self.progression.maintain(state, player_entity, triggers);
|
||||
self.movement.maintain(state, player_entity, triggers);
|
||||
self.combat.maintain(state, player_entity, triggers);
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,7 @@ use crate::audio::sfx::{SfxTriggerItem, SfxTriggers};
|
||||
|
||||
use common::{
|
||||
comp::{
|
||||
item::{Item, ItemKind},
|
||||
Body, CharacterState, ItemConfig, Loadout, PhysicsState, Pos, Vel,
|
||||
Body, CharacterState, PhysicsState, Pos, Vel,
|
||||
},
|
||||
event::{EventBus, SfxEvent, SfxEventItem},
|
||||
state::State,
|
||||
@ -20,7 +19,6 @@ use vek::*;
|
||||
struct PreviousEntityState {
|
||||
event: SfxEvent,
|
||||
time: Instant,
|
||||
weapon_drawn: bool,
|
||||
on_ground: bool,
|
||||
}
|
||||
|
||||
@ -29,7 +27,6 @@ impl Default for PreviousEntityState {
|
||||
Self {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
}
|
||||
}
|
||||
@ -58,13 +55,12 @@ impl MovementEventMapper {
|
||||
.get(player_entity)
|
||||
.map_or(Vec3::zero(), |pos| pos.0);
|
||||
|
||||
for (entity, pos, vel, body, physics, loadout, character) in (
|
||||
for (entity, pos, vel, body, physics, character) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<Pos>(),
|
||||
&ecs.read_storage::<Vel>(),
|
||||
&ecs.read_storage::<Body>(),
|
||||
&ecs.read_storage::<PhysicsState>(),
|
||||
ecs.read_storage::<Loadout>().maybe(),
|
||||
ecs.read_storage::<CharacterState>().maybe(),
|
||||
)
|
||||
.join()
|
||||
@ -79,9 +75,7 @@ impl MovementEventMapper {
|
||||
.or_insert_with(|| PreviousEntityState::default());
|
||||
|
||||
let mapped_event = match body {
|
||||
Body::Humanoid(_) => {
|
||||
Self::map_movement_event(character, physics, state, vel.0, loadout)
|
||||
},
|
||||
Body::Humanoid(_) => Self::map_movement_event(character, physics, state, vel.0),
|
||||
Body::QuadrupedMedium(_)
|
||||
| Body::QuadrupedSmall(_)
|
||||
| Body::BirdMedium(_)
|
||||
@ -104,7 +98,6 @@ impl MovementEventMapper {
|
||||
// update state to determine the next event. We only record the time (above) if
|
||||
// it was dispatched
|
||||
state.event = mapped_event;
|
||||
state.weapon_drawn = Self::weapon_drawn(character);
|
||||
state.on_ground = physics.on_ground;
|
||||
}
|
||||
}
|
||||
@ -157,33 +150,7 @@ impl MovementEventMapper {
|
||||
physics_state: &PhysicsState,
|
||||
previous_state: &PreviousEntityState,
|
||||
vel: Vec3<f32>,
|
||||
loadout: Option<&Loadout>,
|
||||
) -> SfxEvent {
|
||||
// Handle wield state changes
|
||||
if let Some(active_loadout) = loadout {
|
||||
if let Some(ItemConfig {
|
||||
item:
|
||||
Item {
|
||||
kind: ItemKind::Tool(data),
|
||||
..
|
||||
},
|
||||
..
|
||||
}) = active_loadout.active_item
|
||||
{
|
||||
if let Some(wield_event) = match (
|
||||
previous_state.weapon_drawn,
|
||||
character_state.is_dodge(),
|
||||
Self::weapon_drawn(character_state),
|
||||
) {
|
||||
(false, false, true) => Some(SfxEvent::Wield(data.kind)),
|
||||
(true, false, false) => Some(SfxEvent::Unwield(data.kind)),
|
||||
_ => None,
|
||||
} {
|
||||
return wield_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Match run state
|
||||
if physics_state.on_ground && vel.magnitude() > 0.1
|
||||
|| !previous_state.on_ground && physics_state.on_ground
|
||||
@ -216,18 +183,6 @@ impl MovementEventMapper {
|
||||
}
|
||||
}
|
||||
|
||||
/// This helps us determine whether we should be emitting the Wield/Unwield
|
||||
/// events. For now, consider either CharacterState::Wielding or
|
||||
/// ::Equipping to mean the weapon is drawn. This will need updating if the
|
||||
/// animations change to match the wield_duration associated with the weapon
|
||||
fn weapon_drawn(character: &CharacterState) -> bool {
|
||||
character.is_wield()
|
||||
|| match character {
|
||||
CharacterState::Equipping { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
fn get_volume_for_body_type(body: &Body) -> f32 {
|
||||
|
@ -1,10 +1,7 @@
|
||||
use super::*;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{
|
||||
bird_small, humanoid,
|
||||
item::tool::{AxeKind, BowKind, ToolKind},
|
||||
quadruped_medium, quadruped_small, Body, CharacterState, ItemConfig, Loadout, PhysicsState,
|
||||
bird_small, humanoid, quadruped_medium, quadruped_small, Body, CharacterState, PhysicsState,
|
||||
},
|
||||
event::SfxEvent,
|
||||
states,
|
||||
@ -30,7 +27,6 @@ fn config_but_played_since_threshold_no_emit() {
|
||||
let previous_state = PreviousEntityState {
|
||||
event: SfxEvent::Run,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
};
|
||||
|
||||
@ -50,7 +46,6 @@ fn config_and_not_played_since_threshold_emits() {
|
||||
let previous_state = PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now().checked_add(Duration::from_secs(1)).unwrap(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
};
|
||||
|
||||
@ -72,7 +67,6 @@ fn same_previous_event_elapsed_emits() {
|
||||
time: Instant::now()
|
||||
.checked_sub(Duration::from_millis(500))
|
||||
.unwrap(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
};
|
||||
|
||||
@ -96,11 +90,9 @@ fn maps_idle() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Idle);
|
||||
@ -120,11 +112,9 @@ fn maps_run_with_sufficient_velocity() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::new(0.5, 0.8, 0.0),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
@ -144,11 +134,9 @@ fn does_not_map_run_with_insufficient_velocity() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::new(0.02, 0.0001, 0.0),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Idle);
|
||||
@ -168,11 +156,9 @@ fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::new(0.5, 0.8, 0.0),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Idle);
|
||||
@ -195,11 +181,9 @@ fn maps_roll() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Run,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Roll);
|
||||
@ -219,11 +203,9 @@ fn maps_land_on_ground_to_run() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Run);
|
||||
@ -243,11 +225,9 @@ fn maps_glider_open() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Jump,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::GliderOpen);
|
||||
@ -267,11 +247,9 @@ fn maps_glide() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Glide,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Glide);
|
||||
@ -291,11 +269,9 @@ fn maps_glider_close_when_closing_mid_flight() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Glide,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::GliderClose);
|
||||
@ -316,88 +292,14 @@ fn maps_glider_close_when_landing() {
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Glide,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: false,
|
||||
},
|
||||
Vec3::zero(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::GliderClose);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_wield_while_equipping() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.axe.starter_axe"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::Equipping(states::equipping::Data {
|
||||
time_left: Duration::from_millis(10),
|
||||
}),
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_ceiling: false,
|
||||
on_wall: None,
|
||||
touch_entity: None,
|
||||
in_fluid: false,
|
||||
},
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: false,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::zero(),
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Wield(ToolKind::Axe(AxeKind::BasicAxe)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_unwield() {
|
||||
let mut loadout = Loadout::default();
|
||||
|
||||
loadout.active_item = Some(ItemConfig {
|
||||
item: assets::load_expect_cloned("common.items.weapons.bow.starter_bow"),
|
||||
ability1: None,
|
||||
ability2: None,
|
||||
ability3: None,
|
||||
block_ability: None,
|
||||
dodge_ability: None,
|
||||
});
|
||||
|
||||
let result = MovementEventMapper::map_movement_event(
|
||||
&CharacterState::default(),
|
||||
&PhysicsState {
|
||||
on_ground: true,
|
||||
on_ceiling: false,
|
||||
on_wall: None,
|
||||
touch_entity: None,
|
||||
in_fluid: false,
|
||||
},
|
||||
&PreviousEntityState {
|
||||
event: SfxEvent::Idle,
|
||||
time: Instant::now(),
|
||||
weapon_drawn: true,
|
||||
on_ground: true,
|
||||
},
|
||||
Vec3::zero(),
|
||||
Some(&loadout),
|
||||
);
|
||||
|
||||
assert_eq!(result, SfxEvent::Unwield(ToolKind::Bow(BowKind::ShortBow0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_quadrupeds_running() {
|
||||
let result = MovementEventMapper::map_non_humanoid_movement_event(
|
||||
|
@ -22,13 +22,9 @@ pub struct SfxTriggerItem {
|
||||
pub threshold: f64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct SfxTriggers(HashMap<SfxEvent, SfxTriggerItem>);
|
||||
|
||||
impl Default for SfxTriggers {
|
||||
fn default() -> Self { Self(HashMap::new()) }
|
||||
}
|
||||
|
||||
impl SfxTriggers {
|
||||
pub fn get_trigger(&self, trigger: &SfxEvent) -> Option<&SfxTriggerItem> { self.0.get(trigger) }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user