code:
/// Can this limb suffer dismemberment?
/obj/item/bodypart/proc/can_dismember(obj/item/I)
	. = TRUE
	if(!dismemberable)
		return FALSE

/// Does this limb leave a stump behind, when dismembered?
/obj/item/bodypart/proc/can_stump(obj/item/I)
	return !(limb_flags & BODYPART_NO_STUMP)

/// Dismember a limb
/obj/item/bodypart/proc/dismember(dam_type = BRUTE, silent = TRUE, destroy = FALSE, wounding_type = WOUND_SLASH)
	if(!owner || !can_dismember())
		return FALSE

	//owner will get nulled
	var/mob/living/carbon/was_owner = owner
	if(was_owner.status_flags & GODMODE)
		return FALSE
	if(HAS_TRAIT(was_owner, TRAIT_NODISMEMBER))
		return FALSE

	var/obj/item/bodypart/affecting = was_owner.get_bodypart(parent_body_zone)
	affecting.receive_damage(clamp(brute_dam/2 * affecting.body_damage_coeff, 15, 50), clamp(burn_dam/2 * affecting.body_damage_coeff, 0, 50), wound_bonus=CANT_WOUND) //Damage the parent based on limb's existing damage
	if(!silent)
		was_owner.visible_message(span_danger("[was_owner]'s [name] is violently dismembered!"))
		playsound(get_turf(was_owner), 'modular_septic/sound/gore/dismember.ogg', 80, TRUE)

	INVOKE_ASYNC(was_owner, /mob/living.proc/death_scream)
	SEND_SIGNAL(was_owner, COMSIG_ADD_MOOD_EVENT, "dismembered", /datum/mood_event/dismembered)
	drop_limb(dismembered = TRUE, destroyed = destroy, wounding_type = wounding_type)
	was_owner.update_equipment_speed_mods() // Update in case speed affecting item unequipped by dismemberment

	if(QDELETED(src)) //Could have dropped into lava/explosion/chasm/whatever
		return TRUE

	add_mob_blood(was_owner)
	was_owner.bleed(rand(10, 20)) // let the arterial bleeding fuck the bastard over
	var/direction = pick(GLOB.cardinals)
	var/t_range = rand(2,max(throw_range/2, 2))
	var/turf/target_turf = get_turf(src)
	for(var/i in 1 to t_range-1)
		var/turf/new_turf = get_step(target_turf, direction)
		if(!new_turf)
			break
		target_turf = new_turf
		if(new_turf.density)
			break
	var/old_throwforce = throwforce
	throwforce = 0
	throw_at(target_turf, throw_range, throw_speed, callback = CALLBACK(src, .proc/dismember_done, old_throwforce))
	return TRUE

/// Resets damage after being dismembered and thrown
/obj/item/bodypart/proc/dismember_done(new_throwforce = initial(throwforce))
	throwforce = new_throwforce

/// Limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in.
/obj/item/bodypart/proc/drop_limb(special = FALSE, dismembered = FALSE, ignore_children = FALSE, destroyed = FALSE, wounding_type = WOUND_SLASH)
	. = FALSE
	if(!owner)
		return

	var/atom/Tsec = owner.drop_location()
	var/mob/living/carbon/was_owner = owner
	SEND_SIGNAL(was_owner, COMSIG_CARBON_REMOVE_LIMB, src, dismembered)
	update_limb(TRUE, was_owner)
	owner.remove_bodypart(src)

	if(held_index)
		if(LAZYACCESS(owner.hand_bodyparts, held_index) == src)
			// We only want to do this if the limb being removed is the active hand part.
			// This catches situations where limbs are "hot-swapped" such as augmentations and roundstart prosthetics.
			owner.dropItemToGround(owner.get_item_for_held_index(held_index), TRUE)
			owner.hand_bodyparts[held_index] = null
		if(owner.hud_used)
			var/atom/movable/screen/inventory/hand/R = was_owner.hud_used.hand_slots["[held_index]"]
			if(R)
				R.update_appearance()
	if(stance_index)
		if(LAZYACCESS(owner.leg_bodyparts, stance_index) == src)
			owner.leg_bodyparts[stance_index] = null
	if(sight_index)
		if(LAZYACCESS(owner.eye_bodyparts, sight_index) == src)
			owner.eye_bodyparts[sight_index] = null

	for(var/citem in cavity_items)
		var/obj/item/cavity_item = citem
		if(istype(Tsec))
			cavity_item.forceMove(Tsec)
		else
			qdel(cavity_item)
		LAZYREMOVE(cavity_items, cavity_item)

	for(var/thing in injuries)
		var/datum/injury/injury = thing
		injury.remove_from_mob()

	for(var/thing in wounds)
		var/datum/wound/wound = thing
		wound.remove_wound(TRUE)

	for(var/thing in scars)
		var/datum/scar/scar = thing
		scar.victim = null
		LAZYREMOVE(owner.all_scars, scar)

	for(var/obj/item/item in embedded_objects)
		embedded_objects -= item
		if(istype(Tsec))
			item.forceMove(Tsec)
		else
			qdel(item)

	var/mob/living/carbon/phantom_owner = owner // so we can still refer to the guy who lost their limb after said limb forgets 'em
	set_owner(null)
	limb_flags |= BODYPART_CUT_AWAY

	if(!ignore_children)
		for(var/BP in children_zones)
			var/obj/item/bodypart/bodypart = phantom_owner.get_bodypart(BP)
			if(bodypart)
				//child could have been deleted
				bodypart.transfer_to_limb(src, phantom_owner)

	if(!phantom_owner.has_embedded_objects())
		phantom_owner.clear_alert("embeddedobject")
		SEND_SIGNAL(phantom_owner, COMSIG_CLEAR_MOOD_EVENT, "embedded")

	if(!special)
		if(phantom_owner.dna)
			for(var/X in phantom_owner.dna.mutations) //some mutations require having specific limbs to be kept.
				var/datum/mutation/human/MT = X
				if(MT.limb_req && MT.limb_req == body_zone)
					phantom_owner.dna.force_lose(MT)
		for(var/X in phantom_owner.internal_organs) //internal organs inside the dismembered limb are droppe
			var/obj/item/organ/organ = X
			var/org_zone = check_zone(organ.current_zone)
			if(org_zone != body_zone)
				continue
			organ.transfer_to_limb(src, phantom_owner)
		if(CHECK_BITFIELD(limb_flags, BODYPART_VITAL))
			phantom_owner.death()

	/// Not a clean chopping off, leave a stump behind
	if(!special && dismembered && can_stump())
		var/obj/item/bodypart/parent = phantom_owner.get_bodypart(parent_body_zone)
		if(parent && !parent.is_stump())
			var/obj/item/bodypart/stump/stump  = new(phantom_owner)
			stump.inherit_from_limb(src)
			if(!stump.attach_limb(phantom_owner, FALSE, FALSE))
				qdel(stump)
			//make sure the stump wasn't qdeleted
			if(!QDELETED(stump))
				stump.create_injury(wounding_type, stump.max_damage / 2, FALSE, TRUE)

	cut_away_limb()
	update_icon_dropped()
	if(!(phantom_owner.status_flags & BUILDING_ORGANS))
		phantom_owner.update_health_hud() //update the healthdoll
		phantom_owner.updatehealth()
		phantom_owner.update_body()
		phantom_owner.update_medicine_overlays()
		phantom_owner.update_hair()
	. = TRUE
	// Recover integrity, if we get qdeleted or not it does not matter
	limb_integrity = max_limb_integrity
	if(!QDELETED(src))
		// Tsec = null happens when a "dummy human" used for rendering icons on prefs screen gets its limbs replaced
		if(!istype(Tsec) || destroyed)
			qdel(src)
			return
		else if(is_pseudopart)
			drop_organs(phantom_owner) //Pseudoparts shouldn't have organs, but maybe something funny happened
			qdel(src)
			return
		/// Start processing rotting
		START_PROCESSING(SSobj, src)

		forceMove(Tsec)

/**
 * get_mangled_state() is relevant for flesh and bone bodyparts, and returns whether this bodypart has mangled skin, mangled bone, or both (or neither i guess)
 *
 * Dismemberment for flesh and bone requires the victim to have the skin on their bodypart destroyed (either a critical cut or piercing wound), and at least a hairline fracture
 * (severe bone), at which point we can start rolling for dismembering. The attack must also deal at least 10 damage, and must be a brute attack of some kind (sorry for now, cakehat, maybe later)
 *
 * Returns: BODYPART_MANGLED_NONE if we're fine, BODYPART_MANGLED_FLESH if our skin is broken, BODYPART_MANGLED_BONE if our bone is broken, or BODYPART_MANGLED_BOTH if both are broken and we're up for dismembering
 */
/obj/item/bodypart/proc/get_mangled_state()
	. = BODYPART_MANGLED_NONE
	var/biological_state = owner?.get_biological_state()
	var/required_bone_severity = WOUND_SEVERITY_SEVERE //How fractured the bone needs to be, pretty much
	var/required_flesh_severity = WOUND_SEVERITY_SEVERE //How fractured the bone needs to be, pretty much
	var/required_flesh_damage = 10 //How much damage the cut or pierce injury must have

	if(biological_state == BIO_JUST_BONE)
		if(!HAS_TRAIT(owner, TRAIT_EASYDISMEMBER))
			required_bone_severity = WOUND_SEVERITY_CRITICAL

	if(biological_state == BIO_JUST_FLESH)
		if(!HAS_TRAIT(owner, TRAIT_EASYDISMEMBER))
			required_flesh_damage = 20

	for(var/i in wounds)
		//just return, no point in continuing - if we know we are fucked, we won't get unfucked
		if(. == BODYPART_MANGLED_BOTH)
			return

		var/datum/wound/iter_wound = i
		if((iter_wound.wound_flags & WOUND_MANGLES_BONE) && (iter_wound.severity >= required_bone_severity))
			if(. == BODYPART_MANGLED_FLESH || . == BODYPART_MANGLED_BOTH)
				. = BODYPART_MANGLED_BOTH
			else
				. = BODYPART_MANGLED_BONE
		if((iter_wound.wound_flags & WOUND_MANGLES_FLESH) && (iter_wound.severity >= required_flesh_severity))
			if(. == BODYPART_MANGLED_BONE || . == BODYPART_MANGLED_BOTH)
				. = BODYPART_MANGLED_BOTH
			else
				. = BODYPART_MANGLED_FLESH

	for(var/i in injuries)
		//just return, no point in continuing - if we know we are fucked, we won't get unfucked
		if(. == BODYPART_MANGLED_BOTH)
			return

		var/datum/injury/IN = i
		if( ((IN.damage_type in list(WOUND_SLASH, WOUND_PIERCE)) && (IN.damage >= required_flesh_damage)) || ((IN.damage_type == WOUND_BLUNT) && (IN.damage >= required_flesh_damage * 2)) )
			if(. == BODYPART_MANGLED_BONE || . == BODYPART_MANGLED_BOTH)
				. = BODYPART_MANGLED_BOTH
			else
				. = BODYPART_MANGLED_FLESH

	if(is_tendon_torn() || no_tendon())
		if(. == BODYPART_MANGLED_BONE || . == BODYPART_MANGLED_BOTH)
			. = BODYPART_MANGLED_BOTH
		else
			. = BODYPART_MANGLED_FLESH
	if(is_fractured() || no_bone())
		if(. == BODYPART_MANGLED_FLESH || . == BODYPART_MANGLED_BOTH)
			. = BODYPART_MANGLED_BOTH
		else
			. = BODYPART_MANGLED_BONE

/**
  * damage_integrity() is used, once we've confirmed that a flesh and bone bodypart has both the muscle and bone mangled,
  * to try and damage it's integrity, which once it reaches 0... the bodypart is dismembered or gored.
  *
  * Arguments:
  * * wounding_type: Either WOUND_BLUNT, WOUND_SLASH, or WOUND_PIERCE, basically only matters for the dismember message
  * * wounding_dmg: The damage of the strike that prompted this roll, higher damage = higher integrity loss
  * * wound_bonus: Not actually used right now, but maybe someday
  * * bare_wound_bonus: Ditto above
  */
/obj/item/bodypart/proc/damage_integrity(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
	if(!owner)
		return FALSE

	// If we have a compound fracture, then deal more integrity damage
	if(is_compound_fractured())
		wounding_dmg *= 1.25
	// Endurance affects dismemberment slightly
	if(owner)
		var/endurance_modifier = (GET_MOB_ATTRIBUTE_VALUE(owner, STAT_ENDURANCE)-ATTRIBUTE_MIDDLING)*0.05
		wounding_dmg *= (1 - endurance_modifier)

	if(wound_bonus == CANT_WOUND || (wounding_dmg + wound_bonus < DISMEMBER_MINIMUM_DAMAGE))
		return FALSE

	// Damage the integrity with the wounding damage
	limb_integrity = clamp(limb_integrity - (wounding_dmg*incoming_integrity_mult), 0, max_limb_integrity)

/**
 * try_dismember() is used, once we've confirmed that a flesh and bone bodypart has both the skin and bone mangled, to actually roll for it
 *
 * Mangling is described in the above proc, [/obj/item/bodypart/proc/get_mangled_state]. This simply makes the roll for whether we actually dismember or not
 * using how damaged the limb already is, and how much damage this blow was for. If we have a critical bone wound instead of just a severe, we add +10% to the roll.
 * Lastly, we choose which kind of dismember we want based on the wounding type we hit with. Note we don't care about all the normal mods or armor for this
 *
 * Arguments:
 * * wounding_type: Either WOUND_BLUNT, WOUND_SLASH, or WOUND_PIERCE, basically only matters for the dismember message
 * * wounding_dmg: The damage of the strike that prompted this roll, higher damage = higher chance
 * * wound_bonus: Not actually used right now, but maybe someday
 * * bare_wound_bonus: ditto above
 */
/obj/item/bodypart/proc/try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)
	if(!owner)
		return FALSE
	if(!can_dismember() || (wounding_dmg < DISMEMBER_MINIMUM_DAMAGE) || (wound_bonus == CANT_WOUND))
		return FALSE
	if(limb_integrity > 0)
		return FALSE

	apply_dismember(wounding_type, TRUE, TRUE)
	return TRUE

