Fixes digitigrade limbs not being butcherable, adds digi bone limb variants (#94842)

## About The Pull Request

As limbs rely on ``limb_id`` to fetch their meat info, digi limbs would
fail to do so and be unbutcherable since they use a unique digi ID from
a separate spritesheet. I've separated biological limb effects into a
separate var (or rather made one that acts an override for ``limb_id``),
so now they should be butcherable.

Butchered limbs now respect bodytypes of the original, and have unique
sprites to match that (currently this only matters for digi legs, plus
monkey creampie face sprites)

<img width="85" height="122" alt="image"
src="https://github.com/user-attachments/assets/a8766a62-e3f5-4265-964f-c48164f1bf6c"
/>

While at it I've also made some non-species limbs have butcher results -
living meat now drops a chunk of synthmeat, while psyker heads drop
their owner's original species' meat.
This commit is contained in:
SmArtKar
2026-01-14 19:25:19 +00:00
committed by GitHub
parent 26dbd3fb61
commit 84519a3b3f
8 changed files with 43 additions and 10 deletions
+8 -4
View File
@@ -49,6 +49,8 @@
var/is_invisible = FALSE
///The ID of a species used to generate the icon. Needs to match the icon_state portion in the limbs file!
var/limb_id = SPECIES_HUMAN
///ID of a species to use as an override for species-based biological logic, such as what species to pull the meat from, if our limb_id doesn't match
var/species_id = null
//Defines what sprite the limb should use if it is also sexually dimorphic.
var/limb_gender = "m"
///Is there a sprite difference between male and female?
@@ -314,12 +316,14 @@
return FALSE
return ..()
/obj/item/bodypart/proc/get_butcher_drops()
if(!isnull(butcher_drops))
/// Returns an assoc list of items dropped when the limb is butchered
/// force - Force an update of drops ignoring the cache
/obj/item/bodypart/proc/get_butcher_drops(force = FALSE)
if(!isnull(butcher_drops) && !force)
return butcher_drops
if (butcher_drop_cache[type])
if (butcher_drop_cache[type] && !force)
return butcher_drop_cache[type]
var/datum/species/species = GLOB.species_list[limb_id]
var/datum/species/species = GLOB.species_list[species_id || limb_id]
if (!species || !species.meat || !base_meat_amount)
return null
return list(species.meat = base_meat_amount)
+5 -3
View File
@@ -106,10 +106,12 @@
QDEL_NULL(worn_face_offset)
return ..()
/obj/item/bodypart/head/get_butcher_drops()
if(butcher_drops)
/obj/item/bodypart/head/get_butcher_drops(force = FALSE)
if(!isnull(butcher_drops) && !force)
return butcher_drops
var/datum/species/species = GLOB.species_list[limb_id]
if (butcher_drop_cache[type] && !force)
return butcher_drop_cache[type]
var/datum/species/species = GLOB.species_list[species_id || limb_id]
if (!species || !species.skinned_type)
return null
return list(species.skinned_type = 1)
+3 -3
View File
@@ -38,11 +38,11 @@
/// Which functional (i.e. flightpotion) wing types (if any) does this bodypart support? If count is >1 a radial menu is used to choose between all icons in list
var/list/wing_types = list(/obj/item/organ/wings/functional/angel)
/obj/item/bodypart/chest/get_butcher_drops()
/obj/item/bodypart/chest/get_butcher_drops(force = FALSE)
. = ..()
if(butcher_drops)
if(!isnull(butcher_drops) && !force)
return
var/datum/species/species = GLOB.species_list[limb_id]
var/datum/species/species = GLOB.species_list[species_id || limb_id]
if (!species || !species.skinned_type)
return
if (!islist(.))
@@ -78,6 +78,7 @@
/obj/item/bodypart/leg/left/digitigrade
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
species_id = SPECIES_LIZARD
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
footprint_sprite = FOOTPRINT_SPRITE_CLAWS
footstep_type = FOOTSTEP_MOB_CLAW
@@ -89,6 +90,7 @@
/obj/item/bodypart/leg/right/digitigrade
icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi'
limb_id = BODYPART_ID_DIGITIGRADE
species_id = SPECIES_LIZARD
bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE
footprint_sprite = FOOTPRINT_SPRITE_CLAWS
footstep_type = FOOTSTEP_MOB_CLAW
@@ -481,6 +481,10 @@
. = ..()
AddElement(/datum/element/blood_limb_overlay)
/obj/item/bodypart/leg/left/skeleton/nonfunctional/update_limb(dropping_limb = FALSE, is_creating = FALSE)
. = ..()
limb_id = ((bodyshape & BODYSHAPE_DIGITIGRADE) && owner?.is_digitigrade_squished()) ? initial(limb_id) : "[initial(limb_id)]_[BODYPART_ID_DIGITIGRADE]"
/obj/item/bodypart/leg/right/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
@@ -489,6 +493,10 @@
. = ..()
AddElement(/datum/element/blood_limb_overlay)
/obj/item/bodypart/leg/right/skeleton/nonfunctional/update_limb(dropping_limb = FALSE, is_creating = FALSE)
. = ..()
limb_id = ((bodyshape & BODYSHAPE_DIGITIGRADE) && owner?.is_digitigrade_squished()) ? initial(limb_id) : "[initial(limb_id)]_[BODYPART_ID_DIGITIGRADE]"
///MUSHROOM
/obj/item/bodypart/head/mushroom
limb_id = SPECIES_MUSHROOM
@@ -741,6 +749,9 @@
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
AddElement(/datum/element/living_limb_initialiser)
/obj/item/bodypart/arm/left/flesh/get_butcher_drops()
return list(/obj/item/food/meat/slab/synthmeat = 1)
/obj/item/bodypart/arm/right/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
@@ -750,6 +761,9 @@
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
AddElement(/datum/element/living_limb_initialiser)
/obj/item/bodypart/arm/right/flesh/get_butcher_drops()
return list(/obj/item/food/meat/slab/synthmeat = 1)
/obj/item/bodypart/leg/left/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
@@ -759,6 +773,9 @@
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
AddElement(/datum/element/living_limb_initialiser)
/obj/item/bodypart/leg/left/flesh/get_butcher_drops()
return list(/obj/item/food/meat/slab/synthmeat = 1)
/obj/item/bodypart/leg/right/flesh
limb_id = BODYPART_ID_MEAT
should_draw_greyscale = FALSE
@@ -767,3 +784,6 @@
. = ..()
ADD_TRAIT(src, TRAIT_IGNORED_BY_LIVING_FLESH, BODYPART_TRAIT)
AddElement(/datum/element/living_limb_initialiser)
/obj/item/bodypart/leg/right/flesh/get_butcher_drops()
return list(/obj/item/food/meat/slab/synthmeat = 1)