diff --git a/common/src/comp/buff.rs b/common/src/comp/buff.rs
index 24c13a40d7..8a8338c605 100644
--- a/common/src/comp/buff.rs
+++ b/common/src/comp/buff.rs
@@ -29,14 +29,14 @@ pub enum BuffId {
 /// De/buff category ID.
 /// Similar to `BuffId`, but to mark a category (for more generic usage, like
 /// positive/negative buffs).
-#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
 pub enum BuffCategoryId {
     Natural,
     Physical,
     Magical,
     Divine,
-    Negative,
-    Positive,
+    Debuff,
+    Buff,
 }
 
 /// Data indicating and configuring behaviour of a de/buff.
@@ -83,8 +83,14 @@ pub enum BuffChange {
     Add(Buff),
     /// Removes all buffs with this ID.
     RemoveById(BuffId),
-    /// Removes buff of this index
+    /// Removes buffs of these indices (first vec is for active buffs, second is
+    /// for inactive buffs)
     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>),
 }
 
 /// Source of the de/buff
diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs
index 3cfb11af64..8ac6ed2ed2 100644
--- a/server/src/events/entity_manipulation.rs
+++ b/server/src/events/entity_manipulation.rs
@@ -684,8 +684,9 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
             let mut stats = ecs.write_storage::<comp::Stats>();
             let (mut active_buff_indices_for_removal, mut inactive_buff_indices_for_removal) =
                 (Vec::new(), Vec::new());
+            use buff::BuffChange;
             match buff_change {
-                buff::BuffChange::Add(new_buff) => {
+                BuffChange::Add(new_buff) => {
                     if buffs.active_buffs.is_empty() {
                         add_buff_effects(new_buff.clone(), stats.get_mut(entity));
                         buffs.active_buffs.push(new_buff);
@@ -716,11 +717,11 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
                         }
                     }
                 },
-                buff::BuffChange::RemoveByIndex(active_indices, inactive_indices) => {
+                BuffChange::RemoveByIndex(active_indices, inactive_indices) => {
                     active_buff_indices_for_removal = active_indices;
                     inactive_buff_indices_for_removal = inactive_indices;
                 },
-                buff::BuffChange::RemoveById(id) => {
+                BuffChange::RemoveById(id) => {
                     let some_predicate = |current_id: &buff::BuffId| *current_id == id;
                     for i in 0..buffs.active_buffs.len() {
                         if some_predicate(&mut buffs.active_buffs[i].id) {
@@ -733,6 +734,54 @@ pub fn handle_buff(server: &mut Server, uid: Uid, buff_change: buff::BuffChange)
                         }
                     }
                 },
+                BuffChange::RemoveByCategory(all_required, any_required) => {
+                    for i in 0..buffs.active_buffs.len() {
+                        let mut required_met = true;
+                        for required in &all_required {
+                            if !buffs.active_buffs[i]
+                                .cat_ids
+                                .iter()
+                                .any(|cat| cat == required)
+                            {
+                                required_met = false;
+                                break;
+                            }
+                        }
+                        let mut any_met = any_required.is_empty();
+                        for any in &any_required {
+                            if !buffs.active_buffs[i].cat_ids.iter().any(|cat| cat == any) {
+                                any_met = true;
+                                break;
+                            }
+                        }
+                        if required_met && any_met {
+                            active_buff_indices_for_removal.push(i);
+                        }
+                    }
+                    for i in 0..buffs.inactive_buffs.len() {
+                        let mut required_met = true;
+                        for required in &all_required {
+                            if !buffs.inactive_buffs[i]
+                                .cat_ids
+                                .iter()
+                                .any(|cat| cat == required)
+                            {
+                                required_met = false;
+                                break;
+                            }
+                        }
+                        let mut any_met = any_required.is_empty();
+                        for any in &any_required {
+                            if !buffs.inactive_buffs[i].cat_ids.iter().any(|cat| cat == any) {
+                                any_met = true;
+                                break;
+                            }
+                        }
+                        if required_met && any_met {
+                            inactive_buff_indices_for_removal.push(i);
+                        }
+                    }
+                },
             }
             let mut removed_active_buff_ids = Vec::new();
             while !active_buff_indices_for_removal.is_empty() {