/**
 * Applies dismemberment from try_dismember
 */
/obj/item/bodypart/proc/apply_dismember(wounding_type = WOUND_SLASH, silent = FALSE, add_descriptive = TRUE)
	if(!owner || !can_dismember())
		return FALSE

	var/occur_text = "is slashed through the last tissue holding it together, severing it completely"
	switch(wounding_type)
		if(WOUND_BLUNT)
			occur_text = "is shattered into a shower of gore"
			if(status == BODYPART_ROBOTIC)
				occur_text = "is shattered into a shower of sparks"
		if(WOUND_SLASH)
			occur_text = "is slashed through the last bit of tissue holding it together, severing it completely"
			if(status == BODYPART_ROBOTIC)
				occur_text = "is slashed through the last bit of exoskeleton layer holding it together, severing it completely"
		if(WOUND_PIERCE)
			occur_text = "is pierced through the last tissue holding it together, goring it into giblets"
			if(status == BODYPART_ROBOTIC)
				occur_text = "is pierced through the last bit of exoskeleton holding it together, goring it into scrap metal"
		if(WOUND_BURN)
			occur_text = "is completely incinerated, falling to a pile of carbonized remains"
			if(status == BODYPART_ROBOTIC)
				occur_text = "is completely incinerated, falling to a puddle of debris"

	var/mob/living/carbon/was_owner = owner
	if(prob(50))
		was_owner.add_confusion(15)
	if((body_zone == BODY_ZONE_PRECISE_GROIN) && prob(50))
		was_owner.vomit(15, TRUE, TRUE)
	if(prob(80))
		was_owner.death_scream()

	if(!silent)
		was_owner.visible_message(span_danger("[was_owner]'s [name] [occur_text]!"), \
					span_userdanger("My [name] [occur_text]!"))
	if(add_descriptive)
		switch(wounding_type)
			if(WOUND_SLASH)
				SEND_SIGNAL(was_owner, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, span_flashingdanger(" \The [name] is severed!"))
			if(WOUND_PIERCE, WOUND_BLUNT)
				SEND_SIGNAL(was_owner, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, span_flashingdanger(" \The [name] is gored!"))
			if(WOUND_BURN)
				SEND_SIGNAL(was_owner, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, span_flashingdanger(" \The [name] is incinerated!"))

	var/obj/effect/decal/gore
	switch(wounding_type)
		if(WOUND_BURN)
			if(status == BODYPART_ORGANIC)
				gore = new /obj/effect/decal/cleanable/ash(get_turf(owner))
			else if(status == BODYPART_ROBOTIC)
				gore = new /obj/effect/decal/cleanable/robot_debris(get_turf(owner))
		if(WOUND_BLUNT)
			if(status == BODYPART_ORGANIC)
				gore = new /obj/effect/decal/cleanable/blood/gibs(get_turf(owner))
			else if(status == BODYPART_ROBOTIC)
				gore = new /obj/effect/decal/cleanable/oil(get_turf(owner))
	if(gore)
		gore.add_mob_blood(owner)

	//apply the blood gush effect
	if(wounding_type != WOUND_BURN)
		var/direction = owner.dir
		direction = turn(direction, 180)
		var/bodypart_turn = 0 //relative north
		if(body_zone in list(BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_PRECISE_L_FOOT, BODY_ZONE_PRECISE_L_HAND))
			bodypart_turn = -90 //relative east
		else if(body_zone in list(BODY_ZONE_R_ARM, BODY_ZONE_R_LEG, BODY_ZONE_PRECISE_R_FOOT, BODY_ZONE_PRECISE_R_HAND))
			bodypart_turn = 90 //relative west
		direction = turn(direction, bodypart_turn)
		owner.do_hitsplatter(direction, 3, 5, FALSE)

	var/should_kaplosh = FALSE
	if(wounding_type != WOUND_SLASH)
		should_kaplosh = TRUE
	var/kaplosh_sound = pick(dismemberment_sounds)
	if(status == BODYPART_ROBOTIC)
		kaplosh_sound = 'modular_septic/sound/effects/crowbarhit.ogg'
	playsound(owner, kaplosh_sound, 80, 0)
	dismember(dam_type = (wounding_type == WOUND_BURN ? BURN : BRUTE), silent = TRUE, destroy = should_kaplosh, wounding_type = wounding_type)

/// Stuff you do when you go inside a parent limb that was chopped off
/obj/item/bodypart/proc/transfer_to_limb(obj/item/bodypart/new_limb, mob/living/carbon/was_owner)
	if(owner)
		drop_limb()
	if(new_limb)
		forceMove(new_limb)
	limb_flags &= ~BODYPART_CUT_AWAY
	return TRUE

/obj/item/bodypart/proc/attach_limb(mob/living/carbon/new_owner, special = FALSE, ignore_parent = FALSE)
	if(SEND_SIGNAL(new_owner, COMSIG_CARBON_ATTACH_LIMB, src, special) & COMPONENT_NO_ATTACH)
		return FALSE
	var/obj/item/bodypart/parent
	if(new_owner && parent_body_zone)
		parent = new_owner.get_bodypart(parent_body_zone)
	if(parent_body_zone && !ignore_parent && (!istype(parent) || parent.is_stump()) )
		return FALSE
	. = TRUE
	moveToNullspace()
	set_owner(new_owner)
	new_owner.add_bodypart(src)
	/// Infection will be handled on on_life() from now on
	STOP_PROCESSING(SSobj, src)

	if(held_index)
		if(held_index > new_owner.hand_bodyparts.len)
			new_owner.hand_bodyparts.len = held_index
		new_owner.hand_bodyparts[held_index] = src
		if(!(new_owner.status_flags & BUILDING_ORGANS))
			if(new_owner.dna?.species?.mutanthands && !is_pseudopart)
				new_owner.put_in_hand(new new_owner.dna.species.mutanthands(), held_index)
		if(new_owner.hud_used)
			var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots["[held_index]"]
			if(hand)
				hand.update_appearance()
		new_owner.update_inv_gloves()
	if(stance_index)
		if(stance_index > new_owner.leg_bodyparts.len)
			new_owner.leg_bodyparts.len = stance_index
		new_owner.leg_bodyparts[stance_index] = src
	if(sight_index)
		if(sight_index > new_owner.eye_bodyparts.len)
			new_owner.eye_bodyparts.len = sight_index
		new_owner.eye_bodyparts[sight_index] = src

	//Transfer some appearance vars over
	if(brain)
		if(brainmob)
			brainmob.container = null //Reset brainmob limb var.
			brainmob.forceMove(brain) //Throw mob into brain.
			brain.brainmob = brainmob //Set the brain to use the brainmob
			brainmob = null //Set limb brainmob var to null
		brain.Insert(new_owner) //Now insert the brain proper
		brain = null //No more brain in the limb

	//Stored limbs. in normal circumstances, this will be either nothing or just the children
	for(var/obj/item/bodypart/stored_limb in src)
		if(!(stored_limb.body_zone in children_zones) || !stored_limb.attach_limb(new_owner, special, ignore_parent))
			qdel(stored_limb)

	for(var/obj/item/organ/stored_organ in src)
		stored_organ.Insert(new_owner, FALSE, FALSE)

	for(var/i in wounds)
		var/datum/wound/wound = i
		// we have to remove the wound from the limb wound list first, so that we can reapply it fresh with the new person
		// otherwise the wound thinks it's trying to replace an existing wound of the same type (itself) and fails/deletes itself
		LAZYREMOVE(wounds, wound)
		wound.apply_wound(src, TRUE)

	//Add injuries to the owner's injury list
	for(var/i in injuries)
		var/datum/injury/injury = i
		injury.parent_mob = new_owner
		LAZYADD(new_owner.all_injuries, injury)

	for(var/thing in scars)
		var/datum/scar/scar = thing
		if(scar in new_owner.all_scars) // prevent double scars from happening for whatever reason
			continue
		scar.victim = new_owner
		LAZYADD(new_owner.all_scars, thing)

	if(!(new_owner.status_flags & BUILDING_ORGANS))
		update_bodypart_damage_state()
		update_limb_efficiency()

		new_owner.updatehealth()
		new_owner.update_body()
		new_owner.update_hair()
		new_owner.update_damage_overlays()

//Attach a limb to a human and drop any existing limb of that type.
/obj/item/bodypart/proc/replace_limb(mob/living/carbon/new_owner, special = FALSE, ignore_children = FALSE, ignore_parent = FALSE)
	if(!istype(new_owner))
		return
	var/obj/item/bodypart/old_bp = new_owner.get_bodypart(body_zone) //needs to happen before attach because multiple limbs in same zone breaks helpers
	if(old_bp)
		old_bp.drop_limb(special, FALSE, ignore_children)
	if(!attach_limb(new_owner, special, ignore_parent))
		qdel(src)

//Regenerates all limbs. Returns amount of limbs regenerated
/mob/living/proc/regenerate_limbs(noheal = FALSE, list/excluded_zones = list())
	SEND_SIGNAL(src, COMSIG_LIVING_REGENERATE_LIMBS, noheal, excluded_zones)

/mob/living/carbon/regenerate_limbs(noheal = FALSE, list/excluded_zones = list())
	. = ..()
	var/list/zone_list = ALL_BODYPARTS_ORDERED
	if(length(excluded_zones))
		zone_list -= excluded_zones
	for(var/Z in zone_list)
		. += regenerate_limb(Z, noheal)

/mob/living/proc/regenerate_limb(limb_zone, noheal)
	return

/mob/living/carbon/regenerate_limb(limb_zone, noheal)
	var/obj/item/bodypart/limb = get_bodypart(limb_zone)
	if(istype(limb))
		if(limb.is_stump())
			qdel(limb)
		else
			return FALSE
	limb = newBodyPart(limb_zone, 0, 0)
	if(limb)
		if(!noheal)
			limb.set_brute_dam(0)
			limb.set_burn_dam(0)
			limb.brutestate = 0
			limb.burnstate = 0
		if(dna?.species && (ROBOTIC_LIMBS in dna.species.species_traits))
			limb.change_bodypart_status(BODYPART_ROBOTIC)
			limb.limb_flags |= BODYPART_SYNTHETIC
		if(dna?.species.mutant_bodyparts["legs"] && dna.species.mutant_bodyparts["legs"][MUTANT_INDEX_NAME] == "Digitigrade Legs")
			limb.use_digitigrade = FULL_DIGITIGRADE
		if(!limb.attach_limb(src, TRUE))
			qdel(limb)
			return FALSE
		return TRUE

repo_name: AnalWerewolf/sundown

license: mit


code:
/obj/item/bodypart
	// Coloring and proper icon updating variables
	var/skin_tone = ""
	var/body_gender = ""
	var/species_id = ""
	var/species_color = ""
	var/mutation_color = ""
	var/no_update = FALSE
	var/should_draw_gender = FALSE
	var/should_draw_greyscale = FALSE
	var/gender_rendering = FALSE
	var/advanced_rendering = TRUE

	/// Icon used to generate overlays
	var/render_icon
	/// Layer used to generate overlays
	var/render_layer = BODYPARTS_LAYER
	/// Previously used for hands - used for rendering the limb and it's associated limb
	var/aux_zone
	/// Previously used for hands - used for rendering the limb and it's associated limbs
	var/aux_layer = BODYPARTS_LAYER
	/// The type of damage overlay (if any) to use when this bodypart is bruised/burned.
	var/dmg_overlay_type

	/// Alpha of markings on this limb
	var/markings_alpha = 255
	/// Body markings currently inhabiting the limb
	var/list/list/body_markings

//Updates an organ's brute/burn states for use by update_damage_overlays()
//Returns 1 if we need to update overlays. 0 otherwise.
/obj/item/bodypart/proc/update_bodypart_damage_state()
	var/tbrute = FLOOR( (brute_dam/max_damage)*3, 1 )
	var/tburn = FLOOR( (burn_dam/max_damage)*3, 1 )
	if((tbrute != brutestate) || (tburn != burnstate))
		brutestate = tbrute
		burnstate = tburn
		return TRUE
	return FALSE

