///////////////Butcher Datums////////////////////////////////////////////////////////////////
//When giving a mob a special butcher product, like goliath plates, the mob must be given its own get_butchering_products() proc which returns a list of /datum/butchering_product.
//The mob's butchering_drops list is made from get_butchering_products() when it dies. Humans however get it when they're created.
/datum/butchering_product
var/obj/item/result
//What item this is for
var/verb_name
//Something like "skin", don't name this "Butcher" please
var/verb_gerund
//Something like "skinning"
var/amount = 1
var/initial_amount = 1
//How much results you can spawn before this datum disappears
var/stored_in_organ
//Example value: LIMB_HEAD or "arm". When an organ with the same type is cut off, this object will be transferred to it.
var/butcher_time = 20
/datum/butchering_product/New()
..()
initial_amount = amount
/datum/butchering_product/proc/spawn_result(location, mob/parent)
if(amount > 0)
amount--
return new result(location)
//This is added to the description of dead mobs! It's important to add a space at the end (like this: "It has been skinned. ").
/datum/butchering_product/proc/desc_modifier(mob/parent, mob/user) //User - the guy who is looking at Parent
return
//==============Teeth============
/datum/butchering_product/teeth
result = /obj/item/stack/teeth
verb_name = "harvest teeth"
verb_gerund = "removing teeth from"
stored_in_organ = LIMB_HEAD //Cutting a LIMB_HEAD off will transfer teeth to the head object
/datum/butchering_product/teeth/desc_modifier(mob/parent, mob/user)
if(amount == initial_amount)
return
if(!isliving(parent))
return
var/mob/living/L = parent
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/datum/organ/external/head = H.get_organ(LIMB_HEAD)
if((head.status & ORGAN_DESTROYED) || !head)
return //If he has no head, you can't see whether he has teeth or not!
var/obj/item/clothing/mask/M = H.wear_mask
if(istype(M) && is_slot_hidden(M.body_parts_covered,MOUTH))
return //If his mouth is covered, we can't see his teeth
var/pronoun = "Its"
if(L.gender == MALE)
pronoun = "His"
if(L.gender == FEMALE)
pronoun = "Her"
if(amount == 0)
return "[pronoun] teeth are gone. "
else
if(parent.Adjacent(user))
return "[(initial_amount - amount)] of [lowertext(pronoun)] teeth are missing."
else
return "Some of [lowertext(pronoun)] teeth are missing. "
#define ALL_TEETH -1
/datum/butchering_product/teeth/spawn_result(location, mob/parent, drop_amount = ALL_TEETH)
if(amount <= 0)
return
var/obj/item/stack/teeth/T = new(location)
T.update_name(parent) //Change name of the teeth - from the default "teeth" to "corgi teeth", for example
if(drop_amount == ALL_TEETH) //Drop ALL teeth
T.amount = amount
amount = 0
else //Drop a random amount
var/actual_amount = min(src.amount, drop_amount)
T.amount = actual_amount
src.amount -= actual_amount
return T
/datum/butchering_product/teeth/few/New()
amount = rand(4,8)
..()
/datum/butchering_product/teeth/bunch/New()
amount = rand(8,16)
..()
/datum/butchering_product/teeth/lots/New()
amount = rand(16,24)
..()
/datum/butchering_product/teeth/human/New()
amount = 32
..()
#undef ALL_TEETH
//===============Skin=============
/datum/butchering_product/skin
result = /obj/item/stack/sheet/animalhide
verb_name = "skin"
verb_gerund = "skinning"
/datum/butchering_product/skin/desc_modifier(mob/parent)
if(!amount)
var/pronoun = "It"
if(parent.gender == MALE)
pronoun = "He"
if(parent.gender == FEMALE)
pronoun = "She"
return "[pronoun] has been skinned. "
/datum/butchering_product/skin/cat
result = /obj/item/stack/sheet/animalhide/cat
/datum/butchering_product/skin/cat/lots
amount = 3
/datum/butchering_product/skin/corgi
result = /obj/item/stack/sheet/animalhide/corgi
/datum/butchering_product/skin/lizard
result = /obj/item/stack/sheet/animalhide/lizard
/datum/butchering_product/skin/lizard/lots
amount = 3
/datum/butchering_product/skin/human
result = /obj/item/stack/sheet/animalhide/human
amount = 3
/datum/butchering_product/skin/human/spawn_result(location, mob/parent)
if(!amount)
return
amount--
if(ishuman(parent))
var/mob/living/carbon/human/H = parent
var/obj/item/stack/sheet/animalhide/human/A = new result(location)
if(!isjusthuman(H) && H.species) //Grey skin, unathi skin, etc.
A.name = H.species.name ? "[lowertext(H.species.name)] skin" : A.name
A.source_string = H.species.name ? lowertext(H.species.name) : A.source_string
else
if(H.mind && H.mind.assigned_role && H.mind.assigned_role != "MODE") //CLOWN LEATHER, ASSISTANT LEATHER, CAPTAIN LEATHER
A.name = "[lowertext(H.mind.assigned_role)] skin"
A.source_string = lowertext(H.mind.assigned_role)
if (H.species)
A.skin_color = H.species.flesh_color
A.color = A.skin_color
/datum/butchering_product/skin/gondola
result = /obj/item/stack/sheet/animalhide/gondola
amount = 2
/datum/butchering_product/skin/deer
result = /obj/item/stack/sheet/animalhide/deer
amount = 3
initial_amount = 3
/datum/butchering_product/skin/goliath
result = /obj/item/asteroid/goliath_hide
/datum/butchering_product/skin/basilisk
result = /obj/item/asteroid/basilisk_hide
verb_name = "break crystals off"
verb_gerund = "breaking crystals off"
/datum/butchering_product/skin/bear
result = /obj/item/clothing/head/bearpelt/real
/datum/butchering_product/skin/bear/spare
result = /obj/item/clothing/head/bearpelt/real/spare
/datum/butchering_product/skin/bear/spare/spawn_result(location, mob/parent)
..()
parent.dust()
/datum/butchering_product/skin/bear/brownbear
result = /obj/item/clothing/head/bearpelt/brown/real
/datum/butchering_product/skin/bear/panda
result = /obj/item/clothing/head/bearpelt/panda
/datum/butchering_product/skin/bear/polarbear
result = /obj/item/clothing/head/bearpelt/polar
/datum/butchering_product/skin/xeno
result = /obj/item/stack/sheet/xenochitin
verb_name = "remove chitin"
verb_gerund = "removing chitin"
/datum/butchering_product/skin/xeno/New()
amount = rand(1,3)
/datum/butchering_product/skin/xeno/spawn_result(location)
..()
if(!amount) //If all chitin was removed
new /obj/item/stack/sheet/animalhide/xeno(location)
/datum/butchering_product/skin/monkey
result = /obj/item/stack/sheet/animalhide/monkey
/datum/butchering_product/skin/wolf
result = /obj/item/clothing/head/wolfpelt
//--------------Spider legs-------
/datum/butchering_product/spider_legs
result = /obj/item/weapon/reagent_containers/food/snacks/meat/spiderleg
verb_name = "remove legs from"
verb_gerund = "removing legs from"
amount = 8 //Amount of legs that all normal spiders have
butcher_time = 10
/datum/butchering_product/spider_legs/desc_modifier()
if(amount < 8)
return "It only has [amount] [amount==1 ? "leg" : "legs"]. "
//=============Alien claws========
/datum/butchering_product/xeno_claw
result = /obj/item/xenos_claw
verb_name = "declaw"
verb_gerund = "declawing"
/datum/butchering_product/xeno_claw/desc_modifier()
if(!amount)
return "Its claws have been cut off. "
//======frog legs
/datum/butchering_product/frog_leg
result = /obj/item/weapon/reagent_containers/food/snacks/frog_leg
verb_name = "remove legs from"
verb_gerund = "removing legs from"
amount = 2 //not a magic number, frogs have 2 legs
butcher_time = 10
/datum/butchering_product/frog_leg/desc_modifier()
if(amount < 2)
return "It only has [amount] [amount==1 ? "leg" : "legs"]. "
//======hivelord core
/datum/butchering_product/hivelord_core
result = /obj/item/asteroid/hivelord_core
verb_name = "remove the core from"
verb_gerund = "removing the core from"
butcher_time = 2
/datum/butchering_product/hivelord_core/desc_modifier()
if(!amount)
return "Its core has been taken. "
//======deer head
/datum/butchering_product/deer_head
result = /obj/item/deer_head
verb_name = "remove head"
verb_gerund = "removing the head from"
amount = 1
butcher_time = 15
/datum/butchering_product/deer_head/desc_modifier()
if(!amount)
return "Its head has been taken. "
/datum/butchering_product/deer_head/spawn_result(location, mob/parent)
if(isliving(parent))
var/mob/living/L = parent
L.update_icons()
L.mob_property_flags |= MOB_NO_LAZ
if(amount > 0)
amount--
var/obj/I = new result(location)
if(istype(parent, /mob/living/simple_animal/hostile/deer))
var/mob/living/simple_animal/hostile/deer/D = parent
if(D.icon_living == "deer_flower")
I.icon_state = "deer-head-flower"
else if(istype(D, /mob/living/simple_animal/hostile/deer/flesh))
I.icon_state = "deer-head-flesh"
//======Rabbits
/datum/butchering_product/rabbit_ears
result = /obj/item/clothing/head/rabbitears
verb_name = "remove ears"
verb_gerund = "removing the ears from"
amount = 1
butcher_time = 10
/datum/butchering_product/rabbit_foot
result = /obj/item/clothing/accessory/rabbit_foot
verb_name = "remove foot"
verb_gerund = "removing the foot from"
amount = 1 //Only the back left foot is considered lucky.
butcher_time = 10
/datum/butchering_product/snail_carapace
result = /obj/item/clothing/head/helmet/snail_helm
verb_name = "remove carapace"
verb_gerund = "removing the carapace from"
butcher_time = 10
/////////////////////////////////Butcher procs/////////////////////////////////////////////////
//butcherCarveStep() can be used to change how long meat takes to butcher from individual mobs
//butcherMeat() and butcherProduct() are able to be called without the rest of the process.
//Call butcherProduct() with mod = TRUE to have it search for children of the butcher_product you passed to it in the mob's product list.
//modMeat() and modProduct() can be easily used to add properties to butcher results based off the mob it came from.
#define BUTCHER_MEAT 1
#define BUTCHER_SPEED "bSpeed"
#define BUTCHER_TOOL "bTool"
#define BUTCHER_TNAME "bTName"
/mob/living/proc/butcher()
set category = "Object"
set name = "Butcher"
set src in oview(1)
var/mob/living/user = usr
if(!butcherCheck(user))
return
var/butcherTool = null
var/toolName = null
var/speed_mod = 0
var/list/butchValues = butcherValueStep(user)
if(!length(butchValues))
return
if(butchValues[BUTCHER_SPEED])
speed_mod = butchValues[BUTCHER_SPEED]
if(butchValues[BUTCHER_TOOL])
butcherTool = butchValues[BUTCHER_TOOL]
if(butchValues[BUTCHER_TNAME])
toolName = butchValues[BUTCHER_TNAME]
var/list/butcherOptions = butcherMenuStep(user)
if(!length(butcherOptions))
return
var/datum/butchering_product/typeOfCarve = butcherChooseStep(user, butcherOptions, butcherTool)
if(!typeOfCarve)
return
if(butcherCarveStep(user, speed_mod, typeOfCarve, toolName))
if(typeOfCarve != BUTCHER_MEAT)
butcherProduct(user, typeOfCarve)
else
butcherMeat(user, toolName)
/mob/living/proc/butcherCheck(mob/user, var/ourTool = null)
if(!istype(user))
return FALSE
if(user.isUnconscious() || user.restrained())
return FALSE
if(!Adjacent(user))
return FALSE
if(being_butchered)
to_chat(user, "[src] is already being butchered.")
return FALSE
if(!can_butcher)
to_chat(user, "You can't butcher [src]!")
return FALSE
if(ourTool && ishuman(user))
var/mob/living/carbon/human/H = user
if(ourTool != H.get_active_hand())
return FALSE
return TRUE
/mob/living/proc/butcherValueStep(mob/user)
var/butchSpeed = 0
var/obj/item/theTool = null
var/toolName = null
if(ishuman(user))
var/mob/living/carbon/human/H = user
theTool = H.get_active_hand()
if(theTool)
butchSpeed = theTool.is_sharp()
toolName = theTool.name
if(!butchSpeed)
to_chat(user, "You can't butcher \the [src] with this!")
return
if(H.organ_has_mutation(LIMB_HEAD, M_BEAK))
var/obj/item/mask = H.get_item_by_slot(slot_wear_mask)
if(!mask || !(mask.body_parts_covered & MOUTH)) //If our mask doesn't cover mouth, we can use our beak to help us while butchering
butchSpeed += 0.25
if(!toolName)
toolName = "beak"
if(H.organ_has_mutation(H.get_active_hand_organ(), M_CLAWS))
if(!istype(H.gloves))
butchSpeed += 0.25
if(!toolName)
toolName = "claws"
if(isgrue(H))
toolName = "grue"
butchSpeed += 0.5
else
butchSpeed = 0.5
if(!butchSpeed)
return
return list(BUTCHER_SPEED = butchSpeed, BUTCHER_TOOL = theTool, BUTCHER_TNAME = toolName)
/mob/living/proc/butcherMenuStep(mob/user)
var/list/butcherType = list()
if(meat_type && meat_amount > meat_taken)
butcherType += "Butcher"
for(var/datum/butchering_product/BP in butchering_drops)
if(BP.amount)
butcherType += BP.verb_name
if(!butcherType.len)
to_chat(user, "There's nothing to butcher.")
return
butcherType += "Cancel"
return butcherType
/mob/living/proc/butcherChooseStep(mob/user, butcherOptions, butcherTool)
var/choice = input(user,"What would you like to do with \the [src]?","Butchering") in null|butcherOptions
if(!butcherCheck(user, butcherTool))
return 0
if(choice == "Cancel")
return 0
if(choice == "Butcher")
return BUTCHER_MEAT
if(!choice || !butchering_drops.len)
return 0
var/theProduct = getProduct(choice)
return theProduct
/mob/living/proc/getProduct(choice)
for(var/datum/butchering_product/BP in butchering_drops)
if(BP.verb_name == choice)
return BP
/mob/living/proc/butcherCarveStep(mob/user, speed_mod, datum/butchering_product/typeOfCarve, toolName, var/butcherTime = 20)
var/butcherWord = null
if(typeOfCarve == BUTCHER_MEAT)
butcherWord = "butchering"
butcherTime *= size
if(meat_taken >= meat_amount)
to_chat(user, "There's no meat left!.")
return
else
butcherWord = typeOfCarve.verb_gerund
butcherTime = typeOfCarve.butcher_time
if(!butcherWord)
return FALSE
user.visible_message("[user] starts [butcherWord] \the [src][toolName ? " with \the [toolName]" : ""].",\
"You start [butcherWord] \the [src].")
being_butchered = TRUE
if(!do_after(user, src, butcherTime / speed_mod))
to_chat(user, "You stop [butcherWord] \the [src].")
being_butchered = FALSE
return FALSE
being_butchered = FALSE
to_chat(user, "You finish [butcherWord] \the [src].")
return TRUE
/mob/living/proc/butcherMeat(mob/user, var/tool_name)
var/theMeat = drop_meat(loc)
if(theMeat)
if(tool_name)
if(!advanced_butchery)
advanced_butchery = new()
advanced_butchery.Add(tool_name)
modMeat(user, theMeat)
meatEndStep(user)
/mob/living/proc/drop_meat(location)
if(!meat_type)
return
if(meat_taken >= meat_amount)
return
meat_taken++
if(!ispath(meat_type, /obj/item/weapon/reagent_containers/food/snacks/meat)) //For 2 years sheet/bone thought "skeleton" was a number
var/NM = new meat_type(location)
return NM
var/obj/item/weapon/reagent_containers/food/snacks/meat/M = null
M = make_meat(location)
if(length(virus2))
for(var/ID in virus2)
var/datum/disease2/disease/D = virus2[ID]
if(D.spread & SPREAD_BLOOD)
M.infect_disease2(D,1,"(Butchered, from [src])",0)
if(reagents)
reagents.trans_to(M, round(reagents.total_volume * (meat_amount/meat_taken), 1))
return M
/mob/living/proc/make_meat(location)
var/ourMeat = new meat_type(location)
return ourMeat
/mob/living/proc/meatEndStep(mob/user) //Exists for simple_animals
to_chat(user, "You cut a chunk of meat out of \the [src].")
/mob/living/proc/butcherProduct(mob/user, var/datum/butchering_product/theCarve, var/mod = FALSE)
var/datum/butchering_product/toCarve = null
if(mod) //This is here so things can directly call this proc without needing to be overly specific
for(var/datum/butchering_product/BP in butchering_drops)
if(istype(BP, theCarve) && BP.amount)
toCarve = BP
if(!toCarve)
return FALSE
else
toCarve = theCarve
toCarve.spawn_result(loc, src)
update_icons()
modProduct(user, toCarve)
/mob/living/proc/modProduct(mob/user, theProduct) //These procs can easily be used to give features to meat/products based on the animal
return
/mob/living/proc/modMeat(mob/user, theMeat)
return
#undef BUTCHER_MEAT
#undef BUTCHER_SPEED
#undef BUTCHER_TOOL
#undef BUTCHER_TNAME
///////////////////////END PROCS///////////////////////////////////////////////////