diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 9dad2926f8..efc25643f9 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -153,6 +153,7 @@
#define COMSIG_MOB_HUD_CREATED "mob_hud_created" //from base of mob/create_mob_hud(): ()
#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand" //from base of
#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack" //from base of /obj/item/attack(): (mob/M, mob/user)
+ #define COMPONENT_ITEM_NO_ATTACK 1
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 3a45e9bf60..9cb0c52b9a 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -39,23 +39,12 @@
if(..())
return TRUE
user.changeNext_move(CLICK_CD_MELEE)
- if(user.a_intent == INTENT_HARM && stat == DEAD && (butcher_results || guaranteed_butcher_results)) //can we butcher it?
- var/datum/component/butchering/butchering = I.GetComponent(/datum/component/butchering)
- if(butchering && butchering.butchering_enabled)
- to_chat(user, "You begin to butcher [src]...")
- playsound(loc, butchering.butcher_sound, 50, TRUE, -1)
- if(do_mob(user, src, butchering.speed) && Adjacent(I))
- butchering.Butcher(user, src)
- return 1
- else if(I.get_sharpness() && !butchering) //give sharp objects butchering functionality, for consistency
- I.AddComponent(/datum/component/butchering, 80 * I.toolspeed)
- attackby(I, user, params) //call the attackby again to refresh and do the butchering check again
- return
return I.attack(src, user)
/obj/item/proc/attack(mob/living/M, mob/living/user)
- SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user)
+ if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
+ return
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
if(item_flags & NOBLUDGEON)
return
diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm
index 372fa8e283..621aededb2 100644
--- a/code/datums/components/butchering.dm
+++ b/code/datums/components/butchering.dm
@@ -4,8 +4,9 @@
var/bonus_modifier = 0 //percentage increase to bonus item chance
var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
var/butchering_enabled = TRUE
+ var/can_be_blunt = FALSE
-/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled)
+/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
if(_speed)
speed = _speed
if(_effectiveness)
@@ -16,6 +17,22 @@
butcher_sound = _butcher_sound
if(disabled)
butchering_enabled = FALSE
+ if(_can_be_blunt)
+ can_be_blunt = _can_be_blunt
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/onItemAttack)
+
+/datum/component/butchering/proc/onItemAttack(obj/item/source, mob/living/M, mob/living/user)
+ if(user.a_intent == INTENT_HARM && M.stat == DEAD && (M.butcher_results || M.guaranteed_butcher_results)) //can we butcher it?
+ if(butchering_enabled && (can_be_blunt || source.is_sharp()))
+ INVOKE_ASYNC(src, .proc/startButcher, source, M, user)
+ return COMPONENT_ITEM_NO_ATTACK
+
+/datum/component/butchering/proc/startButcher(obj/item/source, mob/living/M, mob/living/user)
+ to_chat(user, "You begin to butcher [M]...")
+ playsound(M.loc, butcher_sound, 50, TRUE, -1)
+ if(do_mob(user, M, speed) && M.Adjacent(source))
+ Butcher(user, M)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
var/turf/T = meat.drop_location()
@@ -50,3 +67,23 @@
/datum/component/butchering/proc/ButcherEffects(mob/living/meat) //extra effects called on butchering, override this via subtypes
return
+
+///Special snowflake component only used for the recycler.
+/datum/component/butchering/recycler
+
+/datum/component/butchering/recycler/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
+ if(!istype(parent, /obj/machinery/recycler)) //EWWW
+ return COMPONENT_INCOMPATIBLE
+ . = ..()
+ if(. == COMPONENT_INCOMPATIBLE)
+ return
+ RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/onCrossed)
+
+/datum/component/butchering/recycler/proc/onCrossed(datum/source, mob/living/L)
+ if(!istype(L))
+ return
+ var/obj/machinery/recycler/eater = parent
+ if(eater.safety_mode || (eater.stat & (BROKEN|NOPOWER))) //I'm so sorry.
+ return
+ if(L.stat == DEAD && (L.butcher_results || L.guaranteed_butcher_results))
+ Butcher(src, L)
\ No newline at end of file
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index d39de4d37d..c8beeb8c83 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -18,8 +18,8 @@
var/item_recycle_sound = 'sound/items/welder.ogg'
/obj/machinery/recycler/Initialize()
+ AddComponent(/datum/component/butchering/recycler, 1, amount_produced,amount_produced/5)
AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_PLASMA, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_URANIUM, MAT_BANANIUM, MAT_TITANIUM, MAT_BLUESPACE, MAT_PLASTIC), INFINITY, FALSE, null, null, null, TRUE)
- AddComponent(/datum/component/butchering, 1, amount_produced,amount_produced/5)
. = ..()
update_icon()
req_one_access = get_all_accesses() + get_all_centcom_access()
@@ -35,7 +35,7 @@
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = mat_mod
amount_produced = min(50, amt_made) + 50
- var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering)
+ var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering/recycler)
butchering.effectiveness = amount_produced
butchering.bonus_modifier = amount_produced/5
@@ -83,20 +83,24 @@
is_powered = FALSE
icon_state = icon_name + "[is_powered]" + "[(blood ? "bld" : "")]" // add the blood tag at the end
-/obj/machinery/recycler/Bumped(atom/movable/AM)
-
- if(stat & (BROKEN|NOPOWER))
- return
+/obj/machinery/recycler/CanPass(atom/movable/AM)
+ . = ..()
if(!anchored)
return
- if(safety_mode)
- return
var/move_dir = get_dir(loc, AM.loc)
if(move_dir == eat_dir)
- eat(AM)
+ return TRUE
+
+/obj/machinery/recycler/Crossed(atom/movable/AM)
+ eat(AM)
+ . = ..()
/obj/machinery/recycler/proc/eat(atom/AM0, sound=TRUE)
+ if(stat & (BROKEN|NOPOWER))
+ return
+ if(safety_mode)
+ return
var/list/to_eat
if(isitem(AM0))
to_eat = AM0.GetAllContentsIgnoring(GLOB.typecache_mob)
@@ -194,9 +198,6 @@
// Instantly lie down, also go unconscious from the pain, before you die.
L.Unconscious(100)
L.adjustBruteLoss(crush_damage)
- if(L.stat == DEAD && (L.butcher_results || L.guaranteed_butcher_results))
- var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering)
- butchering.Butcher(src,L)
/obj/machinery/recycler/deathtrap
name = "dangerous old crusher"
diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm
index 4044951c42..812a9b0834 100644
--- a/code/game/mecha/equipment/tools/mining_tools.dm
+++ b/code/game/mecha/equipment/tools/mining_tools.dm
@@ -20,7 +20,7 @@
/obj/item/mecha_parts/mecha_equipment/drill/Initialize()
. = ..()
- AddComponent(/datum/component/butchering, 50, 100)
+ AddComponent(/datum/component/butchering, 50, 100, null, null, TRUE)
/obj/item/mecha_parts/mecha_equipment/drill/action(atom/target)
if(!action_checks(target))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index a9056975b1..c5d198c05f 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -81,6 +81,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/heat = 0
+ ///All items with sharpness of IS_SHARP or higher will automatically get the butchering component.
var/sharpness = IS_BLUNT
var/tool_behaviour = NONE
@@ -139,6 +140,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
else if (!istype(embedding, /datum/embedding_behavior))
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
+ if(sharpness) //give sharp objects butchering functionality, for consistency
+ AddComponent(/datum/component/butchering, 80 * toolspeed)
+
/obj/item/Destroy()
item_flags &= ~DROPDEL //prevent reqdels
if(ismob(loc))
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index 7eb35ed06b..5bccf91868 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -23,8 +23,8 @@
else
if(attack_verb_off.len)
attack_verb = attack_verb_off
- if(get_sharpness())
- AddComponent(/datum/component/butchering, 50, 100, 0, hitsound, !active)
+ if(sharpness)
+ AddComponent(/datum/component/butchering, 50, 100, 0, hitsound)
/obj/item/melee/transforming/attack_self(mob/living/carbon/user)
if(transform_weapon(user))
@@ -65,13 +65,6 @@
icon_state = initial(icon_state)
w_class = initial(w_class)
total_mass = initial(total_mass)
- if(get_sharpness())
- var/datum/component/butchering/BT = LoadComponent(/datum/component/butchering)
- BT.butchering_enabled = TRUE
- else
- var/datum/component/butchering/BT = GetComponent(/datum/component/butchering)
- if(BT)
- BT.butchering_enabled = FALSE
transform_messages(user, supress_message_text)
add_fingerprint(user)
return TRUE
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index fece60f268..20cc61d743 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -178,7 +178,10 @@
/obj/item/pen/edagger/Initialize()
. = ..()
- AddComponent(/datum/component/butchering, 60, 100, 0, 'sound/weapons/blade1.ogg', TRUE)
+ AddComponent(/datum/component/butchering, 60, 100, 0, 'sound/weapons/blade1.ogg')
+
+/obj/item/pen/edagger/get_sharpness()
+ return on * sharpness
/obj/item/pen/edagger/attack_self(mob/living/user)
if(on)
@@ -201,8 +204,6 @@
throwforce = 35
playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
to_chat(user, "[src] is now active.")
- var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
- butchering.butchering_enabled = on
update_icon()
/obj/item/pen/edagger/update_icon()