//we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob.
/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source)
	var/mob/living/carbon/updater
	if(source)
		updater = source
	else
		updater = owner

	//dropped limb
	if(!updater)
		no_update = TRUE
	else if(original_owner && !IS_WEAKREF_OF(updater, original_owner)) //Foreign limb
		no_update = TRUE
	else
		no_update = FALSE

	if(!original_owner && owner)
		original_owner = WEAKREF(owner)

	if(is_organic_limb())
		if(HAS_TRAIT(src, TRAIT_ROTTEN))
			render_icon = 'modular_septic/icons/mob/human/species/dead/rot_parts.dmi'
			species_id = "rot"
			dmg_overlay_type = ""
			should_draw_gender = FALSE
			should_draw_greyscale = FALSE
			no_update = TRUE
			return
		if(HAS_TRAIT(src, TRAIT_PLASMABURNT))
			render_icon = 'modular_septic/icons/mob/human/species/skeleton/plasmaman_parts.dmi'
			species_id = "plasmaman"
			dmg_overlay_type = ""
			should_draw_gender = FALSE
			should_draw_greyscale = FALSE
			no_update = TRUE
			return
		if(HAS_TRAIT(src, TRAIT_HUSK) || (updater && HAS_TRAIT(updater, TRAIT_HUSK)))
			render_icon = 'modular_septic/icons/mob/human/species/dead/husk_parts.dmi'
			species_id = "husk" //overrides species_id
			dmg_overlay_type = "" //no damage overlay shown when husked
			should_draw_gender = FALSE
			should_draw_greyscale = FALSE
			no_update = TRUE
			return

	if(no_update)
		return

	if(!animal_origin && ishuman(updater))
		var/mob/living/carbon/human/human_updater = updater
		should_draw_greyscale = FALSE

		var/datum/species/updater_species = human_updater.dna.species
		species_id = updater_species.limbs_id
		species_flags_list = human_updater.dna.species.species_traits

		if(updater_species.use_skintones)
			skin_tone = human_updater.skin_tone
			should_draw_greyscale = TRUE
		else
			skin_tone = ""

		body_gender = human_updater.body_type
		should_draw_gender = updater_species.sexes

		if((MUTCOLORS in updater_species.species_traits) || (DYNCOLORS in updater_species.species_traits))
			if(updater_species.fixed_mut_color)
				species_color = updater_species.fixed_mut_color
			else
				species_color = human_updater.dna.features["mcolor"]
			should_draw_greyscale = TRUE
		else
			species_color = ""

		if(!dropping_limb && human_updater.dna.check_mutation(HULK))
			mutation_color = "00aa00"
		else
			mutation_color = ""

		dmg_overlay_type = updater_species.damage_overlay_type

		if(advanced_rendering)
			if(LAZYLEN(updater_species.body_markings))
				body_markings = list()
				if(updater_species.body_markings[body_zone])
					body_markings[body_zone] = updater_species.body_markings[body_zone].Copy()
				if(aux_zone && updater_species.body_markings[aux_zone])
					body_markings[aux_zone] = updater_species.body_markings[aux_zone].Copy()
			if(!LAZYLEN(body_markings))
				body_markings = null
			if(updater_species.bodypart_alpha)
				alpha = updater_species.bodypart_alpha
			if(updater_species.markings_alpha)
				markings_alpha = updater_species.markings_alpha
			if(updater_species.limbs_icon)
				render_icon = updater_species.limbs_icon
	else if(animal_origin == MONKEY_BODYPART) //currently monkeys are the only non human mob to have damage overlays.
		dmg_overlay_type = animal_origin

	if(status == BODYPART_ROBOTIC)
		dmg_overlay_type = "robotic"

	if(dropping_limb)
		no_update = TRUE //when attached, the limb won't be affected by the appearance changes of its mob owner.

//to update the bodypart's icon when not attached to a mob
/obj/item/bodypart/proc/update_icon_dropped()
	cut_overlays()
	var/list/standing = list()
	standing |= get_limb_icon(TRUE)
	for(var/image/I in standing)
		I.pixel_x = px_x
		I.pixel_y = px_y
	for(var/obj/item/bodypart/BP in src)
		var/list/substanding = BP.get_limb_icon(TRUE)
		for(var/image/I in substanding)
			I.pixel_x = px_x
			I.pixel_y = px_y
		standing |= substanding
		for(var/obj/item/bodypart/grandchild in BP)
			var/list/subsubstanding = grandchild.get_limb_icon(TRUE)
			for(var/image/I in subsubstanding)
				I.pixel_x = px_x
				I.pixel_y = px_y
			standing |= subsubstanding
			//the ride never ends
			for(var/obj/item/bodypart/grander_child in grandchild)
				var/list/subsubsubstanding = grander_child.get_limb_icon(TRUE)
				for(var/image/I in subsubsubstanding)
					I.pixel_x = px_x
					I.pixel_y = px_y
				standing |= subsubsubstanding
	if(!LAZYLEN(standing))
		icon_state = initial(icon_state)
		return
	add_overlay(standing)

