diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs index c2b9073368..ca1d690002 100644 --- a/common/src/comp/buff.rs +++ b/common/src/comp/buff.rs @@ -41,6 +41,7 @@ pub enum BuffCategoryId { Divine, Debuff, Buff, + PersistOnDeath, } /// Data indicating and configuring behaviour of a de/buff. @@ -93,9 +94,12 @@ pub enum BuffChange { RemoveByIndex(Vec<usize>, Vec<usize>), /// Removes buffs of these categories (first vec is of categories of which /// all are required, second vec is of categories of which at least one is - /// required) Note that this functionality is currently untested and - /// should be tested when doing so is possible - RemoveByCategory(Vec<BuffCategoryId>, Vec<BuffCategoryId>), + /// required, third vec is of categories that will not be removed) + RemoveByCategory { + required: Vec<BuffCategoryId>, + optional: Vec<BuffCategoryId>, + blacklisted: Vec<BuffCategoryId>, + }, } /// Source of the de/buff @@ -173,6 +177,13 @@ impl Buff { duration, ), }; + assert_eq!( + cat_ids + .iter() + .any(|cat| *cat == BuffCategoryId::Buff || *cat == BuffCategoryId::Debuff), + true, + "Buff must have either buff or debuff category." + ); Buff { id, cat_ids, diff --git a/common/src/sys/buff.rs b/common/src/sys/buff.rs index da1b9eee4d..e509d5114b 100644 --- a/common/src/sys/buff.rs +++ b/common/src/sys/buff.rs @@ -1,5 +1,8 @@ use crate::{ - comp::{BuffChange, BuffEffect, BuffSource, Buffs, HealthChange, HealthSource}, + comp::{ + BuffCategoryId, BuffChange, BuffEffect, BuffSource, Buffs, HealthChange, HealthSource, + Stats, + }, event::{EventBus, ServerEvent}, state::DeltaTime, sync::Uid, @@ -14,12 +17,13 @@ impl<'a> System<'a> for Sys { Read<'a, DeltaTime>, Read<'a, EventBus<ServerEvent>>, ReadStorage<'a, Uid>, + ReadStorage<'a, Stats>, WriteStorage<'a, Buffs>, ); - fn run(&mut self, (dt, server_bus, uids, mut buffs): Self::SystemData) { + fn run(&mut self, (dt, server_bus, uids, stats, mut buffs): Self::SystemData) { let mut server_emitter = server_bus.emitter(); - for (uid, mut buffs) in (&uids, &mut buffs.restrict_mut()).join() { + for (uid, stat, mut buffs) in (&uids, &stats, &mut buffs.restrict_mut()).join() { let buff_comp = buffs.get_mut_unchecked(); let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) = (Vec::<usize>::new(), Vec::<usize>::new()); @@ -95,6 +99,7 @@ impl<'a> System<'a> for Sys { }; } } + server_emitter.emit(ServerEvent::Buff { uid: *uid, buff_change: BuffChange::RemoveByIndex( @@ -102,6 +107,17 @@ impl<'a> System<'a> for Sys { inactive_buff_indices_for_removal, ), }); + + if stat.is_dead { + server_emitter.emit(ServerEvent::Buff { + uid: *uid, + buff_change: BuffChange::RemoveByCategory { + required: vec![], + optional: vec![], + blacklisted: vec![BuffCategoryId::PersistOnDeath], + }, + }); + } } } } diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index a0b24b1db7..6e46d94d6d 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -159,7 +159,7 @@ impl<'a> System<'a> for Sys { strength: attack.base_damage as f32, duration: Some(Duration::from_secs(10)), }, - vec![buff::BuffCategoryId::Physical], + vec![buff::BuffCategoryId::Physical, buff::BuffCategoryId::Debuff], buff::BuffSource::Character { by: *uid }, )), }); diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index 1e2ed26a2a..d0ba6ee4d6 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -758,7 +758,11 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange) } } }, - BuffChange::RemoveByCategory(all_required, any_required) => { + BuffChange::RemoveByCategory { + required: all_required, + optional: any_required, + blacklisted: none_required, + } => { for (i, buff) in buffs.active_buffs.iter().enumerate() { let mut required_met = true; for required in &all_required { @@ -774,7 +778,14 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange) break; } } - if required_met && any_met { + let mut none_met = true; + for none in &none_required { + if buff.cat_ids.iter().any(|cat| cat == none) { + none_met = false; + break; + } + } + if required_met && any_met && none_met { active_buff_indices_for_removal.push(i); } } diff --git a/voxygen/src/hud/buffs.rs b/voxygen/src/hud/buffs.rs index 875c63d779..ad32915443 100644 --- a/voxygen/src/hud/buffs.rs +++ b/voxygen/src/hud/buffs.rs @@ -8,7 +8,7 @@ use crate::{ GlobalState, }; use client::Client; -use common::comp::Stats; +use common::comp::{self, Buffs}; use conrod_core::{ color, widget::{self, Button, Image, Rectangle, Text}, @@ -24,8 +24,15 @@ widget_ids! { debuff_test, } } + +pub struct BuffInfo { + id: comp::BuffId, + is_buff: bool, + dur: f32, +} + #[derive(WidgetCommon)] -pub struct Buffs<'a> { +pub struct BuffsBar<'a> { client: &'a Client, imgs: &'a Imgs, fonts: &'a ConrodVoxygenFonts, @@ -35,10 +42,10 @@ pub struct Buffs<'a> { rot_imgs: &'a ImgsRot, tooltip_manager: &'a mut TooltipManager, localized_strings: &'a std::sync::Arc<VoxygenLocalization>, - stats: &'a Stats, + buffs: &'a Buffs, } -impl<'a> Buffs<'a> { +impl<'a> BuffsBar<'a> { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 pub fn new( client: &'a Client, @@ -48,7 +55,7 @@ impl<'a> Buffs<'a> { rot_imgs: &'a ImgsRot, tooltip_manager: &'a mut TooltipManager, localized_strings: &'a std::sync::Arc<VoxygenLocalization>, - stats: &'a Stats, + buffs: &'a Buffs, ) -> Self { Self { client, @@ -59,7 +66,7 @@ impl<'a> Buffs<'a> { rot_imgs, tooltip_manager, localized_strings, - stats, + buffs, } } } @@ -68,7 +75,7 @@ pub struct State { ids: Ids, } -impl<'a> Widget for Buffs<'a> { +impl<'a> Widget for BuffsBar<'a> { type Event = (); type State = State; type Style = (); @@ -123,3 +130,14 @@ impl<'a> Widget for Buffs<'a> { .set(state.ids.buff_test, ui); } } + +fn get_buff_info(buff: comp::Buff) -> BuffInfo { + BuffInfo { + id: buff.id, + is_buff: buff + .cat_ids + .iter() + .any(|cat| *cat == comp::BuffCategoryId::Buff), + dur: buff.time.map(|dur| dur.as_secs_f32()).unwrap_or(100.0), + } +} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 5b12014c1e..bd3d0575c4 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -25,7 +25,7 @@ pub use hotbar::{SlotContents as HotbarSlotContents, State as HotbarState}; pub use settings_window::ScaleChange; use bag::Bag; -use buffs::Buffs; +use buffs::BuffsBar; use buttons::Buttons; use chat::Chat; use chrono::NaiveTime; @@ -1733,6 +1733,7 @@ impl Hud { // Bag button and nearby icons let ecs = client.state().ecs(); let stats = ecs.read_storage::<comp::Stats>(); + let buffs = ecs.read_storage::<comp::Buffs>(); if let Some(player_stats) = stats.get(client.entity()) { match Buttons::new( client, @@ -1758,8 +1759,8 @@ impl Hud { } // Buffs and Debuffs - if let Some(player_stats) = stats.get(client.entity()) { - match Buffs::new( + if let Some(player_buffs) = buffs.get(client.entity()) { + match BuffsBar::new( client, &self.imgs, &self.fonts, @@ -1767,7 +1768,7 @@ impl Hud { &self.rot_imgs, tooltip_manager, &self.voxygen_i18n, - &player_stats, + &player_buffs, ) .set(self.ids.buffs, ui_widgets) {