diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ac390130..0e3ca83fa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added new orc hairstyles - Added sfx for wielding/unwielding weapons - Fixed NPCs attacking the player forever after killing them +- Added sfx for collecting, dropping and using inventory items ### Changed diff --git a/assets/voxygen/audio/sfx.ron b/assets/voxygen/audio/sfx.ron index 38349f287e..2a8d79e5e2 100644 --- a/assets/voxygen/audio/sfx.ron +++ b/assets/voxygen/audio/sfx.ron @@ -35,5 +35,59 @@ ], threshold: 0.5, ), + Inventory(Collected): ( + files: [ + "voxygen.audio.sfx.inventory.add_item", + ], + threshold: 0.5, + ), + Inventory(Swapped): ( + files: [ + "voxygen.audio.sfx.inventory.add_item", + ], + threshold: 0.5, + ), + Inventory(Given): ( + files: [ + "voxygen.audio.sfx.inventory.add_item", + ], + threshold: 0.5, + ), + Inventory(Dropped): ( + files: [ + "voxygen.audio.sfx.footsteps.stepgrass_4", + ], + threshold: 0.5, + ), + Inventory(Consumed(Potion)): ( + files: [ + "voxygen.audio.sfx.inventory.consumable.liquid", + ], + threshold: 0.3, + ), + Inventory(Consumed(PotionMinor)): ( + files: [ + "voxygen.audio.sfx.inventory.consumable.liquid", + ], + threshold: 0.3, + ), + Inventory(Consumed(Apple)): ( + files: [ + "voxygen.audio.sfx.inventory.consumable.apple", + ], + threshold: 0.3, + ), + Inventory(Consumed(Mushroom)): ( + files: [ + "voxygen.audio.sfx.inventory.consumable.food", + ], + threshold: 0.3, + ), + Inventory(Consumed(Cheese)): ( + files: [ + "voxygen.audio.sfx.inventory.consumable.food", + ], + threshold: 0.3, + ) } ) \ No newline at end of file diff --git a/assets/voxygen/audio/sfx/inventory/add_item.wav b/assets/voxygen/audio/sfx/inventory/add_item.wav new file mode 100644 index 0000000000..b6fa2c3665 --- /dev/null +++ b/assets/voxygen/audio/sfx/inventory/add_item.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5320d020c82cab3f1ed294c06bdd50df007ed354bca2103b42e3fb4fc3f3ee7a +size 71196 diff --git a/assets/voxygen/audio/sfx/inventory/consumable/apple.wav b/assets/voxygen/audio/sfx/inventory/consumable/apple.wav new file mode 100644 index 0000000000..286d8aade0 --- /dev/null +++ b/assets/voxygen/audio/sfx/inventory/consumable/apple.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c4d2931431c26b95a4d41b2e137b3db74456b8b9db54d7c48defb9d7bb67689 +size 70152 diff --git a/assets/voxygen/audio/sfx/inventory/consumable/food.wav b/assets/voxygen/audio/sfx/inventory/consumable/food.wav new file mode 100644 index 0000000000..ea39de567a --- /dev/null +++ b/assets/voxygen/audio/sfx/inventory/consumable/food.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fd5074d0ec517b626e95bc34cb75e735d48dbb99473ffeadb79d90734f52f7d +size 31208 diff --git a/assets/voxygen/audio/sfx/inventory/consumable/liquid.wav b/assets/voxygen/audio/sfx/inventory/consumable/liquid.wav new file mode 100644 index 0000000000..fa0db211f4 --- /dev/null +++ b/assets/voxygen/audio/sfx/inventory/consumable/liquid.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c3a38dede30bb4a8c13644bd43be5fe261f177f3c65f88e5d02da5b9ba68a97 +size 21548 diff --git a/client/src/lib.rs b/client/src/lib.rs index 90ecb651c6..57ee0fb4d7 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -14,6 +14,7 @@ pub use specs::{ use byteorder::{ByteOrder, LittleEndian}; use common::{ comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip}, + event::{EventBus, SfxEvent, SfxEventItem}, msg::{ validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate, RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG, @@ -377,6 +378,7 @@ impl Client { } } } + // Handle new messages from the server. frontend_events.append(&mut self.handle_new_messages()?); @@ -669,8 +671,14 @@ impl Client { self.state.write_component(entity, character_state); } }, - ServerMsg::InventoryUpdate(inventory) => { - self.state.write_component(self.entity, inventory) + ServerMsg::InventoryUpdate(inventory, event) => { + self.state.write_component(self.entity, inventory); + + self.state + .ecs() + .read_resource::>() + .emitter() + .emit(SfxEventItem::at_player_position(SfxEvent::Inventory(event))); }, ServerMsg::TerrainChunkUpdate { key, chunk } => { if let Ok(chunk) = chunk { diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index da958ee9b9..dd25ef9e4f 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -90,7 +90,7 @@ pub enum Armor { Necklace, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Consumable { Apple, Cheese, diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index f6833ff923..f192208b5c 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -1,10 +1,11 @@ pub mod item; // Reexports -pub use item::{Debug, Item, ItemKind, Tool}; +pub use item::{Consumable, Debug, Item, ItemKind, Tool}; use crate::assets; -use specs::{Component, HashMapStorage, NullStorage}; +use specs::{Component, FlaggedStorage, HashMapStorage}; +use specs_idvs::IDVStorage; use std::ops::Not; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -136,12 +137,37 @@ impl Component for Inventory { type Storage = HashMapStorage; } -// ForceUpdate +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub enum InventoryUpdateEvent { + Init, + Used, + Consumed(Consumable), + Gave, + Given, + Swapped, + Dropped, + Collected, + Possession, + Debug, +} + +impl Default for InventoryUpdateEvent { + fn default() -> Self { Self::Init } +} + #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] -pub struct InventoryUpdate; +pub struct InventoryUpdate { + event: InventoryUpdateEvent, +} + +impl InventoryUpdate { + pub fn new(event: InventoryUpdateEvent) -> Self { Self { event } } + + pub fn event(&self) -> InventoryUpdateEvent { self.event } +} impl Component for InventoryUpdate { - type Storage = NullStorage; + type Storage = FlaggedStorage>; } #[cfg(test)] mod test; diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 24b1be9efb..2871761a7a 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -28,7 +28,7 @@ pub use controller::{ }; pub use energy::{Energy, EnergySource}; pub use inputs::CanBuild; -pub use inventory::{item, Inventory, InventoryUpdate, Item, ItemKind}; +pub use inventory::{item, Inventory, InventoryUpdate, InventoryUpdateEvent, Item, ItemKind}; pub use last::Last; pub use location::{Waypoint, WaypointArea}; pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel}; diff --git a/common/src/event.rs b/common/src/event.rs index 6ac5e49531..0ba59b7274 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -1,5 +1,5 @@ use crate::{comp, sync::Uid}; -use comp::item::Tool; +use comp::{item::Tool, InventoryUpdateEvent}; use parking_lot::Mutex; use serde::Deserialize; use specs::Entity as EcsEntity; @@ -42,6 +42,7 @@ pub enum SfxEvent { LevelUp, Wield(Tool), Unwield(Tool), + Inventory(InventoryUpdateEvent), } pub enum LocalEvent { diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index a9244b15f6..0a7b84ae33 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -71,7 +71,7 @@ pub enum ServerMsg { entity: u64, character_state: comp::CharacterState, }, - InventoryUpdate(comp::Inventory), + InventoryUpdate(comp::Inventory, comp::InventoryUpdateEvent), TerrainChunkUpdate { key: Vec2, chunk: Result, ()>, diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 1f46109481..b4a2e3e5dd 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -262,6 +262,7 @@ lazy_static! { ), ]; } + fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) { if let Ok(item) = assets::load_cloned(&args) { server @@ -274,7 +275,10 @@ fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &C .state .ecs() .write_storage::() - .insert(entity, comp::InventoryUpdate); + .insert( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Given), + ); } else { server.notify_client(entity, ServerMsg::private(String::from("Invalid item!"))); } @@ -1113,7 +1117,10 @@ fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action: .state .ecs() .write_storage::() - .insert(entity, comp::InventoryUpdate); + .insert( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Debug), + ); } else { server.notify_client( entity, diff --git a/server/src/events/interaction.rs b/server/src/events/interaction.rs index 96be66e52b..7d7e3fd124 100644 --- a/server/src/events/interaction.rs +++ b/server/src/events/interaction.rs @@ -106,7 +106,10 @@ pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) { } } ecs.write_storage::() - .insert(possesse, comp::InventoryUpdate) + .insert( + possesse, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Possession), + ) .err() .map(|e| { error!( diff --git a/server/src/events/inventory_manip.rs b/server/src/events/inventory_manip.rs index 4485a62fb7..09998ca6aa 100644 --- a/server/src/events/inventory_manip.rs +++ b/server/src/events/inventory_manip.rs @@ -48,7 +48,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv } } - state.write_component(entity, comp::InventoryUpdate); + state.write_component( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected), + ); }, comp::InventoryManip::Collect(pos) => { @@ -76,6 +79,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv .get_mut(entity) .and_then(|inv| inv.remove(slot)); + let mut event = comp::InventoryUpdateEvent::Used; + if let Some(item) = item_opt { match item.kind { comp::ItemKind::Tool { .. } => { @@ -94,7 +99,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv stats.equipment.main = Some(item); } }, - comp::ItemKind::Consumable { effect, .. } => { + comp::ItemKind::Consumable { kind, effect } => { + event = comp::InventoryUpdateEvent::Consumed(kind); state.apply_effect(entity, effect); }, comp::ItemKind::Utility { kind } => match kind { @@ -168,7 +174,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv } } - state.write_component(entity, comp::InventoryUpdate); + state.write_component(entity, comp::InventoryUpdate::new(event)); }, comp::InventoryManip::Swap(a, b) => { @@ -177,7 +183,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv .write_storage::() .get_mut(entity) .map(|inv| inv.swap_slots(a, b)); - state.write_component(entity, comp::InventoryUpdate); + state.write_component( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Swapped), + ); }, comp::InventoryManip::Drop(slot) => { @@ -201,7 +210,10 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv item, )); } - state.write_component(entity, comp::InventoryUpdate); + state.write_component( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Dropped), + ); }, } diff --git a/server/src/lib.rs b/server/src/lib.rs index b39fefea50..4d11efd110 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -282,7 +282,10 @@ impl Server { state.write_component(entity, comp::CharacterState::default()); state.write_component(entity, comp::Alignment::Owned(entity)); state.write_component(entity, comp::Inventory::default()); - state.write_component(entity, comp::InventoryUpdate); + state.write_component( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::default()), + ); // Make sure physics are accepted. state.write_component(entity, comp::ForceUpdate); @@ -606,7 +609,10 @@ impl StateExt for State { .map(|inv| inv.push(item).is_none()) .unwrap_or(false); if success { - self.write_component(entity, comp::InventoryUpdate); + self.write_component( + entity, + comp::InventoryUpdate::new(comp::InventoryUpdateEvent::Collected), + ); } success } diff --git a/server/src/sys/entity_sync.rs b/server/src/sys/entity_sync.rs index 1d28b77117..62bc7521a7 100644 --- a/server/src/sys/entity_sync.rs +++ b/server/src/sys/entity_sync.rs @@ -328,8 +328,11 @@ impl<'a> System<'a> for Sys { // TODO: Sync clients that don't have a position? // Sync inventories - for (client, inventory, _) in (&mut clients, &inventories, &inventory_updates).join() { - client.notify(ServerMsg::InventoryUpdate(inventory.clone())); + for (client, inventory, update) in (&mut clients, &inventories, &inventory_updates).join() { + client.notify(ServerMsg::InventoryUpdate( + inventory.clone(), + update.event(), + )); } // Remove all force flags. diff --git a/voxygen/src/audio/sfx/event_mapper/mod.rs b/voxygen/src/audio/sfx/event_mapper/mod.rs index e195d1cba2..94905cb802 100644 --- a/voxygen/src/audio/sfx/event_mapper/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/mod.rs @@ -1,5 +1,5 @@ -pub mod movement; -pub mod progression; +mod movement; +mod progression; use movement::MovementEventMapper; use progression::ProgressionEventMapper; diff --git a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs index 77c2067177..617092e8d6 100644 --- a/voxygen/src/audio/sfx/event_mapper/movement/mod.rs +++ b/voxygen/src/audio/sfx/event_mapper/movement/mod.rs @@ -172,7 +172,7 @@ impl MovementEventMapper { match ( current_event.movement, current_event.action, - previous_event.event, + previous_event.event.clone(), ) { (_, ActionState::Roll { .. }, _) => SfxEvent::Roll, (MovementState::Climb, ..) => SfxEvent::Climb,