// Gives you a proper icon appearance for the dismembered limb
/obj/item/bodypart/proc/get_limb_icon(dropped)
	icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone.

	. = list()

	var/image_dir = 0
	if(dropped)
		image_dir = SOUTH
		if(dmg_overlay_type)
			if(body_zone in list(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND))
				if(brutestate)
					. += image('modular_septic/icons/mob/human/overlays/damage.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -UPPER_DAMAGE_LAYER, image_dir)
				if(burnstate)
					. += image('modular_septic/icons/mob/human/overlays/damage.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -UPPER_DAMAGE_LAYER, image_dir)
			else
				if(brutestate)
					. += image('modular_septic/icons/mob/human/overlays/damage.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
				if(burnstate)
					. += image('modular_septic/icons/mob/human/overlays/damage.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir)

	var/image/limb = image(layer = -render_layer, dir = image_dir)
	var/image/aux
	. += limb

	if(animal_origin)
		if(is_organic_limb())
			limb.icon = DEFAULT_BODYPART_ICON_ANIMAL
			if(species_id == "husk")
				limb.icon_state = "[animal_origin]_husk_[body_zone]"
			else
				limb.icon_state = "[animal_origin]_[body_zone]"
		else
			limb.icon = DEFAULT_BODYPART_ICON_ROBOTIC
			limb.icon_state = "[animal_origin]_[body_zone]"
		return

	var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable

	if(!gender_rendering)
		should_draw_gender = FALSE

	if(advanced_rendering)
		if(should_draw_greyscale)
			limb.icon = render_icon || DEFAULT_BODYPART_ICON_ORGANIC
			if(should_draw_gender)
				limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
			else if(use_digitigrade)
				limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]"
			else
				limb.icon_state = "[species_id]_[body_zone]"
		else
			limb.icon = render_icon || DEFAULT_BODYPART_ICON
			if(should_draw_gender)
				limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
			else
				limb.icon_state = "[species_id]_[body_zone]"
		if(aux_zone)
			aux = image(limb.icon, "[species_id]_[aux_zone]", -aux_layer, image_dir)
			. += aux

	else
		limb.icon = icon
		limb.icon_state = "[body_zone]" //Inorganic limbs are agender
		if(aux_zone)
			aux = image(limb.icon, "[aux_zone]", -aux_layer, image_dir)
			. += aux
		return

	if(should_draw_greyscale)
		var/draw_color = mutation_color || species_color || skintone2hex(skin_tone)
		if(draw_color)
			limb.color = sanitize_hexcolor(draw_color, 6, TRUE)
			if(aux)
				aux.color = limb.color

	if (!owner || is_pseudopart || is_stump() || HAS_TRAIT(src, TRAIT_ROTTEN) || !ishuman(owner))
		return

	var/mob/living/carbon/human/human = owner
	//set specific alpha before setting the markings alpha
	if(alpha != 255)
		for(var/ov in .)
			var/image/overlay = ov
			overlay.alpha = alpha

	if(!LAZYLEN(body_markings))
		return

	//Markings!
	var/override_color
	if(HAS_TRAIT(human, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_HUSK))
		override_color = "888888"

	for(var/name in body_markings[body_zone])
		var/datum/body_marking/marking = GLOB.body_markings[name]
		var/render_limb_string = body_zone
		if(use_digitigrade)
			render_limb_string = "digitigrade_[use_digitigrade]_[render_limb_string]"

		if(marking.gendered && gender_rendering)
			var/marking_gender = (human.body_type == FEMALE) ? "f" : "m"
			render_limb_string = "[render_limb_string]_[marking_gender]"

		var/mutable_appearance/accessory_overlay = mutable_appearance(marking.icon, "[marking.icon_state]_[render_limb_string]", -BODY_ADJ_LAYER)
		if(body_zone in list(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND))
			accessory_overlay.layer = -HANDS_ADJ_LAYER
		if(override_color)
			accessory_overlay.color = sanitize_hexcolor(override_color, 6, TRUE)
		else
			accessory_overlay.color = sanitize_hexcolor(body_markings[body_zone][name], 6, TRUE)
		accessory_overlay.alpha = markings_alpha
		. += accessory_overlay

	if(aux_zone)
		for(var/key in body_markings[aux_zone])
			var/datum/body_marking/marking = GLOB.body_markings[key]

			var/render_limb_string = aux_zone

			var/mutable_appearance/accessory_overlay = mutable_appearance(marking.icon, "[marking.icon_state]_[render_limb_string]", -BODY_ADJ_LAYER)
			if(body_zone in list(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND))
				accessory_overlay.layer = -HANDS_ADJ_LAYER
			if(override_color)
				accessory_overlay.color = sanitize_hexcolor(override_color, 6, TRUE)
			else
				accessory_overlay.color = sanitize_hexcolor(body_markings[body_zone][key], 6, TRUE)
			accessory_overlay.alpha = markings_alpha
			. += accessory_overlay


code:
/// Used by some medical tools
/obj/item/bodypart/proc/listen()
	var/list/sounds = list()
	for(var/obj/item/organ/organ in get_organs())
		var/gutsound = organ.listen()
		if(gutsound)
			sounds += gutsound
	if(!length(sounds))
		if(owner?.pulse)
			sounds += "faint pulse"
	return sounds

/// Medical scans
/obj/item/bodypart/proc/get_scan_results(do_span = FALSE)
	. = list()
	if(is_robotic_limb())
		. += do_span ? span_info("Mechanical") : "Mechanical"

	if(CHECK_BITFIELD(limb_flags, BODYPART_CUT_AWAY))
		. += do_span ? span_danger("Severed") : "Severed"

	if(rejection_stage)
		. += do_span ? span_danger("Genetic Rejection") : "Genetic Rejection"

	if(CHECK_BITFIELD(limb_flags, BODYPART_DEAD))
		. += do_span ? span_necrosis("Necrotic") : "Necrotic"
	else
		switch(germ_level)
			if(INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + ((INFECTION_LEVEL_TWO - INFECTION_LEVEL_ONE) / 3))
				. += do_span ? span_infection("Light Infection") : "Light Infection"
			if(INFECTION_LEVEL_ONE + ((INFECTION_LEVEL_TWO - INFECTION_LEVEL_ONE) / 3) to INFECTION_LEVEL_ONE + (2 * (INFECTION_LEVEL_TWO - INFECTION_LEVEL_ONE) / 3))
				. += do_span ? span_infection("Medium Infection+") : "Medium Infection+"
			if(INFECTION_LEVEL_ONE + (2 * (INFECTION_LEVEL_TWO - INFECTION_LEVEL_ONE) / 3) to INFECTION_LEVEL_TWO)
				. += do_span ? span_infection("Serious Infection") : "Serious Infection"
			if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_TWO + ((INFECTION_LEVEL_THREE - INFECTION_LEVEL_THREE) / 3))
				. += do_span ? span_infection("Acute Infection") : "Acute Infection"
			if(INFECTION_LEVEL_TWO + ((INFECTION_LEVEL_THREE - INFECTION_LEVEL_THREE) / 3) to INFECTION_LEVEL_TWO + (2 * (INFECTION_LEVEL_THREE - INFECTION_LEVEL_TWO) / 3))
				. += do_span ? span_infection("Acute Infection+") : "Acute Infection+"
			if(INFECTION_LEVEL_TWO + (2 * (INFECTION_LEVEL_THREE - INFECTION_LEVEL_TWO) / 3) to INFECTION_LEVEL_THREE)
				. += do_span ? span_infection("Acute Infection++") : "Acute Infection++"
			if(INFECTION_LEVEL_THREE to INFINITY)
				. += do_span ? span_necrosis("Septic") : "Septic"

/// Advanced examine stuff
/obj/item/bodypart/examine_more(mob/user)
	. = list(span_notice("I examine [src] closer, and note the following..."), "

")
	. |= surgical_examine(user)

/obj/item/bodypart/proc/surgical_examine(mob/user)
	. = list()
	if(get_dist(user, src) <= 2)
		var/ouchies = get_injuries_desc()
		if(ouchies)
			. += span_warning("[capitalize(src.name)] has [ouchies] visible on it.")
		var/list/woundies = list()
		for(var/datum/wound/W in wounds)
			woundies += lowertext(W.name)
		if(length(woundies))
			. += span_warning("[capitalize(src.name)] is suffering with [english_list(woundies)].")
	if(etching)
		. += span_notice("[capitalize(src.name)] has \"[etching]\" inscribed on it.")
	if(status == BODYPART_ROBOTIC)
		. += span_notice("[capitalize(src.name)] is seemingly of a robotic nature.")
	else
		. += span_notice("[capitalize(src.name)] is seemingly of an organic nature.")
	if(limb_flags & BODYPART_NOINFECTION)
		. += span_notice("[capitalize(src.name)] will not decay nor get infected.")
	if(GetComponent(/datum/component/edible))
		. += span_notice("[capitalize(src.name)] is edible.")
	if(limb_flags & BODYPART_DEAD)
		. += span_necrosis("[capitalize(src.name)] seems to be gangrenous!")
	else if(germ_level)
		switch(germ_level)
			if(INFECTION_LEVEL_ONE to INFECTION_LEVEL_TWO)
				. += span_infection("[capitalize(src.name)] seems to be mildly infected.")
			if(INFECTION_LEVEL_TWO to INFECTION_LEVEL_THREE)
				. += span_infection("[capitalize(src.name)] seems to be festering.")
			if(INFECTION_LEVEL_THREE to INFINITY)
				. += span_necrosis("[capitalize(src.name)] seems to be necrotic!")
	for(var/obj/item/bodypart/BP in src)
		if(BP.body_zone in children_zones)
			. += span_notice("[capitalize(src.name)] has \a [lowertext(BP.name)] attached.")
	if(!isobserver(user) && (GET_MOB_ATTRIBUTE_VALUE(user, SKILL_MEDICINE) < 8))
		return
	if(!owner)
		. += span_notice("[src] can be attached on \the [parse_zone(body_zone)].")
	. += span_info("Cavity volume: [max_cavity_volume]")
	. += span_info("Maximum item size: [capitalize(weight_class_to_text(max_cavity_item_size))]")

/obj/item/bodypart/proc/get_injuries_desc()
	var/obj/item/bodypart/parent = owner?.get_bodypart(parent_body_zone)
	var/list/flavor_text = list()
	if(owner && is_cut_away() && !parent?.is_cut_away() && !is_stump())
		if(parent)
			flavor_text += "a tear at the [amputation_point_name] so severe that it hangs by a scrap of [is_organic_limb() ? "flesh" : "metal"] to [parent]"
		else
			flavor_text += "a tear at the [amputation_point_name] so severe that it hangs by a scrap of [is_organic_limb() ? "flesh" : "metal"]"

	var/list/injury_descriptors = list()
	for(var/thing in injuries)
		var/datum/injury/injury = thing
		var/this_injury_desc = injury.get_desc(FALSE)
		if(injury.can_autoheal() && (injury.current_stage >= length(injury.stages)) && (injury.damage < 5))
			this_injury_desc = "[this_injury_desc]"
		if(injury.is_bleeding())
			if(is_artery_torn())
				this_injury_desc = "blood-gushing [this_injury_desc]"
			//Completely arbitrary value
			else if(injury.get_bleed_rate() >= 2)
				this_injury_desc = "badly bleeding [this_injury_desc]"
			else
				this_injury_desc = "bleeding [this_injury_desc]"
		if(injury.is_clamped())
			this_injury_desc = "clamped [this_injury_desc]"
		if(injury.is_sutured())
			this_injury_desc = "sutured [this_injury_desc]"
		if(injury.is_bandaged())
			this_injury_desc = "bandaged [this_injury_desc]"
		if(injury.is_salved())
			this_injury_desc = "salved [this_injury_desc]"
		if(injury.is_disinfected())
			this_injury_desc = "disinfected [this_injury_desc]"

		if(injury.germ_level >= INFECTION_LEVEL_TWO)
			this_injury_desc = "badly infected [this_injury_desc]"
		else if(injury.germ_level >= INFECTION_LEVEL_ONE)
			this_injury_desc = "infected [this_injury_desc]"

		if(length(injury.embedded_objects))
			var/list/chung = list()
			for(var/item in injury.embedded_objects)
				var/obj/I = item
				chung += "\a [I]"
			this_injury_desc += " with [english_list(chung)] poking out of [injury.amount > 1 ? "them" : "it"]"

		if(injury_descriptors[this_injury_desc])
			injury_descriptors[this_injury_desc] += injury.amount
		else
			injury_descriptors[this_injury_desc] = injury.amount

	if(!is_robotic_limb())
		if(CHECK_MULTIPLE_BITFIELDS(how_open(), SURGERY_INCISED|SURGERY_RETRACTED))
			var/bone_name = GLOB.bones_by_path[bone_type] ? GLOB.bones_by_path[bone_type].name : "bone"
			if(is_fractured())
				bone_name = "fractured [bone_name]"
			injury_descriptors["[bone_name] exposed"] = 1
			if(!is_encased() || (CHECK_BITFIELD(how_open(), SURGERY_BROKEN)))
				var/list/bits = list()
				for(var/obj/item/organ/organ as anything in get_organs())
					var/visible_state = organ.get_visible_state()
					if(!LAZYLEN(visible_state))
						continue
					bits += visible_state
				if(bits.len)
					injury_descriptors["[english_list(bits)] visible in the wounds"] = 1

	for(var/injury in injury_descriptors)
		var/found_color = findtext(injury, "style='color: [COLOR_PALE_RED_GRAY]'")
		switch(injury_descriptors[injury])
			if(-INFINITY to 1)
				flavor_text += "a [injury]"
			if(2)
				if(found_color)
					flavor_text += "a pair of [injury]s"
				else
					flavor_text += "a pair of [injury]s"
			if(3 to 5)
				if(found_color)
					flavor_text += "several [injury]s"
				else
					flavor_text += "several [injury]s"
			if(6 to INFINITY)
				if(found_color)
					flavor_text += "a ton of [injury]s"
				else
					flavor_text += "a ton of [injury]s"
	if(length(flavor_text))
		return english_list(flavor_text)

/// Grab examination
/obj/item/bodypart/proc/inspect(mob/user)
	user.visible_message(span_notice("[user] starts inspecting [owner]'s [name] carefully."))
	var/ouchies = get_injuries_desc()
	if(ouchies)
		to_chat(user, span_warning("I find [get_injuries_desc()]."))
	else
		to_chat(user, span_notice("I can't find any visible wounds."))

	to_chat(user, span_notice("Checking skin now..."))
	if(!do_mob(user, owner, 1 SECONDS))
		to_chat(user, span_warning("I must stand still to check [owner]'s skin for abnormalities."))
		return

	var/list/badness = list()
	if(owner.getShockStage() >= SHOCK_STAGE_2)
		badness |= "clammy and cool to the touch"
	if(owner.getToxLoss() >= 25)
		badness |= "jaundiced"
	if(owner.get_blood_oxygenation() <= BLOOD_VOLUME_OKAY)
		badness |= "turning blue"
	if(owner.get_blood_circulation() <= BLOOD_VOLUME_OKAY + 70)
		badness |= "very pale"
	if(is_dead())
		badness |= "rotting"

	if(!length(badness))
		to_chat(user, span_notice("[owner]'s skin is normal."))
	else
		to_chat(user, span_warning("[owner]'s skin is [english_list(badness)]."))

	if(bone_needed())
		to_chat(user, span_notice("Checking bones now..."))
		if(!do_mob(user, owner, 1 SECONDS))
			to_chat(user, span_warning("I must stand still to feel [src] for fractures."))
			return

		var/bone_name = GLOB.bones_by_path[bone_type].name
		if(bone_missing())
			to_chat(user, span_warning("The [name] is missing it's [bone_name]!"))
		else if(is_dislocated())
			var/joint_name = GLOB.bones_by_path[bone_type].joint_name
			to_chat(user, span_warning("The [joint_name] is dislocated!"))
		else if(is_fractured())
			to_chat(user, span_warning("The [bone_name] in [name] moves slightly when I poke it!"))
			owner.custom_pain("My [name] hurts when poked.", 25, affecting = src)
		else
			to_chat(user, span_notice("The [bone_name] in [name] is OK."))

	if(tendon_needed() || artery_needed())
		to_chat(user, span_notice("Checking tendons and arteries now..."))
		if(!do_mob(user, owner, 1 SECONDS))
			to_chat(user, span_warning("I must stand still to feel [src] for torn tendons and arteries."))
			return

		if(tendon_needed())
			var/tendon_name = GLOB.tendons_by_path[tendon_type].name
			if(tendon_missing())
				to_chat(user, span_warning("The [name] is missing it's tendons!"))
			else if(is_tendon_torn())
				to_chat(user, span_warning("The [tendon_name] in [name] is torn!"))
			else
				to_chat(user, span_notice("The [tendon_name] in [name] is OK."))

		if(artery_needed())
			var/artery_name = GLOB.arteries_by_path[artery_type].name
			if(artery_missing())
				to_chat(user, span_warning("The [name] is missing it's [artery_name]!"))
			else if(is_artery_torn())
				to_chat(user, span_warning("The [artery_name] in [name] is severed!"))
			else
				to_chat(user, span_notice("The [artery_name] in [name] is OK."))

	return TRUE


code:
/mob/living/proc/get_bodypart(zone)
	return

/mob/living/proc/get_bodypart_nostump(zone)
	return

/mob/living/carbon/get_bodypart(zone)
	if(!zone)
		zone = BODY_ZONE_CHEST
	return bodyparts_zones[zone]

/mob/living/carbon/get_bodypart_nostump(zone)
	if(!zone)
		zone = BODY_ZONE_CHEST
	var/obj/item/bodypart/bodypart = bodyparts_zones[zone]
	if(bodypart && !bodypart.is_stump())
		return bodypart

/mob/living/carbon/has_hand_for_held_index(i, check_disabled = TRUE)
	if(!i)
		return FALSE
	var/obj/item/bodypart/hand_instance = LAZYACCESS(hand_bodyparts, i)
	if(hand_instance && !(check_disabled && hand_instance.bodypart_disabled))
		return hand_instance
	return FALSE

/// Not nearly as commonly used as get_active_hand()
/mob/proc/get_active_foot()
	return FALSE

/mob/living/carbon/get_active_foot()
	return LAZYACCESS(leg_bodyparts, active_hand_index + 2)

/// Get the bodypart for whatever hand we have active, Only relevant for carbons
/mob/proc/get_active_hand()
	return FALSE

/mob/living/carbon/get_active_hand()
	return LAZYACCESS(hand_bodyparts, active_hand_index)

/mob/proc/has_left_hand(check_disabled = TRUE)
	return TRUE

/mob/living/carbon/has_left_hand(check_disabled = TRUE)
	for(var/obj/item/bodypart/hand_instance in hand_bodyparts)
		if(!(hand_instance.held_index % 2) || (check_disabled && hand_instance.bodypart_disabled))
			continue
		return TRUE
	return FALSE

/mob/living/carbon/alien/larva/has_left_hand()
	return TRUE

/mob/proc/has_right_hand(check_disabled = TRUE)
	return TRUE

/mob/living/carbon/has_right_hand(check_disabled = TRUE)
	for(var/obj/item/bodypart/hand_instance in hand_bodyparts)
		if(hand_instance.held_index % 2 || (check_disabled && hand_instance.bodypart_disabled))
			continue
		return TRUE
	return FALSE

/mob/living/carbon/alien/larva/has_right_hand()
	return TRUE

/mob/living/proc/get_missing_limbs()
	return list()

/mob/living/carbon/get_missing_limbs()
	RETURN_TYPE(/list)
	var/static/list/full = ALL_BODYPARTS_ORDERED
	for(var/zone in full)
		if(get_bodypart(zone))
			full -= zone
	return full

/mob/living/carbon/alien/larva/get_missing_limbs()
	var/static/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST)
	for(var/zone in full)
		if(get_bodypart(zone))
			full -= zone
	return full

/mob/living/proc/get_disabled_limbs()
	return list()

/mob/living/carbon/get_disabled_limbs()
	var/static/list/full = ALL_BODYPARTS_ORDERED
	var/list/disabled = list()
	for(var/zone in full)
		var/obj/item/bodypart/affecting = get_bodypart(zone)
		if(affecting?.bodypart_disabled)
			disabled += zone
	return disabled

/mob/living/carbon/alien/larva/get_disabled_limbs()
	var/list/full = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST)
	var/list/disabled = list()
	for(var/zone in full)
		var/obj/item/bodypart/affecting = get_bodypart(zone)
		if(affecting?.bodypart_disabled)
			disabled += zone
	return disabled

///Remove a specific embedded item from the carbon mob
/mob/living/carbon/proc/remove_embedded_object(obj/item/I)
	SEND_SIGNAL(src, COMSIG_CARBON_EMBED_REMOVAL, I)

///Remove all embedded objects from all limbs on the carbon mob
/mob/living/carbon/proc/remove_all_embedded_objects()
	for(var/X in bodyparts)
		var/obj/item/bodypart/L = X
		for(var/obj/item/I in L.embedded_objects)
			remove_embedded_object(I)

/mob/living/carbon/proc/has_embedded_objects(include_harmless=FALSE)
	for(var/X in bodyparts)
		var/obj/item/bodypart/L = X
		for(var/obj/item/I in L.embedded_objects)
			if(!include_harmless && I.isEmbedHarmless())
				continue
			return TRUE

//Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by
/mob/living/carbon/proc/newBodyPart(zone, robotic, fixed_icon)
	var/obj/item/bodypart/new_limb
	switch(zone)
		if(BODY_ZONE_L_ARM)
			new_limb = new /obj/item/bodypart/l_arm()
		if(BODY_ZONE_PRECISE_L_HAND)
			new_limb = new /obj/item/bodypart/l_hand()
		if(BODY_ZONE_R_ARM)
			new_limb = new /obj/item/bodypart/r_arm()
		if(BODY_ZONE_PRECISE_R_HAND)
			new_limb = new /obj/item/bodypart/r_hand()
		if(BODY_ZONE_HEAD)
			new_limb = new /obj/item/bodypart/head()
		if(BODY_ZONE_PRECISE_MOUTH)
			new_limb = new /obj/item/bodypart/mouth()
		if(BODY_ZONE_PRECISE_NECK)
			new_limb = new /obj/item/bodypart/neck()
		if(BODY_ZONE_PRECISE_L_EYE)
			new_limb = new /obj/item/bodypart/l_eyesocket()
		if(BODY_ZONE_PRECISE_R_EYE)
			new_limb = new /obj/item/bodypart/r_eyesocket()
		if(BODY_ZONE_L_LEG)
			new_limb = new /obj/item/bodypart/l_leg()
		if(BODY_ZONE_PRECISE_L_FOOT)
			new_limb = new /obj/item/bodypart/l_foot()
		if(BODY_ZONE_R_LEG)
			new_limb = new /obj/item/bodypart/r_leg()
		if(BODY_ZONE_PRECISE_R_FOOT)
			new_limb = new /obj/item/bodypart/r_foot()
		if(BODY_ZONE_CHEST)
			new_limb = new /obj/item/bodypart/chest()
		if(BODY_ZONE_PRECISE_GROIN)
			new_limb = new /obj/item/bodypart/groin()
	if(new_limb)
		new_limb.update_limb(fixed_icon, src)
		if(robotic)
			new_limb.change_bodypart_status(BODYPART_ROBOTIC)
			new_limb.limb_flags |= BODYPART_SYNTHETIC
	return new_limb

/mob/living/carbon/human/newBodyPart(zone, robotic, fixed_icon)
	var/obj/item/bodypart/new_limb
	var/datum/species/species = dna.species
	var/obj/item/bodypart/selected_type = species.bodypart_overides[zone]
	new_limb = new selected_type()
	if(new_limb)
		new_limb.update_limb(fixed_icon, src)
		if(robotic)
			new_limb.change_bodypart_status(BODYPART_ROBOTIC)
	return new_limb

/mob/living/carbon/alien/larva/newBodyPart(zone, robotic, fixed_icon)
	var/obj/item/bodypart/new_limb
	switch(zone)
		if(BODY_ZONE_HEAD)
			new_limb = new /obj/item/bodypart/head/larva()
		if(BODY_ZONE_CHEST)
			new_limb = new /obj/item/bodypart/chest/larva()
	if(new_limb)
		new_limb.update_limb(fixed_icon, src)
		if(robotic)
			new_limb.change_bodypart_status(BODYPART_ROBOTIC)
			new_limb.limb_flags |= BODYPART_SYNTHETIC
	return new_limb

/mob/living/carbon/alien/humanoid/newBodyPart(zone, robotic, fixed_icon)
	var/obj/item/bodypart/new_limb
	switch(zone)
		if(BODY_ZONE_L_ARM)
			new_limb = new /obj/item/bodypart/l_arm/alien()
		if(BODY_ZONE_R_ARM)
			new_limb = new /obj/item/bodypart/r_arm/alien()
		if(BODY_ZONE_HEAD)
			new_limb = new /obj/item/bodypart/head/alien()
		if(BODY_ZONE_L_LEG)
			new_limb = new /obj/item/bodypart/l_leg/alien()
		if(BODY_ZONE_R_LEG)
			new_limb = new /obj/item/bodypart/r_leg/alien()
		if(BODY_ZONE_CHEST)
			new_limb = new /obj/item/bodypart/chest/alien()
	if(new_limb)
		new_limb.update_limb(fixed_icon, src)
		if(robotic)
			new_limb.change_bodypart_status(BODYPART_ROBOTIC)
			new_limb.limb_flags |= BODYPART_SYNTHETIC
	return new_limb

/proc/skintone2hex(skin_tone)
	. = 0
	switch(skin_tone)
		if("caucasian1")
			. = "ffe0d1"
		if("caucasian2")
			. = "fcccb3"
		if("caucasian3")
			. = "e8b59b"
		if("latino")
			. = "d9ae96"
		if("mediterranean")
			. = "c79b8b"
		if("asian1")
			. = "ffdeb3"
		if("asian2")
			. = "e3ba84"
		if("arab")
			. = "c4915e"
		if("indian")
			. = "b87840"
		if("african1")
			. = "754523"
		if("african2")
			. = "471c18"
		if("albino")
			. = "fff4e6"
		if("orange")
			. = "ffc905"

/mob/living/carbon/proc/Digitigrade_Leg_Swap(swap_back)
	var/body_plan_changed = FALSE
	for(var/X in bodyparts)
		var/obj/item/bodypart/O = X
		var/obj/item/bodypart/N
		if((!O.use_digitigrade && swap_back == FALSE) || (O.use_digitigrade && swap_back == TRUE))
			if(O.body_part == LEG_LEFT)
				if(swap_back == TRUE)
					N = new /obj/item/bodypart/l_leg
				else
					N = new /obj/item/bodypart/l_leg/digitigrade
			else if(O.body_part == LEG_RIGHT)
				if(swap_back == TRUE)
					N = new /obj/item/bodypart/r_leg
				else
					N = new /obj/item/bodypart/r_leg/digitigrade
		if(!N)
			continue
		body_plan_changed = TRUE
		O.drop_limb(TRUE, FALSE, TRUE)
		qdel(O)
		N.attach_limb(src) //no sanity for if this fails here because we just dropped out a limb of the same zone, SHOULD be okay
	if(body_plan_changed && ishuman(src))
		var/mob/living/carbon/human/H = src
		if(H.w_uniform)
			var/obj/item/clothing/under/U = H.w_uniform
			if(U.mutantrace_variation)
				if(swap_back)
					U.adjusted = NORMAL_STYLE
				else
					U.adjusted = DIGITIGRADE_STYLE
				H.update_inv_w_uniform()
		if(H.shoes && !swap_back)
			H.dropItemToGround(H.shoes)

/// Proc to hook behavior on bodypart additions.
/mob/living/carbon/add_bodypart(obj/item/bodypart/new_bodypart)
	bodyparts += new_bodypart
	bodyparts_zones[new_bodypart.body_zone] = new_bodypart
	if(new_bodypart.stance_index)
		set_num_legs(num_legs + 1)
		if(!new_bodypart.bodypart_disabled)
			set_usable_legs(usable_legs + 1)
	if(new_bodypart.held_index)
		set_num_hands(num_hands + 1)
		if(!new_bodypart.bodypart_disabled)
			set_usable_hands(usable_hands + 1)
	if(new_bodypart.sight_index)
		set_num_eyes(num_eyes + 1)
		if(!new_bodypart.bodypart_disabled)
			set_usable_eyes(usable_eyes + 1)

/// Proc to hook behavior on bodypart removals.
/mob/living/carbon/remove_bodypart(obj/item/bodypart/old_bodypart)
	bodyparts -= old_bodypart
	bodyparts_zones -= old_bodypart.body_zone
	if(old_bodypart.stance_index)
		set_num_legs(num_legs - 1)
		if(!old_bodypart.bodypart_disabled)
			set_usable_legs(usable_legs - 1)
	if(old_bodypart.held_index)
		set_num_hands(num_hands - 1)
		if(!old_bodypart.bodypart_disabled)
			set_usable_hands(usable_hands - 1)
	if(old_bodypart.sight_index)
		set_num_eyes(num_eyes - 1)
		if(!old_bodypart.bodypart_disabled)
			set_usable_eyes(usable_eyes - 1)

/mob/proc/update_limb_efficiencies()
	return

/mob/living/carbon/update_limb_efficiencies()
	if(status_flags & BUILDING_ORGANS)
		return
	for(var/thing in bodyparts)
		var/obj/item/bodypart/limb = thing
		limb.update_limb_efficiency()

/mob/living/proc/get_infected_bodyparts()
	return

/mob/living/carbon/get_infected_bodyparts()
	. = list()
	for(var/thing in bodyparts)
		var/obj/item/bodypart/limb = thing
		if(limb.germ_level)
			. += limb


code:
//This is basically the baystation wound datum, which i thought would synergize well with the TG wounds
/****************************************************
				INJURY DATUM
****************************************************/
//Note that the MINIMUM damage before a injury can be applied should correspond to
//the damage amount for the stage with the same name as the injury.
//e.g. /datum/injury/cut/deep should only be applied for 15 damage and up,
//because in it's stages list, "deep cut" = 15.
/datum/injury
	/// Number representing the current stage
	var/current_stage = 0
	/// Description of the injury - default in case something borks
	var/desc = "injury"
	/// Amount of damage this injury is currently causing
	var/damage = 0
	/// How much we bleed on each tick per 40 damage
	var/bleed_rate = 1
	/// Ticks of bleeding left
	var/bleed_timer = 0
	/// Above this amount of damage, you will need to treat the injury to stop bleeding, regardless of bleed_timer
	var/bleed_threshold = 30
	/// Amount of damage the current injury type requires (less means we need to apply the next healing stage)
	var/min_damage = 0
	/// General flags like INJURY_BANDAGED, INJURY_SALVED
	var/injury_flags = (INJURY_SOUND_HINTS)
	/// world.time when this injury was created
	var/created = 0
	/// Number of inuries stored here
	var/amount = 1
	/// Amount of germs in the injury
	var/germ_level = 0
	/// Rate of infection for this injury
	var/infection_rate = 1
	/// Time it takes for the injury to fade away once healed up
	var/fade_away = 1 MINUTES
	/// The bodypart the injury is on, if on a bodypart
	var/obj/item/bodypart/parent_bodypart
	/// The mob the injury is on, if on a mob
	var/mob/living/carbon/parent_mob

	// ~these are defined by the injury type and should not be changed here
	/// Stages such as "cut", "deep cut", etc.
	var/list/stages
	/// Maximum stage at which bleeding should still happen - Beyond this stage bleeding is prevented
	var/max_bleeding_stage = 0
	/// One of WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE, WOUND_BURN
	var/damage_type = WOUND_SLASH
	/// The maximum amount of damage that this injury can have and still autoheal
	var/autoheal_cutoff = 15

	// ~helper lists
	var/list/desc_list = list()
	var/list/damage_list = list()

	/// Limb status required for this injury
	var/required_status = BODYPART_ORGANIC

	// ~shit that got embedded on this injury
	var/list/embedded_objects
	var/list/embedded_components

/datum/injury/New()
	. = ..()
	created = world.time
	// reading from a list("stage" = damage) is pretty difficult, so build two separate
	// lists from them instead
	for(var/V in stages)
		desc_list += V
		damage_list += stages[V]

/datum/injury/Destroy()
	if(parent_bodypart)
		remove_from_bodypart()
	if(parent_mob)
		remove_from_mob(parent_mob)
	embedded_objects = null
	for(var/embed_success in embedded_components)
		var/datum/component/embedded/embedded = embed_success
		embedded.safeRemove()
		if(!QDELETED(embedded))
			embedded.injury = null
	embedded_components = null
	return ..()

/datum/injury/proc/get_desc(count = TRUE)
	if(count && amount > 1)
		return "[desc]s"
	return desc

/datum/injury/proc/get_bleed_rate_of_change()
	if((bleed_timer > 0 || damage_per_injury() > bleed_threshold) && current_stage <= max_bleeding_stage)
		return BLOOD_FLOW_STEADY
	return BLOOD_FLOW_DECREASING

/datum/injury/proc/set_mob(mob/living/carbon/new_owner, sound_hint = TRUE)
	parent_mob = new_owner
	LAZYADD(new_owner.all_injuries, src)
	if(sound_hint && (injury_flags & INJURY_SOUND_HINTS))
		new_owner.sound_hint()

/datum/injury/proc/set_bodypart(obj/item/bodypart/new_owner, sound_hint = TRUE)
	parent_bodypart = new_owner
	LAZYADD(parent_bodypart.injuries, src)

/datum/injury/proc/remove_from_mob()
	if(!parent_mob)
		return
	LAZYREMOVE(parent_mob.all_injuries, src)
	parent_mob = null

/datum/injury/proc/remove_from_bodypart()
	if(!parent_bodypart)
		return
	LAZYREMOVE(parent_bodypart.injuries, src)
	if(parent_bodypart.last_injury == src)
		parent_bodypart.last_injury = null
	parent_bodypart = null

//applies the injury on a limb proper
/datum/injury/proc/apply_injury(our_damage, obj/item/bodypart/limb)
	//aaaaaaaaah
	damage = our_damage

	//initialize with the appropriate stage and bleeding ticks
	bleed_timer += our_damage
	init_stage(our_damage)

	if(istype(limb))
		set_bodypart(limb)
		if(parent_bodypart.owner)
			set_mob(parent_bodypart.owner)

//increase or decrease infection
/datum/injury/proc/adjust_germ_level(add_germs, minimum_germs = 0, maximum_germs = MAXIMUM_GERM_LEVEL)
	germ_level = clamp(germ_level + add_germs, minimum_germs, maximum_germs)

//makes the injury get infected more when the victim is moving around
/datum/injury/proc/movement_infect(mob/living/carbon/source)
	if(parent_bodypart && prob(25) && infection_check())
		adjust_germ_level(infection_rate)

//special proc for when the parent bodypart receives some damage
/datum/injury/proc/receive_damage(damage_received = 0, pain_received = 0, wounding_type = WOUND_BLUNT)
	return FALSE

// returns 1 if there's a next stage, 0 otherwise
/datum/injury/proc/init_stage(initial_damage)
	current_stage = stages.len

	while(current_stage > 1 && damage_list[current_stage-1] <= initial_damage / amount)
		current_stage--

	min_damage = damage_list[current_stage]
	desc = desc_list[current_stage]

// the amount of damage per injury
/datum/injury/proc/damage_per_injury()
	return (damage/amount)

/datum/injury/proc/can_autoheal()
	if(required_status != BODYPART_ORGANIC)
		return FALSE
	if(CHECK_BITFIELD(injury_flags, INJURY_RETRACTED))
		return FALSE
	for(var/obj/item/wpn in embedded_objects)
		if(!wpn.isEmbedHarmless())
			return FALSE
	return ((damage_per_injury() <= autoheal_cutoff) ? TRUE : (is_treated() || parent_bodypart?.limb_flags & BODYPART_GOOD_HEALER))

// checks whether the injury has been appropriately treated
/datum/injury/proc/is_treated()
	for(var/obj/item/weapon as anything in embedded_objects)
		if(!weapon.isEmbedHarmless())
			return FALSE
	switch(damage_type)
		if(WOUND_SLASH, WOUND_PIERCE)
			return (is_bandaged() || is_sutured() || parent_bodypart.current_gauze)
		if(WOUND_BLUNT)
			return (is_bandaged() || parent_bodypart.current_gauze)
		if(WOUND_BURN)
			return (is_salved() || (is_disinfected() && (is_bandaged() || parent_bodypart.current_gauze) ) )

// Checks whether other other can be merged into src.
/datum/injury/proc/can_merge(datum/injury/other)
	if(other.damage_type != damage_type)
		return FALSE
	if(other.type != type)
		return FALSE
	if(other.current_stage != current_stage)
		return FALSE
	if(other.can_autoheal() != can_autoheal())
		return FALSE
	if(other.injury_flags != injury_flags)
		return FALSE
	if(other.parent_bodypart != parent_bodypart)
		return FALSE
	return TRUE

/datum/injury/proc/merge_injury(datum/injury/other)
	embedded_objects = (src.embedded_objects | other.embedded_objects)
	embedded_components = (src.embedded_components | other.embedded_components)
	for(var/thing in embedded_components)
		var/datum/component/embedded/embedded = thing
		embedded.injury = src
	damage += other.damage
	amount += other.amount
	bleed_timer += other.bleed_timer
	germ_level = max(germ_level, other.germ_level)
	injury_flags |= other.injury_flags
	created = max(created, other.created)	//take the newer created time
	parent_bodypart?.last_injury = src
	qdel(other)

// checks if injury is considered open for external infections
// untreated cuts (and bleeding bruises) and burns are possibly infectable, chance higher if injury is bigger
/datum/injury/proc/infection_check(delta_time = 2, times_fired)
	if(damage < 10)	//small cuts, tiny bruises, and moderate burns shouldn't be infectable.
		return FALSE
	if(is_treated() && damage < 25)	//anything less than a flesh injury (or equivalent) isn't infectable if treated properly
		return FALSE
	if(is_disinfected())
		return FALSE
	if(required_status & BODYPART_ROBOTIC) //Robotic injury
		return FALSE

	if(damage_type == WOUND_BLUNT && !is_bleeding()) //bruises only infectable if bleeding
		return FALSE

	switch(damage_type)
		if(WOUND_BLUNT)
			return DT_PROB(damage/2, delta_time)
		if(WOUND_BURN)
			return DT_PROB(damage*2, delta_time)
		if(WOUND_SLASH)
			return DT_PROB(damage, delta_time)
		if(WOUND_PIERCE)
			return DT_PROB(damage*1.25, delta_time)

	return FALSE

//bleeding from being dragged against the ground
/datum/injury/proc/drag_bleed_amt()
	if(!is_bleeding())
		return FALSE
	return CEILING(get_bleed_rate() * 0.2, 0.1)

// heal the given amount of damage, and if the given amount of damage was more
// than what needed to be healed, return how much heal was left
/datum/injury/proc/heal_damage(amount_heal)
	var/healed_damage = min(src.damage, amount_heal)
	damage -= healed_damage
	while(damage_per_injury() < damage_list[current_stage] && current_stage < length(desc_list))
		current_stage++
	desc = desc_list[current_stage]
	min_damage = damage_list[current_stage]
	if(!damage)
		qdel(src)

	// return amount of healing still leftover, can be used for other injuries
	return (amount_heal - healed_damage)

// returns whether this injury can absorb the given amount of damage.
// this will prevent large amounts of damage being trapped in less severe injury types
/datum/injury/proc/can_worsen(damage_type, damage)
	if(src.damage_type != damage_type)
		return FALSE	//incompatible damage types

	if(amount > 1)
		return FALSE	//multiple injuries cannot be worsened

	//with 1.5*, a shallow cut will be able to carry at most 30 damage,
	//37.5 for a deep cut
	//52.5 for a flesh injury, etc.
	var/max_injury_damage = 1.5 * damage_list[1]
	if(src.damage + damage > max_injury_damage)
		return FALSE

	return TRUE

// closes the injury
/datum/injury/proc/close_injury()
	current_stage = min(max_bleeding_stage + 1, length(damage_list))
	desc = desc_list[current_stage]
	min_damage = damage_list[current_stage]
	if(damage > min_damage)
		heal_damage(damage-min_damage)
	injury_flags &= ~INJURY_RETRACTED
	parent_bodypart?.update_bodypart_damage_state()
	parent_bodypart?.owner?.update_damage_overlays()

// opens the injury and worsens it
/datum/injury/proc/open_injury(damage, retracting = FALSE)
	src.damage += damage
	bleed_timer += damage

	while(current_stage > 1 && damage_list[current_stage-1] < damage_per_injury())
		current_stage--

	desc = desc_list[current_stage]
	min_damage = damage_list[current_stage]
	if(retracting)
		injury_flags |= INJURY_RETRACTED
	if(parent_bodypart)
		parent_bodypart.last_injury = src
		parent_bodypart.update_bodypart_damage_state()
		parent_bodypart.owner?.update_damage_overlays()

// disinfects the injury
/datum/injury/proc/disinfect_injury()
	injury_flags |= INJURY_DISINFECTED
	return TRUE

// undisinfects the injury (differs from infecting the injury)
/datum/injury/proc/undisinfect_injury()
	injury_flags &= ~INJURY_DISINFECTED
	return TRUE

// salves the injury
/datum/injury/proc/salve_injury()
	injury_flags |= INJURY_SALVED
	return TRUE

// unsalves the injury
/datum/injury/proc/unsalve_injury()
	injury_flags &= ~INJURY_SALVED
	return TRUE

// clamps the injury
/datum/injury/proc/clamp_injury()
	injury_flags |= INJURY_CLAMPED
	return TRUE

// unclamps the injury
/datum/injury/proc/unclamp_injury()
	injury_flags &= ~INJURY_CLAMPED
	return TRUE

// sutures the injury
/datum/injury/proc/suture_injury()
	injury_flags |= INJURY_SUTURED
	return TRUE

// unsutures the injury
/datum/injury/proc/unsuture_injury()
	injury_flags &= ~INJURY_SUTURED
	return TRUE

// bandages the injury
/datum/injury/proc/bandage_injury()
	injury_flags |= INJURY_BANDAGED
	return TRUE

// unbandages the injury
/datum/injury/proc/unbandage_injury()
	injury_flags |= INJURY_BANDAGED
	return TRUE

/datum/injury/proc/is_bleeding()
	for(var/thing in embedded_objects)
		var/obj/item/item = thing
		if(!item.isEmbedHarmless() && item.w_class >= WEIGHT_CLASS_SMALL)
			return FALSE
	if(is_bandaged() || is_clamped() || is_sutured())
		return FALSE
	return ((bleed_timer > 0 || damage_per_injury() > bleed_threshold) && current_stage <= max_bleeding_stage)

/datum/injury/proc/get_bleed_rate()
	if(!is_bleeding())
		return 0
	var/bad_embeddies = 0
	for(var/obj/item/wpn in embedded_objects)
		if(!wpn.isEmbedHarmless() && (wpn.w_class < WEIGHT_CLASS_SMALL))
			bad_embeddies += 1
	return max(0.1, (bleed_rate * damage)/40 + bad_embeddies)

/datum/injury/proc/is_surgical()
	if(CHECK_BITFIELD(injury_flags, INJURY_SURGICAL))
		return TRUE
	return FALSE

/datum/injury/proc/is_disinfected()
	if(CHECK_BITFIELD(injury_flags, INJURY_DISINFECTED) && (germ_level <= 0))
		return TRUE
	return FALSE

/datum/injury/proc/is_salved()
	if(CHECK_BITFIELD(injury_flags, INJURY_SALVED))
		return TRUE
	return FALSE

/datum/injury/proc/is_clamped()
	if(CHECK_BITFIELD(injury_flags, INJURY_CLAMPED))
		return TRUE
	return FALSE

/datum/injury/proc/is_sutured()
	if(CHECK_BITFIELD(injury_flags, INJURY_SUTURED))
		return TRUE
	return FALSE

/datum/injury/proc/is_bandaged()
	if(CHECK_BITFIELD(injury_flags, INJURY_BANDAGED))
		return TRUE
	return FALSE


code:
//injury helpers
/obj/item/bodypart/proc/get_injury_type(type, damage)
	if(is_organic_limb())
		switch(type)
			if(WOUND_SLASH)
				switch(damage)
					if(70 to INFINITY)
						return /datum/injury/slash/massive
					if(60 to 70)
						return /datum/injury/slash/gaping_big
					if(50 to 60)
						return /datum/injury/slash/gaping
					if(25 to 50)
						return /datum/injury/slash/flesh
					if(15 to 25)
						return /datum/injury/slash/deep
					if(0 to 15)
						return /datum/injury/slash/small
			if(WOUND_PIERCE)
				switch(damage)
					if(60 to INFINITY)
						return /datum/injury/puncture/massive
					if(50 to 60)
						return /datum/injury/puncture/gaping_big
					if(30 to 50)
						return /datum/injury/puncture/gaping
					if(15 to 30)
						return /datum/injury/puncture/flesh
					if(0 to 15)
						return /datum/injury/puncture/small
			if(WOUND_BLUNT)
				switch(damage)
					if(80 to INFINITY)
						return /datum/injury/bruise/monumental
					if(50 to 80)
						return /datum/injury/bruise/huge
					if(30 to 50)
						return /datum/injury/bruise/large
					if(10 to 20)
						return /datum/injury/bruise/moderate
					if(0 to 10)
						return /datum/injury/bruise/small
			if(WOUND_BURN)
				switch(damage)
					if(50 to INFINITY)
						return /datum/injury/burn/carbonised
					if(40 to 50)
						return /datum/injury/burn/deep
					if(30 to 40)
						return /datum/injury/burn/severe
					if(15 to 30)
						return /datum/injury/burn/large
					if(0 to 15)
						return /datum/injury/burn/moderate
	else
		switch(type)
			if(WOUND_SLASH)
				switch(damage)
					if(70 to INFINITY)
						return /datum/injury/slash/massive/mechanical
					if(60 to 70)
						return /datum/injury/slash/gaping_big/mechanical
					if(50 to 60)
						return /datum/injury/slash/gaping/mechanical
					if(25 to 50)
						return /datum/injury/slash/flesh/mechanical
					if(15 to 25)
						return /datum/injury/slash/deep/mechanical
					if(0 to 15)
						return /datum/injury/slash/small/mechanical
			if(WOUND_PIERCE)
				switch(damage)
					if(60 to INFINITY)
						return /datum/injury/puncture/massive/mechanical
					if(50 to 60)
						return /datum/injury/puncture/gaping_big/mechanical
					if(30 to 50)
						return /datum/injury/puncture/gaping/mechanical
					if(15 to 30)
						return /datum/injury/puncture/flesh/mechanical
					if(0 to 15)
						return /datum/injury/puncture/small/mechanical
			if(WOUND_BLUNT)
				switch(damage)
					if(80 to INFINITY)
						return /datum/injury/bruise/monumental/mechanical
					if(50 to 80)
						return /datum/injury/bruise/huge/mechanical
					if(30 to 50)
						return /datum/injury/bruise/large/mechanical
					if(10 to 20)
						return /datum/injury/bruise/moderate/mechanical
					if(0 to 10)
						return /datum/injury/bruise/small/mechanical
			if(WOUND_BURN)
				switch(damage)
					if(50 to INFINITY)
						return /datum/injury/burn/carbonised/mechanical
					if(40 to 50)
						return /datum/injury/burn/deep/mechanical
					if(30 to 40)
						return /datum/injury/burn/severe/mechanical
					if(15 to 30)
						return /datum/injury/burn/large/mechanical
					if(0 to 15)
						return /datum/injury/burn/moderate/mechanical
	return //no injury


code:
/** MECHANICAL BRUISES **/
/datum/injury/bruise/small/mechanical
	stages = list(
		"mild dent" = 15,
		"small dent" = 10,
		"tiny dent" = 5,
		"tiny depression" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/bruise/moderate/mechanical
	stages = list(
		"big dent" = 25,
		"moderate dent" = 20,
		"mild dent" = 15,
		"small dent" = 10,
		"small healing dent" = 5,
		"small depression" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/bruise/large/mechanical
	stages = list(
		"enormous dent" = 50,
		"large dent" = 30,
		"moderate dent" = 20,
		"mild dent" = 15,
		"small dent" = 10,
		"small healing dent" = 5,
		"small depression" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/bruise/huge/mechanical
	stages = list(
		"gigantic dent" = 80,
		"huge dent" = 50,
		"large dent" = 30,
		"moderate dent" = 20,
		"mild angry dent" = 15,
		"mild dent" = 10,
		"mild healing dent" = 5,
		"mild depression" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/bruise/monumental/mechanical
	stages = list(
		"monumental dent" = 80,
		"huge dent" = 50,
		"large angry dent" = 30,
		"large dent" = 20,
		"moderate angry dent" = 15,
		"moderate dent" = 10,
		"moderate healing dent" = 5,
		"moderate depression" = 0
		)
	required_status = BODYPART_ROBOTIC


code:
/** MECHANICAL BURNS **/
/datum/injury/burn/moderate/mechanical
	stages = list(
		"ripped scorch" = 10,
		"moderate scorch" = 5,
		"healing moderate scorch" = 2,
		"fresh singe" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/burn/large/mechanical
	stages = list(
		"ripped large scorch" = 20,
		"large scorch" = 15,
		"healing large scorch" = 5,
		"fresh singe" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/burn/severe/mechanical
	stages = list(
		"ripped severe scorch" = 35,
		"severe scorch" = 30,
		"healing severe scorch" = 10,
		"singing" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/burn/deep/mechanical
	stages = list(
		"ripped deep scorch" = 45,
		"deep scorch" = 40,
		"healing deep scorch" = 15,
		"large singing" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/burn/carbonised/mechanical
	stages = list(
		"warped area" = 50,
		"healing warped area" = 20,
		"massive singing" = 0
		)
	required_status = BODYPART_ROBOTIC


code:
/** MECHANICAL PUNCTURES **/
/datum/injury/puncture/small/mechanical
	stages = list(
		"perforation" = 5,
		"small perforation" = 2,
		"small nick" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/puncture/flesh/mechanical
	stages = list(
		"large rupture" = 15,
		"perforation" = 5,
		"large nick" = 2,
		"small round nick" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/puncture/gaping/mechanical
	stages = list(
		"gaping rupture" = 30,
		"large rupture" = 15,
		"large perforation" = 10,
		"small deep nick" = 5,
		"small nick" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/puncture/gaping_big/mechanical
	stages = list(
		"big gaping rupture" = 50,
		"gaping rupture" = 20,
		"large rupture" = 15,
		"large perforation" = 10,
		"large nick" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/puncture/massive/mechanical
	stages = list(
		"massive gaping rupture" = 60,
		"massive rupture" = 30,
		"massive pierce" = 25,
		"massive perforation" = 10,
		"massive jagged nick" = 0
		)
	required_status = BODYPART_ROBOTIC


code:
/** MECHANICAL SLASHES **/
/datum/injury/slash/small/mechanical
	stages = list(
		"ugly ripped laceration" = 20,
		"ripped laceration" = 10,
		"laceration" = 5,
		"healing cut" = 2,
		"small tear" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/slash/deep/mechanical
	stages = list(
		"ugly deep ripped laceration" = 25,
		"deep ripped laceration" = 20,
		"deep laceration" = 15,
		"laceration" = 8,
		"tear" = 2,
		"small tear" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/slash/flesh/mechanical
	stages = list(
		"ugly ripped gash" = 35,
		"ugly gash" = 30,
		"gash" = 25,
		"shallow gash" = 15,
		"large tear" = 5,
		"small tear" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/slash/gaping/mechanical
	stages = list(
		"gaping gash" = 50,
		"large gash" = 25,
		"shallow gash" = 15,
		"small angry tear" = 5,
		"small straight tear" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/slash/gaping_big/mechanical
	stages = list(
		"big gaping gash" = 60,
		"melding gaping gash" = 40,
		"large laceration" = 25,
		"large angry tear" = 10,
		"large straight tear" = 0
		)
	required_status = BODYPART_ROBOTIC

/datum/injury/slash/massive/mechanical
	stages = list(
		"massive gash" = 70,
		"massive melding gash" = 50,
		"massive soldering gash" = 25,
		"massive angry tear" = 10,
		"massive jagged tear" = 0
		)
	required_status = BODYPART_ROBOTIC


code:
/** BRUISES **/
/datum/injury/bruise
	bleed_threshold = 20
	autoheal_cutoff = 30
	damage_type = WOUND_BLUNT

/datum/injury/bruise/small
	stages = list(
		"mild bruise" = 15,
		"small bruise" = 10,
		"tiny bruise" = 5,
		"tiny hematoma" = 0
		)

/datum/injury/bruise/moderate
	stages = list(
		"big bruise" = 25,
		"moderate bruise" = 20,
		"mild bruise" = 15,
		"small bruise" = 10,
		"small healing bruise" = 5,
		"small hematoma" = 0
		)
	max_bleeding_stage = 2

/datum/injury/bruise/large
	stages = list(
		"enormous bruise" = 50,
		"large bruise" = 30,
		"moderate bruise" = 20,
		"mild bruise" = 15,
		"small bruise" = 10,
		"small healing bruise" = 5,
		"small hematoma" = 0
		)
	max_bleeding_stage = 3
	fade_away = INFINITY

/datum/injury/bruise/huge
	stages = list(
		"gigantic bruise" = 80,
		"huge bruise" = 50,
		"large bruise" = 30,
		"moderate bruise" = 20,
		"mild angry bruise" = 15,
		"mild bruise" = 10,
		"mild healing bruise" = 5,
		"mild hematoma" = 0
		)
	max_bleeding_stage = 4
	fade_away = INFINITY

/datum/injury/bruise/monumental
	stages = list(
		"monumental bruise" = 80,
		"huge bruise" = 50,
		"large angry bruise" = 30,
		"large bruise" = 20,
		"moderate angry bruise" = 15,
		"moderate bruise" = 10,
		"moderate healing bruise" = 5,
		"moderate hematoma" = 0
		)
	max_bleeding_stage = 4
	fade_away = INFINITY


code:
/** BURNS **/
/datum/injury/burn
	damage_type = WOUND_BURN
	autoheal_cutoff = 3
	max_bleeding_stage = 0
	infection_rate = 2.5

/datum/injury/burn/infection_check()
	//anything less than a FUCK burn isn't infectable if treated properly
	if(is_treated() && damage < 25)
		return FALSE
	if(is_disinfected())
		return FALSE
	//Robotic injury
	if(required_status == BODYPART_ROBOTIC)
		return FALSE

	switch(damage_type)
		if(WOUND_BLUNT)
			return prob(damage/2)
		if(WOUND_BURN)
			return prob(damage*2)
		if(WOUND_SLASH)
			return prob(damage)
		if(WOUND_PIERCE)
			return prob(damage*1.25)

	return FALSE

/datum/injury/burn/is_bleeding()
	return FALSE //burns cannot bleed

/datum/injury/burn/apply_injury(our_damage, obj/item/bodypart/limb)
	. = ..()
	//Burn damage can cause fluid loss due to blistering and cook-off
	if(limb.owner && (damage_per_injury() >= 5 || damage + limb.burn_dam >= 20))
		limb.owner.adjust_bloodvolume(-CEILING(BLOOD_VOLUME_SURVIVE * damage/100, 1))

/datum/injury/burn/receive_damage(damage_received = 0, pain_received = 0, wounding_type = WOUND_BLUNT)
	if((wounding_type == WOUND_BURN) && (damage + damage_received >= 50) && parent_bodypart)
		if(!parent_bodypart.is_dead())
			if(parent_bodypart.is_organic_limb())
				if(parent_mob)
					SEND_SIGNAL(parent_mob, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, " The [parent_bodypart.name] partially melts away!")
				parent_bodypart.kill_limb()
			else
				if(parent_bodypart.can_dismember())
					if(parent_mob)
						SEND_SIGNAL(parent_mob, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, " The [parent_bodypart.name] fully melts away!")
					parent_bodypart.apply_dismember(WOUND_BURN)
		else if(parent_bodypart.can_dismember())
			if(parent_bodypart.is_organic_limb())
				if(parent_mob)
					SEND_SIGNAL(parent_mob, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, " The [parent_bodypart.name] partially melts away!")
				parent_bodypart.kill_limb()
			else
				if(parent_mob)
					SEND_SIGNAL(parent_mob, COMSIG_CARBON_ADD_TO_WOUND_MESSAGE, " The [parent_bodypart.name] fully melts away!")
				parent_bodypart.apply_dismember(WOUND_BURN)

/datum/injury/burn/moderate
	stages = list(
		"ripped burn" = 10,
		"moderate burn" = 5,
		"healing moderate burn" = 2,
		"fresh skin" = 0
		)

/datum/injury/burn/large
	stages = list(
		"ripped large burn" = 20,
		"large burn" = 15,
		"healing large burn" = 5,
		"fresh burn scar" = 0
		)
	fade_away = INFINITY

/datum/injury/burn/severe
	stages = list(
		"ripped severe burn" = 35,
		"severe burn" = 30,
		"healing severe burn" = 10,
		"burn scar" = 0
		)
	fade_away = INFINITY

/datum/injury/burn/deep
	stages = list(
		"ripped deep burn" = 45,
		"deep burn" = 40,
		"healing deep burn" = 15,
		"large burn scar" = 0
		)
	fade_away = INFINITY

/datum/injury/burn/carbonised
	stages = list(
		"carbonised area" = 50,
		"healing carbonised area" = 20,
		"massive burn scar" = 0
		)
	fade_away = INFINITY


code:
/** LIMB LOSS **/
/datum/injury/lost_limb

/datum/injury/lost_limb/apply_injury(damage, obj/item/bodypart/limb, losstype, clean)
	var/damage_amt = limb.max_damage
	if(clean)
		damage_amt /= 2

	switch(losstype)
		if(WOUND_SLASH, WOUND_PIERCE)
			damage_type = WOUND_SLASH
			if(limb.is_robotic_limb())
				max_bleeding_stage = -1
				bleed_threshold = INFINITY
				stages = list("mangled robotic socket" = 0)
			else
				max_bleeding_stage = 3 //clotted stump and above can bleed.
				stages = list(
					"ripped stump" = damage_amt*1.3,
					"bloody stump" = damage_amt,
					"clotted stump" = damage_amt*0.5,
					"scarred stump" = 0
				)
		if(WOUND_BURN)
			damage_type = WOUND_BURN
			stages = list(
				"mangled charred stump" = damage_amt*1.3,
				"charred stump" = damage_amt,
				"scarred stump" = damage_amt*0.5,
				"scarred stump" = 0
				)

	. = ..(damage_amt)


code:
/** PUNCTURES **/
/datum/injury/puncture
	bleed_threshold = 10
	damage_type = WOUND_PIERCE

/datum/injury/puncture/can_worsen(damage_type, damage)
	return FALSE //cannot be enlargened

/datum/injury/puncture/small
	max_bleeding_stage = 2
	stages = list(
		"puncture" = 5,
		"healing puncture" = 2,
		"small round scab" = 0
		)

/datum/injury/puncture/flesh
	max_bleeding_stage = 2
	stages = list(
		"puncture wound" = 15,
		"round blood soaked clot" = 5,
		"large scab" = 2,
		"small round scar" = 0
		)
	fade_away = INFINITY

/datum/injury/puncture/gaping
	max_bleeding_stage = 3
	stages = list(
		"gaping hole" = 30,
		"large round blood soaked clot" = 15,
		"round blood soaked clot" = 10,
		"small round angry scar" = 5,
		"small round scar" = 0
		)
	fade_away = INFINITY

/datum/injury/puncture/gaping_big
	max_bleeding_stage = 3
	stages = list(
		"big gaping hole" = 50,
		"healing gaping hole" = 20,
		"large round blood soaked clot" = 15,
		"large round angry scar" = 10,
		"large round scar" = 0
		)
	fade_away = INFINITY

/datum/injury/puncture/massive
	max_bleeding_stage = 3
	stages = list(
		"massive hole" = 60,
		"massive healing hole" = 30,
		"massive round blood soaked clot" = 25,
		"massive round angry scar" = 10,
		"massive round jagged scar" = 0
		)
	fade_away = INFINITY


code:
/** SLASHES **/
/datum/injury/slash
	bleed_threshold = 5
	damage_type = WOUND_SLASH

/datum/injury/slash/small
	// link wound descriptions to amounts of damage
	// Minor cuts have max_bleeding_stage set to the stage that bears the wound type's name.
	// The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
	max_bleeding_stage = 3
	stages = list(
		"ugly ripped cut" = 20,
		"ripped cut" = 10,
		"cut" = 5,
		"healing cut" = 2,
		"small scab" = 0
		)

/datum/injury/slash/deep
	max_bleeding_stage = 3
	stages = list(
		"ugly deep ripped cut" = 25,
		"deep ripped cut" = 20,
		"deep cut" = 15,
		"clotted cut" = 8,
		"scab" = 2,
		"fresh scar" = 0
		)
	fade_away = INFINITY

/datum/injury/slash/flesh
	max_bleeding_stage = 4
	stages = list(
		"ugly ripped flesh wound" = 35,
		"ugly flesh wound" = 30,
		"flesh wound" = 25,
		"blood soaked clot" = 15,
		"large scab" = 5,
		"fresh scar" = 0
		)
	fade_away = INFINITY

/datum/injury/slash/gaping
	max_bleeding_stage = 3
	stages = list(
		"gaping wound" = 50,
		"large blood soaked clot" = 25,
		"blood soaked clot" = 15,
		"small angry scar" = 5,
		"small straight scar" = 0
		)
	fade_away = INFINITY

/datum/injury/slash/gaping_big
	max_bleeding_stage = 3
	stages = list(
		"big gaping wound" = 60,
		"healing gaping wound" = 40,
		"large blood soaked clot" = 25,
		"large angry scar" = 10,
		"large straight scar" = 0
		)
	fade_away = INFINITY

/datum/injury/slash/massive
	max_bleeding_stage = 3
	stages = list(
		"massive wound" = 70,
		"massive healing wound" = 50,
		"massive blood soaked clot" = 25,
		"massive angry scar" = 10,
		"massive jagged scar" = 0
		)
	fade_away = INFINITY


code:
/obj/item/bodypart/chest
	name = "upper body"
	desc = "It's impolite to stare at someone's chest."
	icon_state = "default_human_chest"
	max_damage = 100
	max_stamina_damage = 100
	body_zone = BODY_ZONE_CHEST
	body_part = CHEST
	px_x = 0
	px_y = 0
	stam_damage_coeff = 1
	maxdam_wound_penalty = 20 //hard to hit this cap
	dismemberable = FALSE
	limb_flags = (BODYPART_EDIBLE|BODYPART_NO_STUMP|BODYPART_HAS_BONE|BODYPART_HAS_TENDON|BODYPART_HAS_NERVE|BODYPART_HAS_ARTERY)
	children_zones = list(BODY_ZONE_PRECISE_NECK, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
	gender_rendering = TRUE

	max_cavity_item_size = WEIGHT_CLASS_BULKY
	max_cavity_volume = 8

	//Positive modifier, hard to miss
	hit_modifier = 2
	//Positive modifier, hard to miss
	hit_zone_modifier = 4

	cavity_name = "thoracic cavity"
	amputation_point_name = "spine"
	bone_type = BONE_CHEST
	tendon_type = TENDON_CHEST
	artery_type = ARTERY_CHEST
	nerve_type = NERVE_CHEST

/obj/item/bodypart/chest/can_dismember(obj/item/I)
	return FALSE

/obj/item/bodypart/chest/drop_limb(special, ignore_children = FALSE, dismembered = FALSE, destroyed = FALSE, wounding_type = WOUND_SLASH)
	if(special)
		return ..()


code:
/obj/item/bodypart/face
	name = "face"
	desc = "You're face, to face, with the man who sold the world."
	icon = 'modular_septic/icons/obj/surgery.dmi'
	icon_state = "face"
	base_icon_state = "face"
	worn_icon = 'modular_septic/icons/mob/clothing/unsorted.dmi'
	worn_icon_state = "blank"
	max_damage = 30
	max_stamina_damage = 30
	parent_body_zone = BODY_ZONE_HEAD
	body_zone = BODY_ZONE_PRECISE_FACE
	body_part = FACE
	w_class = WEIGHT_CLASS_SMALL // Basically a flap of skin
	px_x = 0
	px_y = -8
	stam_damage_coeff = 1
	maxdam_wound_penalty = 10 // too easy to hit max damage
	dismemberable = FALSE
	limb_flags = (BODYPART_EDIBLE|BODYPART_NO_STUMP)

	max_cavity_item_size = WEIGHT_CLASS_SMALL
	max_cavity_volume = 1

	hit_modifier = -2
	hit_zone_modifier = -1

	amputation_point_name = "head"

	throw_range = 2 //not very aerodynamic
	dismemberment_sounds = list('modular_septic/sound/gore/severed.ogg')
	scars_covered_by_clothes = FALSE

	flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
	body_parts_covered = HEAD|FACE|JAW
	slot_flags = ITEM_SLOT_MASK

	deflect_zone = BODY_ZONE_HEAD
	deflect_chance = 50

	// ~limb appearance info
	/// Replacement name
	var/real_name = ""
	/// Left eye
	var/obj/item/bodypart/l_eyesocket/left_eye
	/// Right eye
	var/obj/item/bodypart/r_eyesocket/right_eye
	/// Jaw
	var/obj/item/bodypart/mouth/jaw

/obj/item/bodypart/face/get_limb_icon(dropped)
	icon_state = ""
	if(dropped && !isbodypart(loc))
		. = list()
		var/image/funky_anus
		funky_anus = image(icon, src, base_icon_state, BELOW_MOB_LAYER)
		funky_anus.plane = plane
		if(is_robotic_limb())
			funky_anus.icon_state = "[funky_anus.icon_state]-c"
		. += funky_anus

/obj/item/bodypart/face/get_shock(painkiller_included, nerve_included)
	nerve_included = FALSE
	return ..()

/obj/item/bodypart/face/transfer_to_limb(obj/item/bodypart/new_limb, mob/living/carbon/phantom_owner)
	. = ..()
	if(istype(new_limb, /obj/item/bodypart/head))
		var/obj/item/bodypart/head/head = new_limb
		head.face = src

/obj/item/bodypart/face/receive_damage(brute, burn, stamina, blocked, updating_health, required_status, wound_bonus, bare_wound_bonus, sharpness, spread_damage, pain, toxin, clone)
	. = ..()
	if(owner)
		if((burn_dam + burn >= max_damage) && !HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, BURN))
			owner.visible_message(span_danger("[owner]'s face turns into an unrecognizable, burnt mess!"), \
								span_userdanger("MY FACE MELTS AWAY!"))
			ADD_TRAIT(owner, TRAIT_DISFIGURED, BURN)
			ADD_TRAIT(src, TRAIT_DISFIGURED, BURN)
		if((brute_dam + brute >= max_damage) && !HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, BRUTE))
			owner.visible_message(span_danger("[owner]'s face turns into an unrecognizable, mangled mess!"), \
								span_userdanger("MY FACE IS MANGLED!"))
			ADD_TRAIT(owner, TRAIT_DISFIGURED, BRUTE)
			ADD_TRAIT(src, TRAIT_DISFIGURED, BRUTE)

/obj/item/bodypart/face/on_rotten_trait_gain(obj/item/bodypart/source)
	. = ..()
	if(owner && !HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, GERM_LEVEL))
		ADD_TRAIT(owner, TRAIT_DISFIGURED, GERM_LEVEL)
	ADD_TRAIT(src, TRAIT_DISFIGURED, GERM_LEVEL)

/obj/item/bodypart/face/on_rotten_trait_loss(obj/item/bodypart/source)
	. = ..()
	if(owner && HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, GERM_LEVEL))
		REMOVE_TRAIT(owner, TRAIT_DISFIGURED, GERM_LEVEL)
	REMOVE_TRAIT(src, TRAIT_DISFIGURED, GERM_LEVEL)

/obj/item/bodypart/face/attach_limb(mob/living/carbon/new_owner, special = FALSE, ignore_parent = FALSE)
	// These are stored before calling super- This is so that if the head is from a different body, it persists its appearance.
	var/real_name = src.real_name

	. = ..()
	if(!.)
		return

	if(real_name)
		new_owner.real_name = real_name

	real_name = ""
	name = initial(name)

	//Add disfigured trait as needed
	if(HAS_TRAIT_FROM(src, TRAIT_DISFIGURED, BRUTE))
		ADD_TRAIT(new_owner, TRAIT_DISFIGURED, BRUTE)
	if(HAS_TRAIT_FROM(src, TRAIT_DISFIGURED, BURN))
		ADD_TRAIT(new_owner, TRAIT_DISFIGURED, BURN)
	if(HAS_TRAIT_FROM(src, TRAIT_DISFIGURED, GERM_LEVEL))
		ADD_TRAIT(new_owner, TRAIT_DISFIGURED, GERM_LEVEL)

	if(!(new_owner.status_flags & BUILDING_ORGANS))
		new_owner.updatehealth()
		new_owner.update_body()
		new_owner.update_hair()
		new_owner.update_damage_overlays()
		new_owner.update_name()

/obj/item/bodypart/face/dismember(dam_type = BRUTE, silent = TRUE, destroy = FALSE, wounding_type = WOUND_SLASH)
	var/obj/item/bodypart/head = owner?.get_bodypart(parent_body_zone)
	if(head)
		return head.dismember(dam_type, silent, destroy, wounding_type)
	else
		return ..()

/obj/item/bodypart/face/drop_limb(special, dismembered, ignore_children, destroyed, wounding_type = WOUND_SLASH)
	var/mob/old_owner = owner
	if(!special)
		//Drop all worn face items
		for(var/X in list(owner.wear_mask))
			var/obj/item/item = X
			owner.dropItemToGround(item, force = TRUE)
		//Remove disfigured trait
		if(HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, BRUTE))
			REMOVE_TRAIT(owner, TRAIT_DISFIGURED, BRUTE)
		if(HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, BURN))
			REMOVE_TRAIT(owner, TRAIT_DISFIGURED, BURN)
		if(HAS_TRAIT_FROM(owner, TRAIT_DISFIGURED, GERM_LEVEL))
			REMOVE_TRAIT(owner, TRAIT_DISFIGURED, GERM_LEVEL)
	. = ..()
	old_owner.update_name()

/obj/item/bodypart/face/update_limb(dropping_limb, mob/living/carbon/source)
	. = ..()
	if(!owner)
		name = initial(name)
		if(real_name)
			name = "[real_name]'s face"
	else
		name = initial(name)

	if(istype(loc, /obj/item/bodypart/head))
		var/obj/item/bodypart/head/head = loc
		head.update_limb(dropping_limb, source)

	if(no_update)
		return

	var/mob/living/carbon/carbon
	if(source)
		carbon = source
	else
		carbon = owner

	real_name = carbon?.real_name
	if( (carbon && (HAS_TRAIT(carbon, TRAIT_HUSK) || HAS_TRAIT(carbon, TRAIT_DISFIGURED)) ) || HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_DISFIGURED))
		real_name = "Unknown"

/obj/item/bodypart/face/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
	if(!isinhands)
		return get_worn_limb_icon()
	else
		return ..()

/obj/item/bodypart/face/equipped(mob/user, slot, initial)
	. = ..()
	user.update_name()

/obj/item/bodypart/face/dropped(mob/user, silent)
	. = ..()
	user.update_name()

/obj/item/bodypart/face/proc/get_worn_limb_icon()
	. = list()

	var/image/limb = image(layer = -render_layer)
	var/image/aux
	. += limb

	if(animal_origin)
		if(is_organic_limb())
			limb.icon = DEFAULT_BODYPART_ICON_ANIMAL
			if(species_id == "husk")
				limb.icon_state = "[animal_origin]_husk_[body_zone]"
			else
				limb.icon_state = "[animal_origin]_[body_zone]"
		else
			limb.icon = DEFAULT_BODYPART_ICON_ROBOTIC
			limb.icon_state = "[animal_origin]_[body_zone]"
		return

	var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable

	if(!gender_rendering)
		should_draw_gender = FALSE

	if(advanced_rendering)
		if(should_draw_greyscale)
			limb.icon = render_icon || DEFAULT_BODYPART_ICON_ORGANIC
			if(should_draw_gender)
				limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
			else if(use_digitigrade)
				limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]"
			else
				limb.icon_state = "[species_id]_[body_zone]"
		else
			limb.icon = render_icon || DEFAULT_BODYPART_ICON
			if(should_draw_gender)
				limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
			else
				limb.icon_state = "[species_id]_[body_zone]"
	else
		limb.icon = icon
		limb.icon_state = "[BODY_ZONE_HEAD]" //Inorganic limbs are agender
		return

	if(should_draw_greyscale)
		var/draw_color = mutation_color || species_color || skintone2hex(skin_tone)
		if(draw_color)
			limb.color = sanitize_hexcolor(draw_color, 6, TRUE)
			if(aux)
				aux.color = limb.color

	if (!owner || is_pseudopart || is_stump() || HAS_TRAIT(src, TRAIT_ROTTEN) || !ishuman(owner))
		return

	var/mob/living/carbon/human/human = owner
	//set specific alpha before setting the markings alpha
	if(alpha != 255)
		for(var/ov in .)
			var/image/overlay = ov
			overlay.alpha = alpha

	if(!LAZYLEN(body_markings))
		return

	//Markings!
	var/override_color
	if(HAS_TRAIT(human, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_HUSK))
		override_color = "888888"

	for(var/name in body_markings["[BODY_ZONE_HEAD]"])
		var/datum/body_marking/marking = GLOB.body_markings[name]
		var/render_limb_string = BODY_ZONE_HEAD
		if(use_digitigrade)
			render_limb_string = "digitigrade_[use_digitigrade]_[render_limb_string]"

		if(marking.gendered && gender_rendering)
			var/marking_gender = (human.body_type == FEMALE) ? "f" : "m"
			render_limb_string = "[render_limb_string]_[marking_gender]"

		var/mutable_appearance/accessory_overlay = mutable_appearance(marking.icon, "[marking.icon_state]_[render_limb_string]", -BODY_ADJ_LAYER)
		if(body_zone in list(BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_HAND))
			accessory_overlay.layer = -HANDS_ADJ_LAYER
		if(override_color)
			accessory_overlay.color = sanitize_hexcolor(override_color, 6, TRUE)
		else
			accessory_overlay.color = sanitize_hexcolor(body_markings[body_zone][name], 6, TRUE)
		accessory_overlay.alpha = markings_alpha
		. += accessory_overlay


code:
/obj/item/bodypart/groin
	name = "lower body"
	desc = "Some say groin came from grynde, which is middle-ages speak for depression. Makes sense for the situation."
	icon_state = "default_human_groin"
	max_damage = 100
	max_stamina_damage = 100
	parent_body_zone = BODY_ZONE_CHEST
	body_zone = BODY_ZONE_PRECISE_GROIN
	body_part = GROIN
	px_x = 0
	px_y = 4
	stam_damage_coeff = 1
	maxdam_wound_penalty = 20 //hard to hit this cap
	limb_flags = (BODYPART_EDIBLE|BODYPART_HAS_BONE|BODYPART_HAS_TENDON|BODYPART_HAS_NERVE|BODYPART_HAS_ARTERY)
	children_zones = list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
	gender_rendering = TRUE

	max_cavity_item_size = WEIGHT_CLASS_NORMAL
	max_cavity_volume = 7

	//Positive modifier, hard to miss
	hit_zone_modifier = 1

	cavity_name = "abdominal cavity"
	amputation_point_name = "lumbar"
	bone_type = BONE_GROIN
	tendon_type = TENDON_GROIN
	artery_type = ARTERY_GROIN
	nerve_type = NERVE_GROIN