diff --git a/code/__HELPERS/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm
index 819619d9207..ffc14b71a79 100644
--- a/code/__HELPERS/trait_helpers.dm
+++ b/code/__HELPERS/trait_helpers.dm
@@ -278,7 +278,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_SUPERMATTER_IMMUNE "supermatter_immune"
//***** ITEM TRAITS *****//
-#define TRAIT_BUTCHERS_HUMANS "butchers_humans"
#define TRAIT_CMAGGED "cmagged"
/// An item that is being wielded.
#define TRAIT_WIELDED "wielded"
diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm
index 1485e84fb54..397cda59005 100644
--- a/code/_globalvars/traits.dm
+++ b/code/_globalvars/traits.dm
@@ -132,7 +132,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/obj/item = list(
"TRAIT_SHOW_WIRE_INFO" = TRAIT_SHOW_WIRE_INFO,
"TRAIT_SUPERMATTER_IMMUNE" = TRAIT_SUPERMATTER_IMMUNE,
- "TRAIT_BUTCHER_HUMANS" = TRAIT_BUTCHERS_HUMANS,
"TRAIT_CMAGGED" = TRAIT_CMAGGED,
"TRAIT_OBSCURED_WIRES" = TRAIT_OBSCURED_WIRES,
"TRAIT_XENO_INTERACTABLE" = TRAIT_XENO_INTERACTABLE,
diff --git a/code/datums/elements/butchers_humans.dm b/code/datums/elements/butchers_humans.dm
new file mode 100644
index 00000000000..d919fb31425
--- /dev/null
+++ b/code/datums/elements/butchers_humans.dm
@@ -0,0 +1,54 @@
+/// An element for items that butcher human corpses into meat when attacked on
+/// harm intent.
+/datum/element/butchers_humans
+ element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
+
+/datum/element/butchers_humans/Attach(datum/target)
+ . = ..()
+ if(!isitem(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(target, COMSIG_ATTACK, PROC_REF(on_attack))
+
+/datum/element/butchers_humans/Detach(datum/source, force)
+ . = ..()
+ UnregisterSignal(source, list(COMSIG_PARENT_EXAMINE, COMSIG_ATTACK))
+
+/datum/element/butchers_humans/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER // COMSIG_PARENT_EXAMINE
+ examine_list += "Can be used to butcher dead people into meat while on harm intent."
+
+/datum/element/butchers_humans/proc/on_attack(datum/source, mob/living/victim, mob/living/user, params)
+ SIGNAL_HANDLER // COMSIG_ATTACK
+
+ if(!ishuman(victim) || !isitem(source))
+ return
+
+ var/mob/living/carbon/human/human = victim
+ var/obj/item/item = source
+
+ if(human.stat == DEAD && user.a_intent == INTENT_HARM)
+ var/obj/item/food/meat/human/newmeat = new /obj/item/food/meat/human(get_turf(human))
+ newmeat.name = human.real_name + newmeat.name
+ newmeat.reagents.add_reagent("nutriment", (human.nutrition / 15) / 3)
+ human.reagents.trans_to(newmeat, round((human.reagents.total_volume) / 3, 1))
+ human.add_mob_blood(human)
+ human.meatleft--
+
+ if(human.meatleft)
+ to_chat(user, "You hack off a chunk of meat from [human]!")
+ // fallthrough so we get side-effects like blood splatter and limb
+ // flyoff from human attacked_by while we still have a corpse around
+ return
+ human.send_item_attack_message(item, user)
+
+ // Handle a few tiny things normally done in attack chain
+ user.do_attack_animation(human)
+ item.add_fingerprint(user)
+ if(item.hitsound)
+ playsound(get_turf(item), item.hitsound, item.get_clamped_volume(), TRUE, extrarange = item.stealthy_audio ? SILENCED_SOUND_EXTRARANGE : -1, falloff_distance = 0)
+ add_attack_logs(user, human, "Chopped up into meat with [item.name] ([uppertext(user.a_intent)])", human.ckey ? null : ATKLOG_ALMOSTALL)
+ to_chat(user, "You reduce [human] to a pile of meat!")
+ qdel(human)
+ return COMPONENT_CANCEL_ATTACK_CHAIN
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 5a45e9a3d87..a875dce2b36 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -299,9 +299,6 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
. += "Has [length(attached_bits)] bits attached."
. += "Bits can be removed with Alt-Click."
- if(HAS_TRAIT(src, TRAIT_BUTCHERS_HUMANS))
- . += "Can be used to butcher dead people into meat while on harm intent."
-
/obj/item/burn()
if(!QDELETED(src))
var/turf/T = get_turf(src)
diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm
index 357ac4ca247..60af27cd6ad 100644
--- a/code/game/objects/items/weapons/kitchen.dm
+++ b/code/game/objects/items/weapons/kitchen.dm
@@ -183,7 +183,7 @@
/obj/item/kitchen/knife/butcher/meatcleaver/Initialize(mapload)
. = ..()
- ADD_TRAIT(src, TRAIT_BUTCHERS_HUMANS, ROUNDSTART_TRAIT)
+ AddElement(/datum/element/butchers_humans)
/obj/item/kitchen/knife/combat
name = "combat knife"
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index e8215cd2c2e..a63bd7a852e 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -521,7 +521,7 @@
/obj/item/butcher_chainsaw/Initialize(mapload)
. = ..()
- ADD_TRAIT(src, TRAIT_BUTCHERS_HUMANS, ROUNDSTART_TRAIT)
+ AddElement(/datum/element/butchers_humans)
AddComponent(/datum/component/two_handed, \
force_wielded = 40, \
force_unwielded = force, \
diff --git a/code/modules/food_and_drinks/food/foods/meat.dm b/code/modules/food_and_drinks/food/foods/meat.dm
index d49ae88550d..95626d4c7d0 100644
--- a/code/modules/food_and_drinks/food/foods/meat.dm
+++ b/code/modules/food_and_drinks/food/foods/meat.dm
@@ -34,8 +34,6 @@
/obj/item/food/meat/human
name = "-meat"
- var/subjectname = ""
- var/subjectjob = null
tastes = list("salty meat" = 1)
/obj/item/food/meat/slab/meatproduct
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 8ab535fd81a..128ecc4c037 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -462,24 +462,9 @@ emp_act
return ..()
/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user, def_zone)
- if(!I || !user)
+ if(!I || !user || QDELETED(src))
return
- if(HAS_TRAIT(I, TRAIT_BUTCHERS_HUMANS) && stat == DEAD && user.a_intent == INTENT_HARM)
- var/obj/item/food/meat/human/newmeat = new /obj/item/food/meat/human(get_turf(loc))
- newmeat.name = real_name + newmeat.name
- newmeat.subjectname = real_name
- newmeat.subjectjob = job
- newmeat.reagents.add_reagent("nutriment", (nutrition / 15) / 3)
- reagents.trans_to(newmeat, round((reagents.total_volume) / 3, 1))
- add_mob_blood(src)
- --meatleft
- to_chat(user, "You hack off a chunk of meat from [name]")
- if(!meatleft)
- add_attack_logs(user, src, "Chopped up into meat")
- qdel(src)
- return
-
var/obj/item/organ/external/affecting = get_organ(ran_zone(user.zone_selected))
// if the targeted limb doesn't exist, pick a new one at random so you don't have to swap target zone
diff --git a/paradise.dme b/paradise.dme
index 514f219cc13..b648f45c506 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -563,6 +563,7 @@
#include "code\datums\elements\atmos_requirements.dm"
#include "code\datums\elements\body_temperature.dm"
#include "code\datums\elements\bombable_turf.dm"
+#include "code\datums\elements\butchers_humans.dm"
#include "code\datums\elements\connect_loc.dm"
#include "code\datums\elements\decal_element.dm"
#include "code\datums\elements\earhealing.dm"