diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 878ed53f990..c4e4b40b56c 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -293,10 +293,11 @@ DEFINE_BITFIELD(ammo_box_multiload, list(
#define BODY_ZONE_PRECISE_L_FOOT "l_foot"
#define BODY_ZONE_PRECISE_R_FOOT "r_foot"
-GLOBAL_LIST_INIT(all_body_zones, list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
-GLOBAL_LIST_INIT(limb_zones, list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
+// These lists are ordered as bodyparts would be ordered
+GLOBAL_LIST_INIT(all_body_zones, list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
+GLOBAL_LIST_INIT(limb_zones, list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
-GLOBAL_LIST_INIT(leg_zones, list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
+GLOBAL_LIST_INIT(leg_zones, list(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
GLOBAL_LIST_INIT(all_precise_body_zones, list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_PRECISE_L_FOOT, BODY_ZONE_PRECISE_R_FOOT))
//We will round to this value in damage calculations.
diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm
index ab8fee7c9a0..fcf8b853cad 100644
--- a/code/__DEFINES/surgery.dm
+++ b/code/__DEFINES/surgery.dm
@@ -54,6 +54,9 @@
/// Helper to figure out if a limb is a peg limb
#define IS_PEG_LIMB(limb) (limb.bodytype & BODYTYPE_PEG)
+/// Is the bodypart a stump
+#define IS_STUMP(limb) (limb.bodypart_flags & BODYPART_STUMP)
+
// Flags for the bodypart_flags var on /obj/item/bodypart
/// Bodypart cannot be dismembered or amputated
#define BODYPART_UNREMOVABLE (1<<0)
@@ -65,6 +68,8 @@
#define BODYPART_UNHUSKABLE (1<<3)
/// Bodypart has never been added to a mob
#define BODYPART_VIRGIN (1<<4)
+/// Not a full bodypart, but in fact is part of a missing limb
+#define BODYPART_STUMP (1<<5)
// Bodypart change blocking flags
///Bodypart does not get replaced during set_species()
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 4ff1e10a22f..5e6f71b33c9 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -161,7 +161,7 @@
/// Orders bodyparts by their body_part value, ascending.
/proc/cmp_bodypart_by_body_part_asc(obj/item/bodypart/limb_one, obj/item/bodypart/limb_two)
- return limb_one.body_part - limb_two.body_part
+ return limb_one::body_part - limb_two::body_part
/// Orders by integrated circuit weight
/proc/cmp_port_order_asc(datum/port/compare1, datum/port/compare2)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 533099c3918..250219e8740 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -799,8 +799,9 @@
update_appearance()
/atom/movable/screen/healthdoll/human/update_body_zones()
- limbs = list()
vis_contents.Cut()
+ QDEL_LIST_ASSOC_VAL(limbs)
+ limbs ||= list()
var/mob/living/carbon/human/owner = hud.mymob
for(var/body_zone in owner.get_all_limbs())
var/atom/movable/screen/healthdoll_limb/limb = new(src, null)
@@ -827,12 +828,13 @@
var/list/current_animated = LAZYLISTDUPLICATE(animated_zones)
- for(var/obj/item/bodypart/body_part as anything in owner.bodyparts)
+ for(var/part_zone, body_part_untyped in owner.get_bodyparts_by_zones())
var/icon_key = 0
- var/part_zone = body_part.body_zone
-
+ var/obj/item/bodypart/body_part = body_part_untyped
var/list/overridable_key = list(icon_key)
- if(body_part.bodypart_disabled)
+ if(isnull(body_part) || IS_STUMP(body_part))
+ icon_key = 6
+ else if(body_part.bodypart_disabled)
icon_key = 7
else if(owner.stat == DEAD)
icon_key = "DEAD"
@@ -843,15 +845,11 @@
// calculate what icon state (1-5, or 0 if undamaged) to use based on damage
icon_key = clamp(ceil(damage * 5), 0, 5)
- if(length(body_part.wounds))
+ if(length(body_part?.wounds))
LAZYSET(animated_zones, part_zone, TRUE)
else
LAZYREMOVE(animated_zones, part_zone)
limbs[part_zone].icon_state = "[part_zone][icon_key]"
- // handle leftovers
- for(var/missing_zone in owner.get_missing_limbs())
- limbs[missing_zone].icon_state = "[missing_zone]6"
- LAZYREMOVE(animated_zones, missing_zone)
// time to re-sync animations, something changed
if(animated_zones ~! current_animated)
for(var/animated_zone in animated_zones)
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 7f057a85bf8..c37d6d9d417 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -408,7 +408,7 @@
return TRUE
/mob/living/carbon/attack_effects(damage_done, hit_zone, armor_block, obj/item/attacking_item, mob/living/attacker)
- var/obj/item/bodypart/hit_bodypart = get_bodypart(hit_zone) || bodyparts[1]
+ var/obj/item/bodypart/hit_bodypart = get_bodypart(hit_zone) || get_bodypart()
if(!hit_bodypart.can_bleed())
return FALSE
diff --git a/code/controllers/subsystem/radiation.dm b/code/controllers/subsystem/radiation.dm
index a129c2a3464..316331db7c9 100644
--- a/code/controllers/subsystem/radiation.dm
+++ b/code/controllers/subsystem/radiation.dm
@@ -132,7 +132,7 @@ SUBSYSTEM_DEF(radiation)
/// Returns whether or not the human is covered head to toe in rad-protected clothing.
/datum/controller/subsystem/radiation/proc/wearing_rad_protected_clothing(mob/living/carbon/human/human)
- for (var/obj/item/bodypart/limb as anything in human.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in human.get_bodyparts())
var/protected = FALSE
for (var/obj/item/clothing as anything in human.get_clothing_on_part(limb))
diff --git a/code/datums/bodypart_overlays/texture_bodypart_overlay.dm b/code/datums/bodypart_overlays/texture_bodypart_overlay.dm
index 70086d45f9c..920c2973ac8 100644
--- a/code/datums/bodypart_overlays/texture_bodypart_overlay.dm
+++ b/code/datums/bodypart_overlays/texture_bodypart_overlay.dm
@@ -17,7 +17,8 @@
appearance.add_filter("bodypart_texture_[texture_icon_state]", 1, layering_filter(icon = cached_texture_icon, blend_mode = BLEND_INSET_OVERLAY))
/datum/bodypart_overlay/texture/generate_icon_cache()
- return "[type]"
+ . = ..()
+ . += "[type]"
/datum/bodypart_overlay/texture/can_draw_on_bodypart(obj/item/bodypart/bodypart_owner, mob/living/carbon/owner, is_husked = FALSE)
if (!..())
diff --git a/code/datums/components/amputating_limbs.dm b/code/datums/components/amputating_limbs.dm
index bfaf52ca90c..28a69ee5a19 100644
--- a/code/datums/components/amputating_limbs.dm
+++ b/code/datums/components/amputating_limbs.dm
@@ -58,7 +58,7 @@
return
var/list/valid_targets = list()
- for (var/obj/item/bodypart/possible_target as anything in limbed_victim.bodyparts)
+ for (var/obj/item/bodypart/possible_target as anything in limbed_victim.get_bodyparts())
if (possible_target.bodypart_flags & BODYPART_UNREMOVABLE)
continue
if (!(possible_target.body_zone in target_zones))
diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm
index 4dc7a7feeb6..09c945c2f8d 100644
--- a/code/datums/components/bloodysoles.dm
+++ b/code/datums/components/bloodysoles.dm
@@ -326,7 +326,7 @@
return
// Find any leg of our human and add that to the footprint, instead of the default which is to just add the human type
- for(var/obj/item/bodypart/leg/affecting in wielder.bodyparts)
+ for(var/obj/item/bodypart/leg/affecting in wielder.get_bodyparts())
if(!affecting.bodypart_disabled)
LAZYSET(footprint.species_types, affecting.limb_id, TRUE)
diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm
index b1f7eebab1f..bdc41329a74 100644
--- a/code/datums/components/butchering.dm
+++ b/code/datums/components/butchering.dm
@@ -167,7 +167,7 @@
if (target.body_zone == BODY_ZONE_CHEST && target.owner)
// Cannot butcher the chest until we hack off all the other limbs
- for (var/obj/item/bodypart/limb as anything in target.owner.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in target.owner.get_bodyparts())
if (limb != target && limb.butcher_drops && limb.butcher_replacement)
to_chat(user, span_warning("You need to butcher all other limbs first!"))
return
@@ -249,7 +249,7 @@
for(var/obj/item/result as anything in results)
if (reagents_in_produced)
if (target.owner.reagents)
- target.owner.reagents.trans_to(result, target.owner.reagents.total_volume / reagents_in_produced / length(target.owner.bodyparts), remove_blacklisted = TRUE)
+ target.owner.reagents.trans_to(result, target.owner.reagents.total_volume / reagents_in_produced / length(target.owner.get_bodyparts()), remove_blacklisted = TRUE)
result.reagents?.add_reagent(/datum/reagent/consumable/nutriment/fat, target.owner.nutrition / /datum/reagent/consumable/nutriment/fat::nutriment_factor / reagents_in_produced)
if(LAZYLEN(diseases))
diff --git a/code/datums/components/free_operation.dm b/code/datums/components/free_operation.dm
index a8002ef7f23..1c557cda5ea 100644
--- a/code/datums/components/free_operation.dm
+++ b/code/datums/components/free_operation.dm
@@ -9,17 +9,17 @@
return COMPONENT_REDUNDANT
ADD_TRAIT(parent, TRAIT_READY_TO_OPERATE, REF(src))
var/mob/living/carbon/owner = parent
- if(!istype(owner))
+ if (!istype(owner))
return
- for (var/obj/item/bodypart/limb as anything in owner.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in owner.get_bodyparts(include_stumps = TRUE))
ADD_TRAIT(limb, TRAIT_READY_TO_OPERATE, REF(src))
/datum/component/free_operation/Destroy(force)
REMOVE_TRAIT(parent, TRAIT_READY_TO_OPERATE, REF(src))
var/mob/living/carbon/owner = parent
- if(!istype(owner))
+ if (!istype(owner))
return ..()
- for (var/obj/item/bodypart/limb as anything in owner.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in owner.get_bodyparts(include_stumps = TRUE))
REMOVE_TRAIT(limb, TRAIT_READY_TO_OPERATE, REF(src))
return ..()
diff --git a/code/datums/components/healing_touch.dm b/code/datums/components/healing_touch.dm
index b8580e2e458..f7a9515c9c0 100644
--- a/code/datums/components/healing_touch.dm
+++ b/code/datums/components/healing_touch.dm
@@ -174,7 +174,7 @@
if (!iscarbon(target))
return (target.get_brute_loss() > 0 && heal_brute) || (target.get_fire_loss() > 0 && heal_burn)
var/mob/living/carbon/carbon_target = target
- for (var/obj/item/bodypart/part in carbon_target.bodyparts)
+ for (var/obj/item/bodypart/part in carbon_target.get_bodyparts())
if (!(part.brute_dam && heal_brute) && !(part.burn_dam && heal_burn))
continue
if (!isnull(required_bodytype) && !(part.bodytype & required_bodytype))
diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm
index d12e0812335..d767f33fae3 100644
--- a/code/datums/diseases/advance/symptoms/flesh_eating.dm
+++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm
@@ -60,7 +60,7 @@ Bonus
if(bleed)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- var/obj/item/bodypart/random_part = pick(H.bodyparts)
+ var/obj/item/bodypart/random_part = pick(H.get_bodyparts())
random_part.adjustBleedStacks(5 * power)
return 1
diff --git a/code/datums/elements/blood_limb_overlay.dm b/code/datums/elements/blood_limb_overlay.dm
index 3028d3f4754..bab7b6cb0ec 100644
--- a/code/datums/elements/blood_limb_overlay.dm
+++ b/code/datums/elements/blood_limb_overlay.dm
@@ -12,10 +12,10 @@
. = ..()
UnregisterSignal(source, list(COMSIG_BODYPART_GET_LIMB_ICON, COMSIG_BODYPART_GENERATE_ICON_KEY))
-/datum/element/blood_limb_overlay/proc/on_limb_icon(obj/item/bodypart/source, list/limb_icons, dropped, mob/living/carbon/update_on)
+/datum/element/blood_limb_overlay/proc/on_limb_icon(obj/item/bodypart/source, list/limb_icons, dropped)
SIGNAL_HANDLER
- var/list/blood_dna_info = source.blood_dna_info || update_on?.get_blood_dna_list()
+ var/list/blood_dna_info = source.blood_dna_info
if (!LAZYLEN(blood_dna_info) || source.is_invisible)
return
@@ -38,4 +38,4 @@
var/list/blood_dna_info = source.blood_dna_info || source.owner?.get_blood_dna_list()
if (LAZYLEN(blood_dna_info) && !source.is_invisible)
- icon_keys += "-blood-[get_color_from_blood_list(blood_dna_info)]"
+ icon_keys += "blood:[get_color_from_blood_list(blood_dna_info)]"
diff --git a/code/datums/elements/organ_set_bonus.dm b/code/datums/elements/organ_set_bonus.dm
index 07d7e2474d2..49cd58ddf93 100644
--- a/code/datums/elements/organ_set_bonus.dm
+++ b/code/datums/elements/organ_set_bonus.dm
@@ -105,7 +105,7 @@
RegisterSignal(carbon_owner, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(texture_limb))
RegisterSignal(carbon_owner, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(untexture_limb))
- for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_owner.get_bodyparts())
if (!(limb.bodytype & BODYTYPE_ORGANIC))
continue
limb.add_bodypart_overlay(new limb_overlay(), update = FALSE)
@@ -139,7 +139,7 @@
if(QDELETED(carbon_owner))
return
- for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_owner.get_bodyparts())
var/overlay = locate(limb_overlay) in limb.bodypart_overlays
if(!overlay)
continue
diff --git a/code/datums/elements/spooky.dm b/code/datums/elements/spooky.dm
index 85daaaeda78..4ae70bb5095 100644
--- a/code/datums/elements/spooky.dm
+++ b/code/datums/elements/spooky.dm
@@ -52,7 +52,7 @@
if(isskeleton(human))
return FALSE //undeads are unaffected by the spook-pocalypse.
var/bone_amount = 0
- for(var/obj/item/bodypart/part as anything in human.bodyparts)
+ for(var/obj/item/bodypart/part as anything in human.get_bodyparts())
if((part.biological_state & BIO_FLESH_BONE) == BIO_FLESH_BONE)
bone_amount++
if(bone_amount)
diff --git a/code/datums/embedding.dm b/code/datums/embedding.dm
index 77fec4f8746..32d838eedf4 100644
--- a/code/datums/embedding.dm
+++ b/code/datums/embedding.dm
@@ -133,7 +133,7 @@
failed_embed(victim, hit_zone, random = TRUE)
return
- var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || victim.bodyparts[1]
+ var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || victim.get_bodypart()
embed_into(victim, limb)
return MOVABLE_IMPACT_ZONE_OVERRIDE
@@ -153,7 +153,7 @@
failed_embed(victim, hit_zone, random = TRUE)
return
- var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || victim.bodyparts[1]
+ var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || victim.get_bodypart()
embed_into(victim, limb)
SEND_SIGNAL(source, COMSIG_PROJECTILE_ON_EMBEDDED, payload, hit)
diff --git a/code/datums/mutations/autotomy.dm b/code/datums/mutations/autotomy.dm
index 03575a8f039..da34bfd4660 100644
--- a/code/datums/mutations/autotomy.dm
+++ b/code/datums/mutations/autotomy.dm
@@ -27,7 +27,7 @@
return
var/list/parts = list()
- for(var/obj/item/bodypart/to_remove as anything in cast_on.bodyparts)
+ for(var/obj/item/bodypart/to_remove as anything in cast_on.get_bodyparts())
if(to_remove.body_zone == BODY_ZONE_HEAD || to_remove.body_zone == BODY_ZONE_CHEST)
continue
if(to_remove.bodypart_flags & BODYPART_UNREMOVABLE)
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 9de066eeacb..6fd35026309 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -33,7 +33,7 @@
. = ..()
if(!.)
return
- for(var/obj/item/bodypart/part as anything in owner.bodyparts)
+ for(var/obj/item/bodypart/part as anything in owner.get_bodyparts())
if (part.bodytype & BODYTYPE_ORGANIC)
part.add_color_override(bodypart_color, LIMB_COLOR_HULK)
owner.update_body_parts()
@@ -74,7 +74,7 @@
/datum/mutation/hulk/on_losing(mob/living/carbon/human/owner)
if(..())
return
- for(var/obj/item/bodypart/part as anything in owner.bodyparts)
+ for(var/obj/item/bodypart/part as anything in owner.get_bodyparts())
part.remove_color_override(LIMB_COLOR_HULK)
owner.update_body_parts()
owner.clear_mood_event("hulk")
diff --git a/code/datums/mutations/touch.dm b/code/datums/mutations/touch.dm
index ba24f4f30bc..7a91cc390e8 100644
--- a/code/datums/mutations/touch.dm
+++ b/code/datums/mutations/touch.dm
@@ -226,7 +226,7 @@
// Get at least organic limb to transfer the damage to
var/list/mendicant_organic_limbs = list()
- for(var/obj/item/bodypart/possible_limb in mendicant.bodyparts)
+ for(var/obj/item/bodypart/possible_limb in mendicant.get_bodyparts())
if(IS_ORGANIC_LIMB(possible_limb))
mendicant_organic_limbs += possible_limb
// None? Gtfo
@@ -258,7 +258,7 @@
// Get the hurtguy's limbs and the mendicant's limbs to attempt a 1-1 transfer.
var/list/hurt_limbs = hurtguy.get_damaged_bodyparts(1, 1, BODYTYPE_ORGANIC) + hurtguy.get_wounded_bodyparts(BODYTYPE_ORGANIC)
var/list/mendicant_organic_limbs = list()
- for(var/obj/item/bodypart/possible_limb in mendicant.bodyparts)
+ for(var/obj/item/bodypart/possible_limb in mendicant.get_bodyparts())
if(IS_ORGANIC_LIMB(possible_limb))
mendicant_organic_limbs += possible_limb
diff --git a/code/datums/quirks/negative_quirks/body_purist.dm b/code/datums/quirks/negative_quirks/body_purist.dm
index 76221df7a5c..063887b8746 100644
--- a/code/datums/quirks/negative_quirks/body_purist.dm
+++ b/code/datums/quirks/negative_quirks/body_purist.dm
@@ -31,7 +31,7 @@
var/mob/living/carbon/owner = quirk_holder
if(!istype(owner))
return
- for(var/obj/item/bodypart/limb as anything in owner.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in owner.get_bodyparts())
if(IS_ROBOTIC_LIMB(limb))
cybernetics_level++
for(var/obj/item/organ/organ as anything in owner.organs)
diff --git a/code/datums/quirks/neutral_quirks/transhumanist.dm b/code/datums/quirks/neutral_quirks/transhumanist.dm
index 82570e6cf21..6dfa2d16f6c 100644
--- a/code/datums/quirks/neutral_quirks/transhumanist.dm
+++ b/code/datums/quirks/neutral_quirks/transhumanist.dm
@@ -76,7 +76,7 @@
var/organic_bodytypes = 0
var/silicon_bodytypes = 0
var/other_bodytypes = FALSE
- for(var/obj/item/bodypart/part as anything in target.bodyparts)
+ for(var/obj/item/bodypart/part as anything in target.get_bodyparts())
if(part.bodytype & BODYTYPE_ROBOTIC)
silicon_bodytypes += 1
else if(part.bodytype & BODYTYPE_ORGANIC)
diff --git a/code/datums/status_effects/debuffs/rust_corruption.dm b/code/datums/status_effects/debuffs/rust_corruption.dm
index 6692ef111a0..66374898ab7 100644
--- a/code/datums/status_effects/debuffs/rust_corruption.dm
+++ b/code/datums/status_effects/debuffs/rust_corruption.dm
@@ -13,6 +13,6 @@
if(!iscarbon(owner))
return
var/mob/living/carbon/carbon_owner = owner
- for(var/obj/item/bodypart/robotic_limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/robotic_limb as anything in carbon_owner.get_bodyparts())
if(IS_ROBOTIC_LIMB(robotic_limb))
robotic_limb.receive_damage(10)
diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm
index a49c7cb6c34..22a3993fa78 100644
--- a/code/datums/voice_of_god_command.dm
+++ b/code/datums/voice_of_god_command.dm
@@ -205,7 +205,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands())
/datum/voice_of_god_command/bleed/execute(list/listeners, mob/living/user, power_multiplier = 1, message)
for(var/mob/living/carbon/human/target in listeners)
- var/obj/item/bodypart/chosen_part = pick(target.bodyparts)
+ var/obj/item/bodypart/chosen_part = pick(target.get_bodyparts())
chosen_part.adjustBleedStacks(5)
/// This command sets the listeners ablaze.
diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm
index d9f645c30bc..416f4c16fac 100644
--- a/code/game/machinery/computer/operating_computer.dm
+++ b/code/game/machinery/computer/operating_computer.dm
@@ -236,33 +236,14 @@
"mechanic" = operation.operation_flags & OPERATION_MECHANIC,
))
- if(!any_recommended && table?.patient)
- var/obj/item/part = table.patient.get_bodypart(deprecise_zone(target_zone))
- var/just_drapes = FALSE
- if(table.patient.has_limbs)
- if(isnull(part))
- data["surgeries"] += list(list(
- "name" = "Prepare for [/datum/surgery_operation/prosthetic_replacement::name]",
- "desc" = "Prepare the patient's chest for prosthetic limb attachment.",
- "tool_rec" = "operate on chest",
- "show_as_next" = TRUE,
- "show_in_list" = FALSE,
- ))
-
- else if(!HAS_TRAIT(part, TRAIT_READY_TO_OPERATE))
- just_drapes = TRUE
-
- else if(!HAS_TRAIT(table.patient, TRAIT_READY_TO_OPERATE))
- just_drapes = TRUE
-
- if(just_drapes)
- data["surgeries"] += list(list(
- "name" = "Prepare for surgery",
- "desc" = "Begin surgery by applying surgical drapes to the patient.",
- "tool_rec" = /obj/item/surgical_drapes::name,
- "show_as_next" = TRUE,
- "show_in_list" = FALSE,
- ))
+ if(!any_recommended && table?.patient && !HAS_TRAIT(table.patient, TRAIT_READY_TO_OPERATE))
+ data["surgeries"] += list(list(
+ "name" = "Prepare for surgery",
+ "desc" = "Begin surgery by applying surgical drapes to the patient or by buckling the patient to the surgical table.",
+ "tool_rec" = /obj/item/surgical_drapes::name,
+ "show_as_next" = TRUE,
+ "show_in_list" = FALSE,
+ ))
return data
diff --git a/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm
index 16bf78ee396..2284e2afa18 100644
--- a/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/fish_organs.dm
@@ -93,7 +93,7 @@
if (new_value >= FISH_INFUSION_ALL_ORGANS && tail_color)
if (!color_active)
- for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_owner.get_bodyparts())
limb.add_color_override(tail_color, LIMB_COLOR_FISH_INFUSION)
color_active = TRUE
return
@@ -101,7 +101,7 @@
if (!color_active)
return
- for(var/obj/item/bodypart/limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_owner.get_bodyparts())
limb.remove_color_override(LIMB_COLOR_FISH_INFUSION)
color_active = FALSE
diff --git a/code/game/machinery/experimental_cloner/experimental_cloning_record.dm b/code/game/machinery/experimental_cloner/experimental_cloning_record.dm
index 96c1b9bc164..caea82e3677 100644
--- a/code/game/machinery/experimental_cloner/experimental_cloning_record.dm
+++ b/code/game/machinery/experimental_cloner/experimental_cloning_record.dm
@@ -75,7 +75,7 @@
for (var/trauma_type in brain_traumas)
subject.gain_trauma(trauma_type)
- for (var/obj/item/bodypart/limb as anything in subject.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in subject.get_bodyparts())
limb.update_limb(is_creating = TRUE)
subject.updateappearance(mutcolor_update = TRUE)
diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm
index 70849a1198f..0af6c9933a4 100644
--- a/code/game/machinery/harvester.dm
+++ b/code/game/machinery/harvester.dm
@@ -101,7 +101,7 @@
header = "Gruesome!",
)
- operation_order = reverseList(carbon_occupant.bodyparts) //Chest and head are first in bodyparts, so we invert it to make them suffer more
+ operation_order = reverse_range(carbon_occupant.get_bodyparts()) //Chest and head are first in bodyparts, so we invert it to make them suffer more
warming_up = TRUE
harvesting = TRUE
visible_message(span_notice("\The [src] begins warming up!"))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 08ab1724c5e..ec0ff3340cd 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -2217,7 +2217,7 @@
return FALSE
if (!istype(target_limb))
- target_limb = victim.get_bodypart(target_limb) || victim.bodyparts[1]
+ target_limb = victim.get_bodypart(target_limb) || victim.get_bodypart()
return get_embed()?.embed_into(victim, target_limb)
diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm
index e4487f62192..01dfb14d891 100644
--- a/code/game/objects/items/devices/scanners/health_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/health_analyzer.dm
@@ -219,7 +219,7 @@
if(iscarbon(target))
var/mob/living/carbon/carbontarget = target
var/any_damage = brute_loss > 0 || fire_loss > 0 || oxy_loss > 0 || tox_loss > 0 || fire_loss > 0
- var/any_missing = length(carbontarget.bodyparts) < (carbontarget.dna?.species?.max_bodypart_count || 6)
+ var/any_missing = length(carbontarget.get_missing_limbs())
var/any_wounded = length(carbontarget.all_wounds)
var/any_embeds = carbontarget.has_embedded_objects()
if(any_damage || (mode == SCANNER_VERBOSE && (any_missing || any_wounded || any_embeds)))
diff --git a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm
index ab8e3796f22..fe44c1eef41 100644
--- a/code/game/objects/items/stacks/golem_food/golem_status_effects.dm
+++ b/code/game/objects/items/stacks/golem_food/golem_status_effects.dm
@@ -78,7 +78,7 @@
if(isgolem(owner))
var/mob/living/carbon/golem_owner = owner
- for (var/obj/item/bodypart/part in golem_owner.bodyparts)
+ for (var/obj/item/bodypart/part in golem_owner.get_bodyparts())
// these overlays won't look good on anything but golem limbs
if (part.limb_id != SPECIES_GOLEM)
continue
@@ -307,7 +307,7 @@
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/light_speed)
var/mob/living/carbon/carbon_owner = owner
- for (var/obj/item/bodypart/arm/arm in carbon_owner.bodyparts)
+ for (var/obj/item/bodypart/arm/arm in carbon_owner.get_bodyparts())
set_arm_fluff(arm)
return TRUE
@@ -388,7 +388,7 @@
var/mob/living/carbon/human/human_owner = owner
RegisterSignal(human_owner, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_punched))
human_owner.physiology.brute_mod *= brute_modifier
- for (var/obj/item/bodypart/arm/arm in human_owner.bodyparts)
+ for (var/obj/item/bodypart/arm/arm in human_owner.get_bodyparts())
buff_arm(arm)
/// Give mining mobs an extra slap
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index d244efb3ad4..de4020bc85d 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -230,7 +230,7 @@
PRIVATE_PROC(TRUE)
var/list/other_affected_limbs = list()
- for(var/obj/item/bodypart/limb as anything in patient.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in patient.get_bodyparts())
if(!try_heal_checks(patient, user, limb.body_zone, silent = TRUE))
continue
other_affected_limbs += limb.body_zone
@@ -774,7 +774,7 @@
return BRUTELOSS
patient.emote("scream")
- for(var/obj/item/bodypart/bone as anything in patient.bodyparts)
+ for(var/obj/item/bodypart/bone as anything in patient.get_bodyparts())
// fine to just, use these raw, its a meme anyway
var/datum/wound/blunt/bone/severe/oof_ouch = new
oof_ouch.apply_wound(bone, wound_source = "bone gel")
diff --git a/code/game/objects/items/weaponry/melee/sabre.dm b/code/game/objects/items/weaponry/melee/sabre.dm
index 770f5b53a9c..0cc90020800 100644
--- a/code/game/objects/items/weaponry/melee/sabre.dm
+++ b/code/game/objects/items/weaponry/melee/sabre.dm
@@ -81,7 +81,7 @@
var/list/legs = list()
var/obj/item/bodypart/bodypart
- for(bodypart in Cuser.bodyparts)
+ for(bodypart in Cuser.get_bodyparts())
if(bodypart == holding_bodypart)
continue
if(bodypart.body_part & ARMS)
diff --git a/code/game/objects/items/wiki_manuals.dm b/code/game/objects/items/wiki_manuals.dm
index 5c0c0802464..56efbd0669a 100644
--- a/code/game/objects/items/wiki_manuals.dm
+++ b/code/game/objects/items/wiki_manuals.dm
@@ -213,7 +213,7 @@
var/obj/item/bodypart/head = H.get_bodypart(BODY_ZONE_HEAD)
if(head)
ADD_TRAIT(head, TRAIT_DISFIGURED, TRAIT_GENERIC)
- for(var/obj/item/bodypart/part as anything in H.bodyparts)
+ for(var/obj/item/bodypart/part as anything in H.get_bodyparts())
part.adjustBleedStacks(5)
H.gib_animation()
sleep(0.3 SECONDS)
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index d530d00a00f..a931748a577 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -437,7 +437,7 @@
var/list/immune_parts = list() // Parts we can't transform because they're not organic or can't be dismembered
var/list/transform_parts = list() // Parts we want to transform
- for(var/obj/item/bodypart/burn_limb as anything in burn_human.bodyparts)
+ for(var/obj/item/bodypart/burn_limb as anything in burn_human.get_bodyparts())
if(!IS_ORGANIC_LIMB(burn_limb) || !burn_limb.can_dismember())
immune_parts += burn_limb
continue
diff --git a/code/modules/admin/smites/berforate.dm b/code/modules/admin/smites/berforate.dm
index 6b5fffa38e6..8bd027eb8bc 100644
--- a/code/modules/admin/smites/berforate.dm
+++ b/code/modules/admin/smites/berforate.dm
@@ -41,7 +41,7 @@
dude.Immobilize(5 SECONDS)
for (var/wound_bonus_rep in 1 to repetitions)
- for (var/_limb in dude.bodyparts)
+ for (var/_limb in dude.get_bodyparts())
var/obj/item/bodypart/limb = _limb
var/shots_this_limb = 0
for (var/_iter_turf in shuffle(open_adj_turfs))
diff --git a/code/modules/admin/smites/bloodless.dm b/code/modules/admin/smites/bloodless.dm
index c970e920f22..df43ed2048a 100644
--- a/code/modules/admin/smites/bloodless.dm
+++ b/code/modules/admin/smites/bloodless.dm
@@ -8,7 +8,7 @@
to_chat(user, span_warning("This must be used on a carbon mob."), confidential = TRUE)
return
var/mob/living/carbon/carbon_target = target
- for(var/_limb in carbon_target.bodyparts)
+ for(var/_limb in carbon_target.get_bodyparts())
var/obj/item/bodypart/limb = _limb // fine to use this raw, its a meme smite
var/type_wound = pick(list(/datum/wound/slash/flesh/severe, /datum/wound/slash/flesh/moderate))
limb.force_wound_upwards(type_wound, smited = TRUE)
diff --git a/code/modules/admin/smites/boneless.dm b/code/modules/admin/smites/boneless.dm
index 3fd1a1121f4..5dd2afd6ef2 100644
--- a/code/modules/admin/smites/boneless.dm
+++ b/code/modules/admin/smites/boneless.dm
@@ -10,7 +10,7 @@
return
var/mob/living/carbon/carbon_target = target
- for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_target.get_bodyparts())
var/severity = pick_weight(alist(
WOUND_SEVERITY_MODERATE = 1,
WOUND_SEVERITY_SEVERE = 2,
diff --git a/code/modules/admin/smites/nugget.dm b/code/modules/admin/smites/nugget.dm
index 18e5254e615..9efde93dfee 100644
--- a/code/modules/admin/smites/nugget.dm
+++ b/code/modules/admin/smites/nugget.dm
@@ -11,7 +11,7 @@
var/mob/living/carbon/carbon_target = target
var/timer = 2 SECONDS
- for (var/_limb in carbon_target.bodyparts)
+ for (var/_limb in carbon_target.get_bodyparts())
var/obj/item/bodypart/limb = _limb
if (limb.body_part == HEAD || limb.body_part == CHEST)
continue
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 380eea90b96..fdbfc81b23c 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -99,7 +99,7 @@
// If we have a team skincolor, apply it here. Applied by admins or 2% chance of natural occurance
if(!isnull(team.team_skincolor))
- for(var/obj/item/bodypart/part as anything in new_abductor.bodyparts)
+ for(var/obj/item/bodypart/part as anything in new_abductor.get_bodyparts())
part.should_draw_greyscale = TRUE
part.add_color_override(team.team_skincolor, LIMB_COLOR_AYYLMAO)
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index b841ec26626..53abe0952e4 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -801,7 +801,7 @@
chosen_dna.copy_dna(user.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
- for(var/obj/item/bodypart/limb as anything in user.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in user.get_bodyparts())
limb.update_limb(is_creating = TRUE)
user.updateappearance(mutcolor_update = TRUE)
diff --git a/code/modules/antagonists/changeling/powers/defib_grasp.dm b/code/modules/antagonists/changeling/powers/defib_grasp.dm
index 38c14efdfe7..5d63b5b2e05 100644
--- a/code/modules/antagonists/changeling/powers/defib_grasp.dm
+++ b/code/modules/antagonists/changeling/powers/defib_grasp.dm
@@ -63,7 +63,7 @@
if(iscarbon(defibber))
var/removed_arms = 0
var/mob/living/carbon/carbon_defibber = defibber
- for(var/obj/item/bodypart/arm/limb in carbon_defibber.bodyparts)
+ for(var/obj/item/bodypart/arm/limb in carbon_defibber.get_bodyparts())
if(limb.dismember(silent = FALSE))
removed_arms++
qdel(limb)
diff --git a/code/modules/antagonists/cult/cult_armor.dm b/code/modules/antagonists/cult/cult_armor.dm
index d4a62d5fd54..36ede426e69 100644
--- a/code/modules/antagonists/cult/cult_armor.dm
+++ b/code/modules/antagonists/cult/cult_armor.dm
@@ -151,7 +151,7 @@
return
if(!SPT_PROB(15, seconds_per_tick))
return
- var/obj/item/bodypart/bone_to_wound = pick(wearer.bodyparts)
+ var/obj/item/bodypart/bone_to_wound = pick(wearer.get_bodyparts())
var/wound_type = pick(list(
/datum/wound/blunt/bone/moderate,
/datum/wound/pierce/bleed/moderate,
diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm
index 71f79a51cbd..ad7478fc6fd 100644
--- a/code/modules/antagonists/heretic/influences.dm
+++ b/code/modules/antagonists/heretic/influences.dm
@@ -141,7 +141,7 @@
// A very elaborate way to suicide
visible_message(span_userdanger("Psychic tendrils lash out from [src], psychically grabbing onto [user]'s psychically sensitive mind and tearing [user.p_their()] head off!"))
- var/obj/item/bodypart/head/head = locate() in human_user.bodyparts
+ var/obj/item/bodypart/head/head = human_user.get_bodypart(BODY_ZONE_HEAD)
if(head?.dismember())
head.forceMove(src) // stored for later fishage
else
diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm
index 4d0dffa781c..8e496353fae 100644
--- a/code/modules/antagonists/heretic/items/heretic_armor.dm
+++ b/code/modules/antagonists/heretic/items/heretic_armor.dm
@@ -142,7 +142,7 @@
return
var/mob/living/carbon/victim = user
var/iteration = 0
- for(var/obj/item/bodypart/limb as anything in victim.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in victim.get_bodyparts())
if(istype(limb, /obj/item/bodypart/head) || istype(limb, /obj/item/bodypart/chest))
continue
iteration++
@@ -259,7 +259,7 @@
if(!length(valid_turfs))
var/mob/living/carbon/carbon_target = target
if(iscarbon(target))
- var/obj/item/bodypart/limb = pick(carbon_target.bodyparts)
+ var/obj/item/bodypart/limb = pick(carbon_target.get_bodyparts())
limb.force_wound_upwards(/datum/wound/slash/flesh/severe)
return
throw_blade(pick(valid_turfs), target)
@@ -451,7 +451,7 @@
return
var/mob/living/carbon/victim = user
var/iteration = 0
- for(var/obj/item/bodypart/limb as anything in victim.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in victim.get_bodyparts())
iteration++
addtimer(CALLBACK(limb, TYPE_PROC_REF(/obj/item/bodypart, force_wound_upwards), /datum/wound/slash/flesh/critical), 1 SECONDS * iteration)
diff --git a/code/modules/antagonists/heretic/items/heretic_grenade.dm b/code/modules/antagonists/heretic/items/heretic_grenade.dm
index 14ceaf1183e..3a5e0e2a129 100644
--- a/code/modules/antagonists/heretic/items/heretic_grenade.dm
+++ b/code/modules/antagonists/heretic/items/heretic_grenade.dm
@@ -95,7 +95,7 @@
addtimer(CALLBACK(victim, TYPE_PROC_REF(/mob, remove_movespeed_modifier), /datum/movespeed_modifier/reagent/pepperspray), 10 SECONDS)
victim.update_damage_hud()
victim.adjust_disgust(5)
- for(var/obj/item/bodypart/robotic_limb in victim.bodyparts)
+ for(var/obj/item/bodypart/robotic_limb in victim.get_bodyparts())
if(robotic_limb.biological_state & BIO_ROBOTIC)
robotic_limb.receive_damage(5, 5)
if(methods & INGEST)
diff --git a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
index cb2ac3d3bde..f5282015b0a 100644
--- a/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/flesh_lore.dm
@@ -267,7 +267,7 @@
return
var/mob/living/carbon/carbon_target = target
- var/obj/item/bodypart/bodypart = pick(carbon_target.bodyparts)
+ var/obj/item/bodypart/bodypart = pick(carbon_target.get_bodyparts())
var/datum/wound/crit_wound = new wound_type()
crit_wound.apply_wound(bodypart, attack_direction = get_dir(source, target))
diff --git a/code/modules/antagonists/heretic/knowledge/moon_lore.dm b/code/modules/antagonists/heretic/knowledge/moon_lore.dm
index f3a9a9da712..eb6428aee27 100644
--- a/code/modules/antagonists/heretic/knowledge/moon_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/moon_lore.dm
@@ -300,7 +300,7 @@
to_chat(carbon_view, span_boldbig(span_red(\
"YOUR SENSES REEL AS YOUR MIND IS ENVELOPED BY AN OTHERWORLDLY FORCE ATTEMPTING TO REWRITE YOUR VERY BEING. \
YOU CANNOT EVEN BEGIN TO SCREAM BEFORE YOUR IMPLANT ACTIVATES ITS PSIONIC FAIL-SAFE PROTOCOL, TAKING YOUR HEAD WITH IT.")))
- var/obj/item/bodypart/head/head = locate() in carbon_view.bodyparts
+ var/obj/item/bodypart/head/head = carbon_view.get_bodypart(BODY_ZONE_HEAD)
if(!head?.dismember())
carbon_view.gib(DROP_ALL_REMAINS)
var/datum/effect_system/reagents_explosion/explosion = new(get_turf(carbon_view), 1, 1, 1)
diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm
index 207669735e0..565879a7c8c 100644
--- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm
@@ -81,7 +81,7 @@
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
- for(var/obj/item/bodypart/robotic_limb as anything in carbon_target.bodyparts)
+ for(var/obj/item/bodypart/robotic_limb as anything in carbon_target.get_bodyparts())
if(IS_ROBOTIC_LIMB(robotic_limb))
robotic_limb.receive_damage(500)
diff --git a/code/modules/antagonists/heretic/knowledge/side_knowledge/tier_two.dm b/code/modules/antagonists/heretic/knowledge/side_knowledge/tier_two.dm
index cac879740de..5d155281e5e 100644
--- a/code/modules/antagonists/heretic/knowledge/side_knowledge/tier_two.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_knowledge/tier_two.dm
@@ -29,10 +29,10 @@
/datum/heretic_knowledge/codex_morbus/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
. = ..()
var/mob/living/carbon/human/to_fuck_up = locate() in selected_atoms
- for(var/_limb in to_fuck_up.bodyparts)
+ for(var/_limb in to_fuck_up.get_bodyparts())
var/obj/item/bodypart/limb = _limb
limb.force_wound_upwards(/datum/wound/slash/flesh/critical)
- for(var/obj/item/bodypart/limb as anything in to_fuck_up.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in to_fuck_up.get_bodyparts())
to_fuck_up.cause_wound_of_type_and_severity(WOUND_BLUNT, limb, WOUND_SEVERITY_CRITICAL)
return TRUE
diff --git a/code/modules/antagonists/heretic/knowledge/starting_lore.dm b/code/modules/antagonists/heretic/knowledge/starting_lore.dm
index 830e6edae32..6647ee086bc 100644
--- a/code/modules/antagonists/heretic/knowledge/starting_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/starting_lore.dm
@@ -257,7 +257,7 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge())
// If it is, we will damage a random bodypart, and check that bodypart for its body type, to select between 'skin' or 'exterior'.
if(iscarbon(body))
var/mob/living/carbon/carbody = body
- var/obj/item/bodypart/bodypart = pick(carbody.bodyparts)
+ var/obj/item/bodypart/bodypart = pick(carbody.get_bodyparts())
ripped_thing = bodypart
carbody.apply_damage(25, BRUTE, bodypart, sharpness = SHARP_EDGED)
diff --git a/code/modules/antagonists/heretic/magic/apetravulnera.dm b/code/modules/antagonists/heretic/magic/apetravulnera.dm
index c0398b2b745..b878fd36bed 100644
--- a/code/modules/antagonists/heretic/magic/apetravulnera.dm
+++ b/code/modules/antagonists/heretic/magic/apetravulnera.dm
@@ -38,7 +38,7 @@
return FALSE
var/a_limb_got_damaged = FALSE
- for(var/obj/item/bodypart/bodypart in cast_on.bodyparts)
+ for(var/obj/item/bodypart/bodypart in cast_on.get_bodyparts())
if(bodypart.brute_dam < 15)
continue
a_limb_got_damaged = TRUE
@@ -47,7 +47,7 @@
if(!a_limb_got_damaged)
var/datum/wound/slash/crit_wound = new wound_type()
- crit_wound.apply_wound(pick(cast_on.bodyparts))
+ crit_wound.apply_wound(pick(cast_on.get_bodyparts()))
cast_on.visible_message(
span_danger("[cast_on]'s scratches and bruises are torn open by an unholy force!"),
diff --git a/code/modules/antagonists/heretic/magic/blood_cleave.dm b/code/modules/antagonists/heretic/magic/blood_cleave.dm
index 065286f490e..e0c9454ba33 100644
--- a/code/modules/antagonists/heretic/magic/blood_cleave.dm
+++ b/code/modules/antagonists/heretic/magic/blood_cleave.dm
@@ -44,7 +44,7 @@
span_danger("Your veins burst from within and unholy flame erupts from your blood!")
)
- var/obj/item/bodypart/bodypart = pick(victim.bodyparts)
+ var/obj/item/bodypart/bodypart = pick(victim.get_bodyparts())
var/datum/wound/slash/flesh/crit_wound = new wound_type()
crit_wound.apply_wound(bodypart)
victim.apply_damage(20, BURN, wound_bonus = CANT_WOUND)
diff --git a/code/modules/antagonists/heretic/magic/blood_siphon.dm b/code/modules/antagonists/heretic/magic/blood_siphon.dm
index cb0b4ec355c..3ef5a7920f8 100644
--- a/code/modules/antagonists/heretic/magic/blood_siphon.dm
+++ b/code/modules/antagonists/heretic/magic/blood_siphon.dm
@@ -50,11 +50,11 @@
var/mob/living/carbon/carbon_target = cast_on
var/mob/living/carbon/carbon_user = owner
- for(var/obj/item/bodypart/bodypart as anything in carbon_user.bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in carbon_user.get_bodyparts())
for(var/datum/wound/iter_wound as anything in bodypart.wounds)
if(prob(50))
continue
- var/obj/item/bodypart/target_bodypart = locate(bodypart.type) in carbon_target.bodyparts
+ var/obj/item/bodypart/target_bodypart = carbon_target.get_bodypart(bodypart.body_zone)
if(!target_bodypart)
continue
iter_wound.remove_wound()
diff --git a/code/modules/antagonists/heretic/magic/crimson_cleave.dm b/code/modules/antagonists/heretic/magic/crimson_cleave.dm
index b64a5221a50..6ee02e2fea9 100644
--- a/code/modules/antagonists/heretic/magic/crimson_cleave.dm
+++ b/code/modules/antagonists/heretic/magic/crimson_cleave.dm
@@ -32,7 +32,7 @@
. = ..()
if(iscarbon(owner))
var/mob/living/carbon/carbon_owner = owner
- for(var/obj/item/bodypart/limbs as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/limbs as anything in carbon_owner.get_bodyparts())
for(var/datum/wound/iter_wound as anything in limbs.wounds)
iter_wound.remove_wound()
diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm
index f3660e2f813..e4802049433 100644
--- a/code/modules/antagonists/heretic/status_effects/buffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/buffs.dm
@@ -87,7 +87,7 @@
if(!iscarbon(owner))
return
var/mob/living/carbon/drinker = owner
- for(var/obj/item/bodypart/potentially_wounded as anything in drinker.bodyparts)
+ for(var/obj/item/bodypart/potentially_wounded as anything in drinker.get_bodyparts())
for(var/datum/wound/found_wound as anything in potentially_wounded.wounds)
found_wound.remove_wound()
if(length(drinker.get_missing_limbs()))
@@ -102,7 +102,7 @@
carbie.adjust_brute_loss(-0.5 * seconds_between_ticks, updating_health = FALSE)
carbie.adjust_fire_loss(-0.5 * seconds_between_ticks, updating_health = FALSE)
- for(var/BP in carbie.bodyparts)
+ for(var/BP in carbie.get_bodyparts())
var/obj/item/bodypart/part = BP
for(var/W in part.wounds)
var/datum/wound/wound = W
diff --git a/code/modules/antagonists/heretic/status_effects/heretic_passive.dm b/code/modules/antagonists/heretic/status_effects/heretic_passive.dm
index 6f5786b809b..08d2292d677 100644
--- a/code/modules/antagonists/heretic/status_effects/heretic_passive.dm
+++ b/code/modules/antagonists/heretic/status_effects/heretic_passive.dm
@@ -307,7 +307,7 @@
if(!iscarbon(owner))
return
var/mob/living/carbon/carbon_eater = owner
- for(var/obj/item/bodypart/wounded_limb as anything in carbon_eater.bodyparts)
+ for(var/obj/item/bodypart/wounded_limb as anything in carbon_eater.get_bodyparts())
for(var/datum/wound/to_cure as anything in wounded_limb.wounds)
to_cure.remove_wound()
break
@@ -543,7 +543,7 @@
var/mob/living/carbon/carbon_owner = source
if(passive_level < HERETIC_LEVEL_UPGRADE)
return
- for(var/obj/item/bodypart/wounded_limb as anything in carbon_owner.bodyparts)
+ for(var/obj/item/bodypart/wounded_limb as anything in carbon_owner.get_bodyparts())
for(var/datum/wound/to_cure as anything in wounded_limb.wounds)
to_cure.remove_wound()
for(var/obj/item/organ/internal as anything in carbon_owner.organs)
diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
index 465ad530d24..18b35b2eedc 100644
--- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm
+++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
@@ -64,7 +64,7 @@
/datum/status_effect/eldritch/flesh/on_effect()
if(ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
- var/obj/item/bodypart/bodypart = pick(human_owner.bodyparts)
+ var/obj/item/bodypart/bodypart = pick(human_owner.get_bodyparts())
human_owner.cause_wound_of_type_and_severity(WOUND_SLASH, bodypart, WOUND_SEVERITY_SEVERE)
return ..()
diff --git a/code/modules/antagonists/spy/spy_bounty.dm b/code/modules/antagonists/spy/spy_bounty.dm
index d58fd398d7a..a1020c3c93e 100644
--- a/code/modules/antagonists/spy/spy_bounty.dm
+++ b/code/modules/antagonists/spy/spy_bounty.dm
@@ -663,7 +663,7 @@
/datum/spy_bounty/targets_person/some_item/limb_or_organ/find_desired_thing(mob/living/carbon/human/crewmember)
if(ispath(desired_type, /obj/item/bodypart))
- return locate(desired_type) in crewmember.bodyparts
+ return locate(desired_type) in crewmember.get_bodyparts()
if(ispath(desired_type, /obj/item/organ))
return locate(desired_type) in crewmember.organs
return null
diff --git a/code/modules/antagonists/voidwalker/voidwalker_traumas.dm b/code/modules/antagonists/voidwalker/voidwalker_traumas.dm
index 3deab1fd0d6..c6c2f3f2340 100644
--- a/code/modules/antagonists/voidwalker/voidwalker_traumas.dm
+++ b/code/modules/antagonists/voidwalker/voidwalker_traumas.dm
@@ -45,7 +45,7 @@
RegisterSignal(owner, COMSIG_CARBON_ATTACH_LIMB, PROC_REF(texture_limb)) //also catch new limbs being attached
RegisterSignal(owner, COMSIG_CARBON_REMOVE_LIMB, PROC_REF(untexture_limb)) //and remove it from limbs if they go away
- for(var/obj/item/bodypart as anything in owner.bodyparts)
+ for(var/obj/item/bodypart as anything in owner.get_bodyparts())
texture_limb(owner, bodypart)
if(ishuman(owner))
@@ -75,7 +75,7 @@
var/mob/living/carbon/human/human = owner
human.physiology.brute_mod /= brute_mod
- for(var/obj/item/bodypart/bodypart as anything in owner.bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in owner.get_bodyparts())
untexture_limb(owner, bodypart)
owner.update_body()
diff --git a/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm b/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm
index a9047c79878..40f271a30f4 100644
--- a/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm
+++ b/code/modules/antagonists/wizard/grand_ritual/finales/immortality.dm
@@ -124,7 +124,7 @@
target_quirk.add_to_holder(target)
dna.copy_dna(target.dna, COPY_DNA_SE|COPY_DNA_SPECIES)
- for(var/obj/item/bodypart/limb as anything in target.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in target.get_bodyparts())
limb.update_limb(is_creating = TRUE)
target.updateappearance(mutcolor_update = TRUE)
target.domutcheck()
diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm
index c1829cb21cf..6d237f67f8d 100644
--- a/code/modules/cargo/supplypod.dm
+++ b/code/modules/cargo/supplypod.dm
@@ -329,7 +329,7 @@
if (iscarbon(target_living)) //If effectLimb is true (which means we pop limbs off when we hit people):
if (effectLimb)
var/mob/living/carbon/carbon_target_mob = target_living
- for (var/bp in carbon_target_mob.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
+ for (var/bp in carbon_target_mob.get_bodyparts()) //Look at the bodyparts in our poor mob beneath our pod as it lands
var/obj/item/bodypart/bodypart = bp
if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson!
if(bodypart.dismember()) //Using the power of flextape i've sawed this man's limb in half!
@@ -342,7 +342,7 @@
organ_to_yeet.forceMove(turf_underneath) //Move the organ outta the body
organ_to_yeet.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away
sleep(0.1 SECONDS)
- for (var/bp in carbon_target_mob.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
+ for (var/bp in carbon_target_mob.get_bodyparts()) //Look at the bodyparts in our poor mob beneath our pod as it lands
var/obj/item/bodypart/bodypart = bp
var/destination = get_edge_target_turf(turf_underneath, pick(GLOB.alldirs))
if (bodypart.dismember()) //Using the power of flextape i've sawed this man's bodypart in half!
diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm
index 10236d9e415..849d1a21114 100644
--- a/code/modules/client/preferences/species_features/lizard.dm
+++ b/code/modules/client/preferences/species_features/lizard.dm
@@ -94,7 +94,7 @@
correct_legs[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade
correct_legs[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade
- for(var/obj/item/bodypart/old_part as anything in target.bodyparts)
+ for(var/obj/item/bodypart/old_part as anything in target.get_bodyparts())
if(old_part.change_exempt_flags & BP_BLOCK_CHANGE_SPECIES)
continue
diff --git a/code/modules/experisci/experiment/experiments.dm b/code/modules/experisci/experiment/experiments.dm
index 8f658884830..271322b1a49 100644
--- a/code/modules/experisci/experiment/experiments.dm
+++ b/code/modules/experisci/experiment/experiments.dm
@@ -452,7 +452,7 @@
return
if (isandroid(check))
return TRUE
- if (length(check.organs) < 6 || length(check.bodyparts) < 6)
+ if (length(check.organs) < 6 || length(check.get_missing_limbs()) > 1)
return FALSE
var/static/list/augmented_organ_slots = list(
@@ -468,7 +468,7 @@
continue
if (!IS_ROBOTIC_ORGAN(organ))
return FALSE
- for (var/obj/item/bodypart/bodypart as anything in check.bodyparts)
+ for (var/obj/item/bodypart/bodypart as anything in check.get_bodyparts())
if (!IS_ROBOTIC_LIMB(bodypart))
return FALSE
return TRUE
diff --git a/code/modules/fishing/fish/types/holographic.dm b/code/modules/fishing/fish/types/holographic.dm
index a4a10857d46..ae4f550ab85 100644
--- a/code/modules/fishing/fish/types/holographic.dm
+++ b/code/modules/fishing/fish/types/holographic.dm
@@ -115,7 +115,7 @@
if(!iscarbon(user))
return ..()
- for(var/obj/item/bodypart/limb in user.bodyparts)
+ for(var/obj/item/bodypart/limb in user.get_bodyparts())
limb.add_color_override(COLOR_WHITE, LIMB_COLOR_CS_SOURCE_SUICIDE)
limb.add_bodypart_overlay(new /datum/bodypart_overlay/texture/checkered(), update = FALSE)
diff --git a/code/modules/fishing/fish/types/ruins.dm b/code/modules/fishing/fish/types/ruins.dm
index 8654d45538f..db02dcd7130 100644
--- a/code/modules/fishing/fish/types/ruins.dm
+++ b/code/modules/fishing/fish/types/ruins.dm
@@ -167,7 +167,7 @@
return SHAME
var/skin_tone
- for(var/obj/item/bodypart/to_wound as anything in user.bodyparts)
+ for(var/obj/item/bodypart/to_wound as anything in user.get_bodyparts())
if(to_wound == user.get_bodypart(BODY_ZONE_CHEST))
skin_tone = to_wound.species_color || skintone2hex(to_wound.skin_tone)
user.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_CRITICAL, WOUND_SEVERITY_CRITICAL)
diff --git a/code/modules/food_and_drinks/machinery/gibber.dm b/code/modules/food_and_drinks/machinery/gibber.dm
index 3422eee9944..0c661867370 100644
--- a/code/modules/food_and_drinks/machinery/gibber.dm
+++ b/code/modules/food_and_drinks/machinery/gibber.dm
@@ -234,7 +234,7 @@
var/mob/living/carbon/human/agent_whiskey = victim
var/drop_chance = 0
- for (var/obj/item/bodypart/limb as anything in agent_whiskey.bodyparts)
+ for (var/obj/item/bodypart/limb as anything in agent_whiskey.get_bodyparts())
if (!limb.butcher_drops)
continue
diff --git a/code/modules/hallucination/blood_flow.dm b/code/modules/hallucination/blood_flow.dm
index 7805768c252..71dbb5c8acf 100644
--- a/code/modules/hallucination/blood_flow.dm
+++ b/code/modules/hallucination/blood_flow.dm
@@ -11,11 +11,11 @@
return FALSE
var/mob/living/carbon/carb_hallucinator = hallucinator
- if(!length(carb_hallucinator.bodyparts) || !carb_hallucinator.can_bleed())
+ var/list/bodyparts = carb_hallucinator.get_bodyparts()
+ if(!length(bodyparts) || !carb_hallucinator.can_bleed())
return FALSE
var/obj/item/bodypart/picked
- var/list/bodyparts = carb_hallucinator.bodyparts.Copy()
while(isnull(picked) && length(bodyparts))
picked = pick_n_take(bodyparts)
if(!picked.can_bleed())
diff --git a/code/modules/hallucination/screwy_health_doll.dm b/code/modules/hallucination/screwy_health_doll.dm
index 35f7356b4d4..2ab8a8c928a 100644
--- a/code/modules/hallucination/screwy_health_doll.dm
+++ b/code/modules/hallucination/screwy_health_doll.dm
@@ -50,7 +50,7 @@
/datum/hallucination/fake_health_doll/proc/add_fake_limb(obj/item/bodypart/specific_limb, severity)
var/mob/living/carbon/human/human_mob = hallucinator
- var/obj/item/bodypart/picked = specific_limb || pick(human_mob.bodyparts)
+ var/obj/item/bodypart/picked = specific_limb || pick(human_mob.get_bodyparts())
if(!(picked in bodyparts))
RegisterSignals(picked, list(COMSIG_QDELETING, COMSIG_BODYPART_REMOVED), PROC_REF(remove_bodypart))
RegisterSignal(picked, COMSIG_BODYPART_UPDATING_HEALTH_HUD, PROC_REF(on_bodypart_hud_update))
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 936028f86f0..899224b33f3 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -49,7 +49,7 @@
if(!ishuman(spawned) || !prob(PIG_COP_PROBABILITY))
return
var/mob/living/carbon/human/piggy = spawned
- for (var/obj/item/bodypart/ham as anything in piggy.bodyparts)
+ for (var/obj/item/bodypart/ham as anything in piggy.get_bodyparts())
// These are string lists
ham.butcher_drops = ham.butcher_drops.Copy()
for (var/meat_type in ham.butcher_drops)
diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm
index 8c55dfcdce0..99b3eab2155 100644
--- a/code/modules/jobs/job_types/prisoner.dm
+++ b/code/modules/jobs/job_types/prisoner.dm
@@ -73,7 +73,7 @@
var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name]
if (isnull(crime))
return
- var/list/limbs_to_tat = new_prisoner.bodyparts.Copy()
+ var/list/limbs_to_tat = new_prisoner.get_bodyparts()
for(var/i in 1 to crime.tattoos)
if(!length(SSpersistence.prison_tattoos_to_use) || visuals_only)
return
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 06c78c25f1c..d78fb4f94b0 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -62,7 +62,7 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
if(!ishuman(spawned) || !prob(PIG_COP_PROBABILITY))
return
var/mob/living/carbon/human/piggy = spawned
- for (var/obj/item/bodypart/ham as anything in piggy.bodyparts)
+ for (var/obj/item/bodypart/ham as anything in piggy.get_bodyparts())
// These are string lists
ham.butcher_drops = ham.butcher_drops.Copy()
for (var/meat_type in ham.butcher_drops)
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index bcc07dfd2d6..eea6d428c10 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -47,7 +47,7 @@
if(!ishuman(spawned) || !prob(PIG_COP_PROBABILITY))
return
var/mob/living/carbon/human/piggy = spawned
- for (var/obj/item/bodypart/ham as anything in piggy.bodyparts)
+ for (var/obj/item/bodypart/ham as anything in piggy.get_bodyparts())
// These are string lists
ham.butcher_drops = ham.butcher_drops.Copy()
for (var/meat_type in ham.butcher_drops)
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 950f2c70a5c..07a83912f00 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -215,7 +215,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
return BLESSING_FAILED
var/mob/living/carbon/human/built_in_his_image = blessed
- for(var/obj/item/bodypart/bodypart as anything in built_in_his_image.bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in built_in_his_image.get_bodyparts())
if(!IS_ORGANIC_LIMB(bodypart))
balloon_alert(user, "can't heal inorganic!")
return BLESSING_IGNORED
diff --git a/code/modules/lost_crew/damages/post_mortem.dm b/code/modules/lost_crew/damages/post_mortem.dm
index 5eeaabc3302..0e70b0cad62 100644
--- a/code/modules/lost_crew/damages/post_mortem.dm
+++ b/code/modules/lost_crew/damages/post_mortem.dm
@@ -36,7 +36,11 @@
/datum/corpse_damage/post_mortem/limb_loss/apply_to_body(mob/living/carbon/human/body, severity, list/saved_movables, list/datum/callback/on_revive_and_player_occupancy)
var/limbs_to_take = round(min_limbs + (max_limbs - min_limbs) * severity)
- var/list/limbs_we_can_take = body.bodyparts - body.get_bodypart(BODY_ZONE_HEAD) - body.get_bodypart(BODY_ZONE_CHEST)
+ var/list/limbs_we_can_take = list()
+ for(var/zone in GLOB.limb_zones)
+ var/bodypart = body.get_bodypart(zone)
+ if(bodypart)
+ limbs_we_can_take += bodypart
if(!limbs_we_can_take.len)
return
diff --git a/code/modules/lost_crew/lost_crew_manager.dm b/code/modules/lost_crew/lost_crew_manager.dm
index 1494204ad71..08d6d724681 100644
--- a/code/modules/lost_crew/lost_crew_manager.dm
+++ b/code/modules/lost_crew/lost_crew_manager.dm
@@ -36,9 +36,12 @@ GLOBAL_DATUM_INIT(lost_crew_manager, /datum/lost_crew_manager, new)
var/datum/corpse_damage_class/scenario = forced_class || pick_weight(scenarios)
scenario = new scenario ()
+ new_body.living_flags |= STOP_OVERLAY_UPDATE_BODY_PARTS
scenario.apply_character(new_body, protected_items, recovered_items, on_revive_and_player_occupancy, body_data)
scenario.apply_injuries(new_body, recovered_items, on_revive_and_player_occupancy, body_data)
scenario.death_lore += "I should get a formalized assignment!"
+ new_body.living_flags &= ~STOP_OVERLAY_UPDATE_BODY_PARTS
+ new_body.update_body_parts()
. = new_body
// so bodies can also be used for runes, morgue, etc
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index c3d55e7167b..4c57ced89bb 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -677,6 +677,7 @@
if(hud_used)
hud_used.build_hand_slots()
+ hud_used.healthdoll.update_body_zones()
//GetAllContents that is reasonable and not stupid
/mob/living/proc/get_all_gear(equipment_flags = INCLUDE_ACCESSORIES|INCLUDE_PROSTHETICS, recursive = TRUE)
diff --git a/code/modules/mob/living/basic/cult/constructs/harvester.dm b/code/modules/mob/living/basic/cult/constructs/harvester.dm
index 8fc1226ab09..1c36453b184 100644
--- a/code/modules/mob/living/basic/cult/constructs/harvester.dm
+++ b/code/modules/mob/living/basic/cult/constructs/harvester.dm
@@ -46,7 +46,7 @@
return ..()
var/mob/living/carbon/carbon_target = attack_target
- for(var/obj/item/bodypart/limb as anything in carbon_target.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in carbon_target.get_bodyparts())
if(limb.body_part == HEAD || limb.body_part == CHEST)
continue
return ..() //if any arms or legs exist, attack
diff --git a/code/modules/mob/living/basic/farm_animals/goat/_goat.dm b/code/modules/mob/living/basic/farm_animals/goat/_goat.dm
index 583542ff5ce..0f94efaf7fb 100644
--- a/code/modules/mob/living/basic/farm_animals/goat/_goat.dm
+++ b/code/modules/mob/living/basic/farm_animals/goat/_goat.dm
@@ -79,7 +79,7 @@
if(ishuman(living_target))
var/mob/living/carbon/human/plant_man = target
- edible_bodypart = pick(plant_man.bodyparts)
+ edible_bodypart = pick(plant_man.get_bodyparts())
edible_bodypart.dismember()
living_target.visible_message(
diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm
index 5d607c2c1a4..94bb50f026d 100644
--- a/code/modules/mob/living/basic/ruin_defender/flesh.dm
+++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm
@@ -114,7 +114,7 @@
return
var/list/zone_candidates = target.get_missing_limbs()
- for(var/obj/item/bodypart/bodypart in target.bodyparts)
+ for(var/obj/item/bodypart/bodypart in target.get_bodyparts())
if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
continue
if(HAS_TRAIT(bodypart, TRAIT_IGNORED_BY_LIVING_FLESH))
diff --git a/code/modules/mob/living/basic/space_fauna/lightgeist.dm b/code/modules/mob/living/basic/space_fauna/lightgeist.dm
index f59c5070bff..36ae135619c 100644
--- a/code/modules/mob/living/basic/space_fauna/lightgeist.dm
+++ b/code/modules/mob/living/basic/space_fauna/lightgeist.dm
@@ -103,7 +103,7 @@
if (!iscarbon(target))
return target.get_brute_loss() > 0 || target.get_fire_loss() > 0
var/mob/living/carbon/carbon_target = target
- for (var/obj/item/bodypart/part in carbon_target.bodyparts)
+ for (var/obj/item/bodypart/part in carbon_target.get_bodyparts())
if (!part.brute_dam && !part.burn_dam)
continue
if (!(part.bodytype & required_bodytype))
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 5b75da86443..f06bed87776 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -180,7 +180,7 @@
bleed(bleed_rate * seconds_per_tick)
bleed_warn(bleed_rate)
- for (var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for (var/obj/item/bodypart/bodypart as anything in get_bodyparts())
if (bodypart.generic_bleedstacks)
bodypart.adjustBleedStacks(-1, 0)
@@ -263,7 +263,7 @@
/// Has each bodypart update its bleed/wound overlay icon states
/mob/living/carbon/proc/update_bodypart_bleed_overlays()
- for(var/obj/item/bodypart/iter_part as anything in bodyparts)
+ for(var/obj/item/bodypart/iter_part as anything in get_bodyparts())
iter_part.update_part_wound_overlay()
/// Bleeds amount units of blood from the mob, sometimes creating a blood splatter on the floor.
@@ -290,7 +290,7 @@
return 0
. = 0
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
. += bodypart.cached_bleed_rate
/mob/living/carbon/human/get_bleed_rate()
@@ -359,7 +359,7 @@
/mob/living/carbon/restore_blood()
. = ..()
- for(var/obj/item/bodypart/bodypart_to_restore as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart_to_restore as anything in get_bodyparts())
bodypart_to_restore.setBleedStacks(0)
/****************************************************
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index d1ee541429f..bc884201e83 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -425,8 +425,7 @@
return
var/total_burn = 0
var/total_brute = 0
- for(var/X in bodyparts) //hardcoded to streamline things a bit
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
total_brute += (BP.brute_dam * BP.body_damage_coeff)
total_burn += (BP.burn_dam * BP.body_damage_coeff)
set_health(round(maxHealth - get_oxy_loss() - get_tox_loss() - total_burn - total_brute, DAMAGE_PRECISION))
@@ -773,7 +772,7 @@
if(heal_flags & HEAL_LIMBS)
regenerate_limbs()
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts(include_stumps = TRUE))
limb.remove_surgical_state(ALL)
if(heal_flags & (HEAL_REFRESH_ORGANS|HEAL_ORGANS))
@@ -911,13 +910,15 @@
switch(new_bodypart.body_part)
if(LEG_LEFT, LEG_RIGHT)
- set_num_legs(num_legs + 1)
- if(!new_bodypart.bodypart_disabled)
- set_usable_legs(usable_legs + 1)
+ if(!IS_STUMP(new_bodypart))
+ set_num_legs(num_legs + 1)
+ if(!new_bodypart.bodypart_disabled)
+ set_usable_legs(usable_legs + 1)
if(ARM_LEFT, ARM_RIGHT)
- set_num_hands(num_hands + 1)
- if(!new_bodypart.bodypart_disabled)
- set_usable_hands(usable_hands + 1)
+ if(!IS_STUMP(new_bodypart))
+ set_num_hands(num_hands + 1)
+ if(!new_bodypart.bodypart_disabled)
+ set_usable_hands(usable_hands + 1)
synchronize_bodytypes()
synchronize_bodyshapes()
@@ -938,13 +939,27 @@
switch(old_bodypart.body_part)
if(LEG_LEFT, LEG_RIGHT)
- set_num_legs(num_legs - 1)
- if(!old_bodypart.bodypart_disabled)
- set_usable_legs(usable_legs - 1)
+ if(!IS_STUMP(old_bodypart))
+ set_num_legs(num_legs - 1)
+ if(!old_bodypart.bodypart_disabled)
+ set_usable_legs(usable_legs - 1)
if(ARM_LEFT, ARM_RIGHT)
- set_num_hands(num_hands - 1)
- if(!old_bodypart.bodypart_disabled)
- set_usable_hands(usable_hands - 1)
+ if(!IS_STUMP(old_bodypart))
+ set_num_hands(num_hands - 1)
+ if(!old_bodypart.bodypart_disabled)
+ set_usable_hands(usable_hands - 1)
+
+ if(!special && old_bodypart.stump_typepath)
+ if(old_bodypart.type == old_bodypart.stump_typepath)
+ stack_trace("Attempted to replace a stump with a stump")
+ else
+ var/obj/item/bodypart/stump = new old_bodypart.stump_typepath()
+ stump.bodyshape = old_bodypart.bodyshape
+ stump.bodytype = old_bodypart.bodytype
+ if(!stump.try_attach_limb(src, special = TRUE))
+ // the only way this can happen is if the stump is rejected via signal
+ // not much we can do about that besides hope they know what they're doing
+ qdel(stump)
synchronize_bodytypes()
synchronize_bodyshapes()
@@ -952,7 +967,7 @@
///Updates the bodypart speed modifier based on our bodyparts.
/mob/living/carbon/proc/update_bodypart_speed_modifier()
var/final_modification = 0
- for(var/obj/item/bodypart/leg/bodypart in bodyparts)
+ for(var/obj/item/bodypart/leg/bodypart in get_bodyparts())
final_modification += bodypart.speed_modifier
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/bodypart, update = TRUE, multiplicative_slowdown = final_modification)
@@ -985,7 +1000,7 @@
return
var/list/limb_list = list()
if(edit_action == "remove")
- for(var/obj/item/bodypart/iter_part as anything in bodyparts)
+ for(var/obj/item/bodypart/iter_part as anything in get_bodyparts())
limb_list += iter_part.body_zone
limb_list -= BODY_ZONE_CHEST
else
@@ -1019,7 +1034,7 @@
var/limb2add = input(usr, "Select a bodypart type to add", "Add/Replace Bodypart") as null|anything in sort_list(limbtypes)
var/obj/item/bodypart/new_bp = new limb2add()
if(new_bp.replace_limb(src))
- admin_ticket_log("key_name_admin(usr)] has replaced [src]'s [part.type] with [new_bp.type]")
+ admin_ticket_log("key_name_admin(usr)] has replaced [src]'s [part?.type || "missing limb"] with [new_bp.type]")
qdel(part)
else
to_chat(usr, "Failed to replace bodypart! They might be incompatible.")
@@ -1097,7 +1112,7 @@
/mob/living/carbon/proc/is_bleeding()
if(!CAN_HAVE_BLOOD(src))
return FALSE
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
if(part.cached_bleed_rate)
return TRUE
@@ -1107,7 +1122,7 @@
return FALSE
var/total_bleed_rate = 0
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
total_bleed_rate += part.cached_bleed_rate
return total_bleed_rate
@@ -1269,9 +1284,9 @@
/// Goes through the organs and bodyparts of the mob and updates their blood_dna_info, in case their blood type has changed (via set_species() or otherwise)
/mob/living/carbon/proc/update_cached_blood_dna_info()
var/list/blood_dna_info = get_blood_dna_list()
- for(var/obj/item/organ/organ in organs)
+ for(var/obj/item/organ/organ as anything in organs)
organ.blood_dna_info = blood_dna_info
- for(var/obj/item/bodypart/bodypart in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
bodypart.blood_dna_info = blood_dna_info
/// Setter for changing a mob's blood type
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 5dc3cbd7d70..497f133b117 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -453,7 +453,7 @@
return
var/embeds = FALSE
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts())
for(var/obj/item/weapon as anything in limb.embedded_objects)
if(!embeds)
embeds = TRUE
@@ -562,8 +562,7 @@
/mob/living/carbon/get_organic_health()
. = health
- for (var/_limb in bodyparts)
- var/obj/item/bodypart/limb = _limb
+ for (var/obj/item/bodypart/limb as anything in get_bodyparts())
if (!IS_ORGANIC_LIMB(limb))
. += (limb.brute_dam * limb.body_damage_coeff) + (limb.burn_dam * limb.body_damage_coeff)
diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm
index 271eef3cd40..b759c290efe 100644
--- a/code/modules/mob/living/carbon/carbon_update_icons.dm
+++ b/code/modules/mob/living/carbon/carbon_update_icons.dm
@@ -290,7 +290,7 @@
remove_overlay(DAMAGE_LAYER)
var/mutable_appearance/damage_overlay
- for(var/obj/item/bodypart/iter_part as anything in bodyparts)
+ for(var/obj/item/bodypart/iter_part as anything in get_bodyparts())
if(!iter_part.dmg_overlay_type)
continue
if(isnull(damage_overlay) && (iter_part.brutestate || iter_part.burnstate))
@@ -319,7 +319,7 @@
return
var/mutable_appearance/wound_overlay
- for(var/obj/item/bodypart/iter_part as anything in bodyparts)
+ for(var/obj/item/bodypart/iter_part as anything in get_bodyparts())
if(iter_part.bleed_overlay_icon)
var/mutable_appearance/blood_overlay = mutable_appearance('icons/mob/effects/bleed_overlays.dmi', "blank", -WOUND_LAYER, appearance_flags = KEEP_TOGETHER)
blood_overlay.color = blood_type.get_wound_color(src)
@@ -463,38 +463,35 @@
/mob/living/carbon/proc/update_body_parts(update_limb_data)
update_damage_overlays()
update_wound_overlays()
- var/list/needs_update = list()
var/limb_count_update = 0
- for(var/obj/item/bodypart/limb as anything in bodyparts)
- limb.update_limb(is_creating = update_limb_data) //Update limb actually doesn't do much, get_limb_icon is the cpu eater.
+ var/list/new_limbs = list()
+ for(var/body_zone, limb_untyped in get_bodyparts_by_zones())
+ var/obj/item/bodypart/limb = limb_untyped
+ if(isnull(limb) || IS_STUMP(limb))
+ if(icon_render_keys[body_zone])
+ icon_render_keys -= body_zone
+ limb_count_update += 1
+ continue
- var/old_key = icon_render_keys?[limb.body_zone] //Checks the mob's icon render key list for the bodypart
- icon_render_keys[limb.body_zone] = (limb.is_husked) ? limb.generate_husk_key().Join() : limb.generate_icon_key().Join() //Generates a key for the current bodypart
+ // Update limb actually doesn't do much, get_limb_icon is the cpu eater.
+ limb.update_limb(is_creating = update_limb_data)
- if(icon_render_keys[limb.body_zone] != old_key) //If the keys match, that means the limb doesn't need to be redrawn
- needs_update += limb
+ var/old_key = icon_render_keys[limb.body_zone]
+ var/new_key = limb.get_cache_key()
- limb_count_update += length(needs_update)
- var/list/missing_bodyparts = get_missing_limbs()
- if(((dna ? dna.species.max_bodypart_count : BODYPARTS_DEFAULT_MAXIMUM) - icon_render_keys.len) != missing_bodyparts.len) //Checks to see if the target gained or lost any limbs.
- limb_count_update += 1
- for(var/missing_limb in missing_bodyparts)
- icon_render_keys -= missing_limb //Removes dismembered limbs from the key list
+ if(new_key == old_key)
+ new_limbs += limb_icon_cache[new_key]
+
+ else
+ limb_icon_cache[new_key] ||= limb.get_limb_icon(dropped = FALSE)
+ new_limbs += limb_icon_cache[new_key]
+ icon_render_keys[limb.body_zone] = new_key
+ limb_count_update += 1
. = limb_count_update
if(!.)
return
- //GENERATE NEW LIMBS
- var/list/new_limbs = list()
- for(var/obj/item/bodypart/limb as anything in bodyparts)
- if(limb in needs_update)
- var/bodypart_icon = limb.get_limb_icon(dropped = FALSE, update_on = src)
- new_limbs += bodypart_icon
- limb_icon_cache[icon_render_keys[limb.body_zone]] = bodypart_icon //Caches the icon with the bodypart key, as it is new
- else
- new_limbs += limb_icon_cache[icon_render_keys[limb.body_zone]] //Pulls existing sprites from the cache
-
remove_overlay(BODYPARTS_LAYER)
if(new_limbs.len)
@@ -508,6 +505,13 @@
/////////////////////////
// Limb Icon Cache 2.0 //
/////////////////////////
+
+/// Returns a string representing the bodyparts icon cache key
+/obj/item/bodypart/proc/get_cache_key()
+ if(is_husked)
+ return jointext(generate_husk_key(), "-")
+ return jointext(generate_icon_key(), "-")
+
/**
* Called from update_body_parts() these procs handle the limb icon cache.
* the limb icon cache adds an icon_render_key to a human mob, it represents:
@@ -522,20 +526,20 @@
RETURN_TYPE(/list)
. = list()
if(is_dimorphic)
- . += "[limb_gender]-"
- . += "[limb_id]"
- . += "-[body_zone]"
+ . += limb_gender
+ . += limb_id
+ . += body_zone
if(should_draw_greyscale && draw_color)
- . += "-[draw_color]"
+ . += draw_color
if(is_invisible)
- . += "-invisible"
+ . += "invisible"
for(var/datum/bodypart_overlay/overlay as anything in bodypart_overlays)
if(!overlay.can_draw_on_bodypart(src, owner, is_husked))
continue
- . += "-[jointext(overlay.generate_icon_cache(), "-")]"
+ . += overlay.generate_icon_cache()
if(ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
- . += "-[human_owner.mob_height]"
+ . += "[human_owner.mob_height]"
SEND_SIGNAL(src, COMSIG_BODYPART_GENERATE_ICON_KEY, .)
return .
@@ -543,24 +547,22 @@
/obj/item/bodypart/proc/generate_husk_key()
RETURN_TYPE(/list)
. = list()
- . += "[limb_id]-"
- . += "[husk_type]"
- . += "-husk"
- . += "-[body_zone]"
+ if(is_dimorphic)
+ . += limb_gender
+ . += limb_id
+ . += husk_type
+ . += "husk"
+ . += body_zone
if(is_invisible)
- . += "-invisible"
- var/list/blood_dna = blood_dna_info || owner?.get_blood_dna_list()
- if (LAZYLEN(blood_dna))
- . += "-[get_color_from_blood_list(blood_dna)]"
- else
- . += "-[BLOOD_COLOR_RED]"
+ . += "invisible"
+ . += "[LAZYLEN(blood_dna_info) ? get_color_from_blood_list(blood_dna_info) : BLOOD_COLOR_RED]"
for(var/datum/bodypart_overlay/overlay as anything in bodypart_overlays)
if(!overlay.can_draw_on_bodypart(src, owner, TRUE))
continue
- . += "-[jointext(overlay.generate_icon_cache(), "-")]"
+ . += overlay.generate_icon_cache()
if(ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
- . += "-[human_owner.mob_height]"
+ . += "[human_owner.mob_height]"
return .
/obj/item/bodypart/head/generate_icon_key()
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index 191b303f715..fc2a98df0c0 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -20,7 +20,7 @@
// ALso we'll automatically covnert string def zones into bodyparts to pass into parent call.
else if(!isbodypart(def_zone))
var/random_zone = check_zone(def_zone || get_random_valid_zone(def_zone))
- def_zone = get_bodypart(random_zone) || bodyparts[1]
+ def_zone = get_bodypart(random_zone) || get_bodypart()
. = ..()
// Taking brute or burn to bodyparts gives a damage flash
@@ -84,13 +84,13 @@
//These procs fetch a cumulative total damage from all bodyparts
/mob/living/carbon/get_brute_loss()
var/amount = 0
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
amount += bodypart.brute_dam
return round(amount, DAMAGE_PRECISION)
/mob/living/carbon/get_fire_loss()
var/amount = 0
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
amount += bodypart.burn_dam
return round(amount, DAMAGE_PRECISION)
@@ -104,7 +104,7 @@
*/
/mob/living/carbon/proc/get_brute_loss_for_type(required_bodytype = ALL)
var/amount = 0
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
if(!(bodypart.bodytype & required_bodytype))
continue
amount += bodypart.brute_dam
@@ -119,7 +119,7 @@
*/
/mob/living/carbon/proc/get_fire_loss_for_type(required_bodytype = ALL)
var/amount = 0
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts())
if(!(bodypart.bodytype & required_bodytype))
continue
amount += bodypart.burn_dam
@@ -239,8 +239,7 @@
///Returns a list of damaged bodyparts
/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, required_bodytype = NONE, target_zone = null)
var/list/obj/item/bodypart/parts = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
if(required_bodytype && !(BP.bodytype & required_bodytype))
continue
if(!isnull(target_zone) && BP.body_zone != target_zone)
@@ -252,8 +251,7 @@
///Returns a list of damageable bodyparts
/mob/living/carbon/proc/get_damageable_bodyparts(required_bodytype)
var/list/obj/item/bodypart/parts = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
if(required_bodytype && !(BP.bodytype & required_bodytype))
continue
if(BP.brute_dam + BP.burn_dam < BP.max_damage)
@@ -264,8 +262,7 @@
///Returns a list of bodyparts with wounds (in case someone has a wound on an otherwise fully healed limb)
/mob/living/carbon/proc/get_wounded_bodyparts(required_bodytype)
var/list/obj/item/bodypart/parts = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
if(required_bodytype && !(BP.bodytype & required_bodytype))
continue
if(LAZYLEN(BP.wounds))
diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm
index 77611210d8c..292eda9c6ac 100644
--- a/code/modules/mob/living/carbon/death.dm
+++ b/code/modules/mob/living/carbon/death.dm
@@ -28,7 +28,7 @@
return ..()
/mob/living/carbon/get_gibs_type(drop_bitflags = NONE)
- var/obj/item/bodypart/chest = get_bodypart(BODY_ZONE_CHEST) || (length(bodyparts) ? bodyparts[1] : null)
+ var/obj/item/bodypart/chest = get_bodypart(BODY_ZONE_CHEST) || get_bodypart()
if (!istype(chest)) // what
return ..()
@@ -74,13 +74,22 @@
qdel(organ)
/mob/living/carbon/spread_bodyparts(drop_bitflags=NONE)
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
+ if(part.body_zone == BODY_ZONE_CHEST)
+ continue // never drop this
if(!(drop_bitflags & DROP_BRAIN) && part.body_zone == BODY_ZONE_HEAD)
- continue
- else if(part.body_zone == BODY_ZONE_CHEST)
- continue
- part.drop_limb()
+ continue // don't drop head if we aren't dropping a brain
+
+ var/list/leftover_organs = list()
+ for(var/obj/item/organ/leftover in part)
+ leftover_organs += leftover
+
+ part.drop_limb(TRUE)
part.throw_at(get_edge_target_turf(src, pick(GLOB.alldirs)), rand(1,3), 5)
+ // any organs that weren't throw out already about need to follow the bodypart out
+ for(var/obj/item/organ/leftover as anything in leftover_organs)
+ leftover.Remove(src, TRUE)
+ leftover.bodypart_insert(part)
/mob/living/carbon/set_suicide(suicide_state) //you thought that box trick was pretty clever, didn't you? well now hardmode is on, boyo.
. = ..()
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 946e009d4f8..279e65b8355 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -50,7 +50,7 @@
. += span_deadsay("It appears that [t_his] brain is missing...")
var/list/disabled = list()
- for(var/obj/item/bodypart/body_part as anything in bodyparts)
+ for(var/obj/item/bodypart/body_part as anything in get_bodyparts())
if(body_part.bodypart_disabled)
disabled += body_part
@@ -178,7 +178,7 @@
var/list/obj/item/bodypart/bleeding_limbs = list()
var/list/obj/item/bodypart/grasped_limbs = list()
- for(var/obj/item/bodypart/body_part as anything in bodyparts)
+ for(var/obj/item/bodypart/body_part as anything in get_bodyparts())
if(body_part.cached_bleed_rate)
bleeding_limbs += body_part.plaintext_zone
if(body_part.grasped_by)
@@ -338,7 +338,7 @@
var/list/seen_damage = list() // This looks like: ({Damage type} = list({Damage description for that damage type} = {number of times it has appeared}, ...), ...)
var/list/most_seen_damage = list() // This looks like: ({Damage type} = {Frequency of the most common description}, ...)
var/list/final_descriptions = list() // This looks like: ({Damage type} = {Most common damage description for that type}, ...)
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
for(var/damage_type in part.damage_examines)
var/damage_desc = part.damage_examines[damage_type]
if(!seen_damage[damage_type])
@@ -373,7 +373,7 @@
if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP))
continue
. += "[t_He] [t_is] holding [held_thing.examine_title(user)] in [t_his] [get_held_index_name(get_held_index_of_item(held_thing))]."
- for(var/obj/item/bodypart/arm/part in bodyparts)
+ for(var/obj/item/bodypart/arm/part in get_bodyparts())
if(!(part.bodypart_flags & BODYPART_PSEUDOPART))
continue
var/obj/item/corresponding_item = get_item_for_held_index(part.held_index) || part
@@ -475,7 +475,7 @@
if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP))
continue
. += "[t_He] [t_is] holding [held_thing.examine_title(user)] in [t_his] [get_held_index_name(get_held_index_of_item(held_thing))]."
- for(var/obj/item/bodypart/arm/part in bodyparts)
+ for(var/obj/item/bodypart/arm/part in get_bodyparts())
if(!(part.bodypart_flags & BODYPART_PSEUDOPART))
continue
var/obj/item/corresponding_item = get_item_for_held_index(part.held_index) || part
@@ -594,7 +594,7 @@
/mob/living/carbon/human/proc/get_mismatched_limb_text()
var/list/covered = get_covered_body_zones()
var/list/texts = list()
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
var/part_id = part.limb_id
var/obj/item/bodypart/expected_part = dna?.species?.bodypart_overrides[part.body_zone]
var/expected_id = initial(expected_part?.limb_id)
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 406b3eb8e26..75dbe2f24e9 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -189,6 +189,8 @@ GLOBAL_LIST_EMPTY(features_by_species)
plural_form = "[name]\s"
if(!examine_limb_id)
examine_limb_id = id
+ // Carbons determine bodypart order by this list, so we need to make sure it's sorted properly
+ sortTim(bodypart_overrides, GLOBAL_PROC_REF(cmp_bodypart_by_body_part_asc), associative = TRUE)
return ..()
@@ -1270,7 +1272,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return
// Lets pick a random body part and check for an existing burn
- var/obj/item/bodypart/bodypart = pick(humi.bodyparts)
+ var/obj/item/bodypart/bodypart = pick(humi.get_bodyparts())
var/datum/wound/existing_burn
for (var/datum/wound/iterated_wound as anything in bodypart.wounds)
var/datum/wound_pregen_data/pregen_data = iterated_wound.get_pregen_data()
@@ -1976,7 +1978,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
final_bodypart_overrides[BODY_ZONE_R_LEG] = /obj/item/bodypart/leg/right/digitigrade
final_bodypart_overrides[BODY_ZONE_L_LEG] = /obj/item/bodypart/leg/left/digitigrade
- for(var/obj/item/bodypart/old_part as anything in target.bodyparts)
+ for(var/obj/item/bodypart/old_part as anything in target.get_bodyparts())
if((old_part.change_exempt_flags & BP_BLOCK_CHANGE_SPECIES) || (old_part.bodypart_flags & BODYPART_IMPLANTED))
continue
@@ -2048,7 +2050,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
/// Remove body markings
/datum/species/proc/remove_body_markings(mob/living/carbon/human/hooman)
- for(var/obj/item/bodypart/part as anything in hooman.bodyparts)
+ for(var/obj/item/bodypart/part as anything in hooman.get_bodyparts())
for(var/datum/bodypart_overlay/simple/body_marking/marking in part.bodypart_overlays)
part.remove_bodypart_overlay(marking)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index a49e73fc415..187e684d06e 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -192,8 +192,7 @@
var/status = ""
if(get_brute_loss())
to_chat(human_user, "Physical trauma analysis:")
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
var/brutedamage = BP.brute_dam
if(brutedamage > 0)
status = "received minor physical injuries."
@@ -208,8 +207,7 @@
to_chat(human_user, "[BP] appears to have [status]")
if(get_fire_loss())
to_chat(human_user, "Analysis of skin burns:")
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
var/burndamage = BP.burn_dam
if(burndamage > 0)
status = "signs of minor burns."
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index fedc4d6e58c..86b5d138354 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -13,8 +13,7 @@
//If a specific bodypart is targeted, check how that bodypart is protected and return the value.
//If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
armorval += check_armor(BP, type)
organnum++
return (armorval/max(organnum, 1))
@@ -331,8 +330,7 @@
if(EXPLODE_DEVASTATE)
max_limb_loss = 4
probability = 50
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
+ for(var/obj/item/bodypart/BP as anything in get_bodyparts())
if(prob(probability) && !prob(getarmor(BP, BOMB)) && BP.body_zone != BODY_ZONE_HEAD && BP.body_zone != BODY_ZONE_CHEST)
BP.receive_damage(INFINITY, wound_bonus = CANT_WOUND) //Capped by proc
BP.dismember()
@@ -557,10 +555,12 @@
combined_msg += span_notice("You check yourself for injuries.")
- var/list/missing = get_all_limbs()
- for(var/obj/item/bodypart/body_part as anything in bodyparts)
- missing -= body_part.body_zone
+ for(var/part_zone, body_part_untyped in get_bodyparts_by_zones())
+ var/obj/item/bodypart/body_part = body_part_untyped
+ if(isnull(body_part) || IS_STUMP(body_part))
+ combined_msg += span_boldannounce("↳ Your [parse_zone(body_part?.body_zone || part_zone)] is missing!")
+ continue
if(body_part.bodypart_flags & BODYPART_PSEUDOPART) //don't show injury text for fake bodyparts; ie chainsaw arms or synthetic armblades
continue
@@ -568,9 +568,6 @@
if(bodypart_report)
combined_msg += "[span_notice("↳")] [bodypart_report]"
- for(var/t in missing)
- combined_msg += span_boldannounce("↳ Your [parse_zone(t)] is missing!")
-
var/tox = get_tox_loss() + (disgust / 5) + (HAS_TRAIT(src, TRAIT_SELF_AWARE) ? 0 : (rand(-3, 0) * 5))
switch(tox)
if(10 to 20)
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index 7b0d8e7dd0e..15d8175ffcf 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -967,7 +967,7 @@ generate/load female uniform sprites matching all previously decided variables
// optimization - none of our limbs or organs have the desired shape
return .
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts())
var/checked_bodyshape = limb.bodyshape
// accounts for stuff like snouts
for(var/obj/item/organ/organ in limb)
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 439ed75d544..10e9edfb715 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -413,6 +413,8 @@
new_bodypart = newBodyPart(BODY_ZONE_L_ARM)
new_bodypart.held_index = i
+ if(i >= 3) // start indexing them as right_arm2 and so on
+ new_bodypart.body_zone = "[new_bodypart.body_zone]_[ceil(i / 2)]"
new_bodypart.try_attach_limb(src, TRUE)
hand_bodyparts[i] = new_bodypart
..() //Don't redraw hands until we have organs for them
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 2d6754d2b95..bfa1ae5649b 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -67,7 +67,7 @@
var/obj/item/organ/heart/ethereal/ethereal_heart = new_ethereal.get_organ_slot(ORGAN_SLOT_HEART)
ethereal_heart.ethereal_color = default_color
- for(var/obj/item/bodypart/limb as anything in new_ethereal.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in new_ethereal.get_bodyparts())
if(limb.limb_id == SPECIES_ETHEREAL)
limb.update_limb(is_creating = TRUE)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index c2e5bb95d46..5fa890e834c 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -502,7 +502,7 @@
return COMPONENT_NO_EXPOSE_REAGENTS
/mob/living/carbon/proc/handle_bodyparts(seconds_per_tick)
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts(include_stumps = TRUE))
. |= limb.on_life(seconds_per_tick)
/mob/living/carbon/proc/handle_organs(seconds_per_tick)
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index 80189ae4902..32421516713 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -25,6 +25,13 @@
if(drop_bitflags & DROP_BODYPARTS)
spread_bodyparts(drop_bitflags)
+ // failsafe for if we fuck up and leave our brain behind. (other organs are replaceable so we can ignore them.)
+ var/obj/item/organ/brain/brain = get_organ_slot(ORGAN_SLOT_BRAIN)
+ if((drop_bitflags & DROP_BRAIN) && !isnull(brain))
+ stack_trace("gib invoked with drop_brain() had their brain after spilling organs and bodyparts, meaning both failed!")
+ brain.Remove(src)
+ brain.forceMove(drop_location())
+
SEND_SIGNAL(src, COMSIG_LIVING_GIBBED, drop_bitflags)
qdel(src)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 25cc456dda3..d9466e62241 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -2536,7 +2536,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
return
. = num_legs
num_legs = new_value
-
+ hud_used?.update_locked_slots()
///Proc to modify the value of usable_legs and hook behavior associated to this event.
/mob/living/proc/set_usable_legs(new_value)
@@ -2586,7 +2586,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
return
. = num_hands
num_hands = new_value
-
+ hud_used?.update_locked_slots()
///Proc to modify the value of usable_hands and hook behavior associated to this event.
/mob/living/proc/set_usable_hands(new_value)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 02e382c7117..40ee61766b8 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -62,7 +62,7 @@
/mob/living/carbon/get_random_valid_zone(base_zone, base_probability = 80, list/blacklisted_parts, even_weights, bypass_warning)
var/list/limbs = list()
- for(var/obj/item/bodypart/part as anything in bodyparts)
+ for(var/obj/item/bodypart/part as anything in get_bodyparts())
var/limb_zone = part.body_zone //cache the zone since we're gonna check it a ton.
if(limb_zone in blacklisted_parts)
continue
diff --git a/code/modules/projectiles/ammunition/ballistic/rifle.dm b/code/modules/projectiles/ammunition/ballistic/rifle.dm
index a252832dcd0..3c06aa13950 100644
--- a/code/modules/projectiles/ammunition/ballistic/rifle.dm
+++ b/code/modules/projectiles/ammunition/ballistic/rifle.dm
@@ -161,7 +161,7 @@
/datum/embedding/rebar_healium/on_successful_embed(mob/living/carbon/victim, obj/item/bodypart/target_limb)
. = ..()
- for(var/obj/item/bodypart/limb as anything in victim.bodyparts)
+ for(var/obj/item/bodypart/limb as anything in victim.get_bodyparts())
for(var/obj/item/ammo_casing/rebar/healium/other_rebar in limb.embedded_objects)
if (other_rebar == parent)
continue
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index bdbe041d2cf..79f5cfb4fd2 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -362,7 +362,7 @@
if (!iscarbon(user))
return BRUTELOSS
var/mob/living/carbon/suicider = user
- for (var/obj/item/bodypart/limb in suicider.bodyparts)
+ for (var/obj/item/bodypart/limb in suicider.get_bodyparts())
limb.dismember(BRUTE, silent = FALSE, wounding_type = WOUND_SLASH)
sleep(0.25 SECONDS)
diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
index 1b0dad125df..ba6ff560c9f 100644
--- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
@@ -1264,7 +1264,7 @@ Basically, we fill the time between now and 2s from now with hands based off the
for (var/obj/item/organ/organ as anything in exposed_carbon.organs)
organ.add_atom_colour(color_filter, WASHABLE_COLOUR_PRIORITY)
- for (var/obj/item/bodypart/part as anything in exposed_carbon.bodyparts)
+ for (var/obj/item/bodypart/part as anything in exposed_carbon.get_bodyparts())
part.add_atom_colour(color_filter, WASHABLE_COLOUR_PRIORITY)
/datum/reagent/inverse/colorful_reagent/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, metabolization_ratio)
@@ -1313,22 +1313,22 @@ Basically, we fill the time between now and 2s from now with hands based off the
switch(current_cycle)
if(10)
- for(var/obj/item/bodypart/leg/leg in affected_mob.bodyparts)
+ for(var/obj/item/bodypart/leg/leg in affected_mob.get_bodyparts())
affected_mob.cause_wound_of_type_and_severity(WOUND_BLUNT, leg, WOUND_SEVERITY_MODERATE)
to_chat(affected_mob, span_warning("Your legs start to cave in to your overwhelming gravity!"))
if(20)
- for(var/obj/item/bodypart/leg/leg in affected_mob.bodyparts)
+ for(var/obj/item/bodypart/leg/leg in affected_mob.get_bodyparts())
affected_mob.cause_wound_of_type_and_severity(WOUND_BLUNT, leg, WOUND_SEVERITY_SEVERE)
to_chat(affected_mob, span_warning("Your bones fragment horribly as the gravity pounds on you!"))
if(30)
- for(var/obj/item/bodypart/leg/leg in affected_mob.bodyparts)
+ for(var/obj/item/bodypart/leg/leg in affected_mob.get_bodyparts())
affected_mob.cause_wound_of_type_and_severity(WOUND_BLUNT, leg, WOUND_SEVERITY_CRITICAL)
to_chat(affected_mob, span_warning("The gravity of this situation makes your bones snap like popsicle sticks!"))
/datum/reagent/inverse/gravitum/overdose_start(mob/living/carbon/affected_mob, metabolization_ratio)
. = ..()
affected_mob.AddElement(/datum/element/squish, 120 SECONDS)
- for(var/obj/item/bodypart/leg/leg in affected_mob.bodyparts)
+ for(var/obj/item/bodypart/leg/leg in affected_mob.get_bodyparts())
affected_mob.cause_wound_of_type_and_severity(WOUND_SLASH, leg, WOUND_SEVERITY_SEVERE)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 7bed221fd53..1105c0a611c 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -2358,7 +2358,7 @@
for (var/obj/item/organ/organ as anything in exposed_carbon.organs)
organ.add_atom_colour(color_filter, WASHABLE_COLOUR_PRIORITY)
- for (var/obj/item/bodypart/part as anything in exposed_carbon.bodyparts)
+ for (var/obj/item/bodypart/part as anything in exposed_carbon.get_bodyparts())
part.add_atom_colour(color_filter, WASHABLE_COLOUR_PRIORITY)
/datum/reagent/colorful_reagent/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, metabolization_ratio)
diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm
index e30529bcd57..66096a368f4 100644
--- a/code/modules/reagents/reagent_containers/patch.dm
+++ b/code/modules/reagents/reagent_containers/patch.dm
@@ -90,7 +90,7 @@
. = ..()
if (!.)
return
- var/obj/item/bodypart/affecting = victim.get_bodypart(hit_zone) || victim.bodyparts[1]
+ var/obj/item/bodypart/affecting = victim.get_bodypart(hit_zone) || victim.get_bodypart()
if (!IS_ORGANIC_LIMB(affecting))
return FALSE
return TRUE
diff --git a/code/modules/religion/festival/instrument_rites.dm b/code/modules/religion/festival/instrument_rites.dm
index e3f53c10fd8..3f03b47747b 100644
--- a/code/modules/religion/festival/instrument_rites.dm
+++ b/code/modules/religion/festival/instrument_rites.dm
@@ -176,7 +176,7 @@
listener.adjust_brute_loss(damage_dealt)
/datum/religion_rites/song_tuner/pain/finish_effect(mob/living/carbon/human/listener, atom/song_source)
- var/obj/item/bodypart/sliced_limb = pick(listener.bodyparts)
+ var/obj/item/bodypart/sliced_limb = pick(listener.get_bodyparts())
sliced_limb.force_wound_upwards(/datum/wound/slash/flesh/moderate/many_cuts)
/datum/religion_rites/song_tuner/lullaby
diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm
index 05cf51ea433..d375a1c3882 100644
--- a/code/modules/religion/religion_sects.dm
+++ b/code/modules/religion/religion_sects.dm
@@ -111,7 +111,7 @@
return BLESSING_FAILED
var/mob/living/carbon/human/blessed = target
- for(var/obj/item/bodypart/bodypart as anything in blessed.bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in blessed.get_bodyparts())
if(IS_ROBOTIC_LIMB(bodypart))
to_chat(chap, span_warning("[GLOB.deity] refuses to heal this metallic taint!"))
return BLESSING_IGNORED
@@ -280,7 +280,7 @@
return BLESSING_IGNORED
var/mob/living/carbon/human/blessed = blessed_living
- for(var/obj/item/bodypart/robolimb as anything in blessed.bodyparts)
+ for(var/obj/item/bodypart/robolimb as anything in blessed.get_bodyparts())
if(IS_ROBOTIC_LIMB(robolimb))
to_chat(chap, span_warning("[GLOB.deity] refuses to heal this metallic taint!"))
return BLESSING_IGNORED
@@ -346,7 +346,7 @@
var/transferred = FALSE
var/list/hurt_limbs = target.get_damaged_bodyparts(1, 1, BODYTYPE_ORGANIC) + target.get_wounded_bodyparts(BODYTYPE_ORGANIC)
var/list/chaplains_limbs = list()
- for(var/obj/item/bodypart/possible_limb in chaplain.bodyparts)
+ for(var/obj/item/bodypart/possible_limb in chaplain.get_bodyparts())
if(IS_ORGANIC_LIMB(possible_limb))
chaplains_limbs += possible_limb
diff --git a/code/modules/religion/sparring/sparring_datum.dm b/code/modules/religion/sparring/sparring_datum.dm
index fbe0fe93070..c9ea83be5f0 100644
--- a/code/modules/religion/sparring/sparring_datum.dm
+++ b/code/modules/religion/sparring/sparring_datum.dm
@@ -216,7 +216,7 @@
if(PUNISHMENT_BRAND)
var/mob/living/carbon/human/branded = interfering
to_chat(interfering, span_warning("[GLOB.deity] brands your flesh for interfering with [chaplain]'s sparring match!!"))
- var/obj/item/bodypart/branded_limb = pick(branded.bodyparts)
+ var/obj/item/bodypart/branded_limb = pick(branded.get_bodyparts())
branded_limb.force_wound_upwards(/datum/wound/burn/flesh/severe/brand, wound_source = "divine intervention")
branded.emote("scream")
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
index a8f22f5f980..a75df1542a6 100644
--- a/code/modules/research/xenobiology/crossbreeding/_misc.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -37,18 +37,11 @@ Slimecrossing Items
saved_part.old_part.heal_damage(INFINITY, INFINITY, null, FALSE)
saved_part.old_part.receive_damage(saved_part.brute_dam, saved_part.burn_dam, wound_bonus=CANT_WOUND)
dont_chop[zone] = TRUE
- for(var/_part in bodyparts)
- var/obj/item/bodypart/part = _part
- if(dont_chop[part.body_zone])
- continue
- part.drop_limb(TRUE)
/mob/living/carbon/proc/save_bodyparts()
var/list/datum/saved_bodypart/ret = list()
- for(var/_part in bodyparts)
- var/obj/item/bodypart/part = _part
+ for(var/obj/item/bodypart/part as anything in get_bodyparts(include_stumps = TRUE))
var/datum/saved_bodypart/saved_part = new(part)
-
ret[part.body_zone] = saved_part
return ret
diff --git a/code/modules/spells/spell_types/touch/scream_for_me.dm b/code/modules/spells/spell_types/touch/scream_for_me.dm
index d3c142d7039..2c951f1160d 100644
--- a/code/modules/spells/spell_types/touch/scream_for_me.dm
+++ b/code/modules/spells/spell_types/touch/scream_for_me.dm
@@ -28,7 +28,7 @@
return
var/mob/living/carbon/human/human_victim = victim
human_victim.emote("scream")
- for(var/obj/item/bodypart/to_wound as anything in human_victim.bodyparts)
+ for(var/obj/item/bodypart/to_wound as anything in human_victim.get_bodyparts())
human_victim.cause_wound_of_type_and_severity(WOUND_SLASH, to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL)
return TRUE
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index f266827d4e5..462c7067e17 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -231,6 +231,8 @@
var/static/list/butcher_drop_cache = list()
/// What state is the bodypart in for determining surgery availability
VAR_FINAL/surgery_state = NONE
+ /// Typepath of this limb as a stump
+ var/stump_typepath
/obj/item/bodypart/apply_fantasy_bonuses(bonus)
. = ..()
@@ -625,8 +627,7 @@
SHOULD_CALL_PARENT(TRUE)
var/atom/drop_loc = drop_location()
- if(IS_ORGANIC_LIMB(src))
- playsound(drop_loc, 'sound/misc/splort.ogg', 50, TRUE, -1)
+ var/play_sfx = FALSE
for(var/obj/item/organ/bodypart_organ in contents)
if(bodypart_organ.organ_flags & ORGAN_UNREMOVABLE)
@@ -643,10 +644,15 @@
if(drop_loc) //can be null if being deleted
bodypart_organ.forceMove(get_turf(drop_loc))
+ play_sfx = TRUE
if(drop_loc) //can be null during deletion
for(var/atom/movable/movable as anything in src)
movable.forceMove(drop_loc)
+ play_sfx = TRUE
+
+ if(play_sfx && IS_ORGANIC_LIMB(src))
+ playsound(drop_loc, 'sound/misc/splort.ogg', 50, TRUE, -1)
update_icon_dropped()
@@ -1261,7 +1267,7 @@
update_icon_dropped()
///Generates an /image for the limb to be used as an overlay
-/obj/item/bodypart/proc/get_limb_icon(dropped, mob/living/carbon/update_on)
+/obj/item/bodypart/proc/get_limb_icon(dropped)
SHOULD_CALL_PARENT(TRUE)
RETURN_TYPE(/list)
@@ -1275,7 +1281,7 @@
// Handles invisibility (not alpha or actual invisibility but invisibility)
if(is_invisible)
. += image(icon_invisible, "invisible_[body_zone]", -BODYPARTS_LAYER, dir = image_dir)
- SEND_SIGNAL(src, COMSIG_BODYPART_GET_LIMB_ICON, ., dropped, update_on)
+ SEND_SIGNAL(src, COMSIG_BODYPART_GET_LIMB_ICON, ., dropped)
return .
// Normal non-husk handling
@@ -1303,7 +1309,7 @@
if(brutestate)
// divided into two overlays: one that gets colored and one that doesn't.
var/image/brute_blood_overlay = image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, dir = SOUTH)
- brute_blood_overlay.color = get_color_from_blood_list(update_on ? update_on.get_blood_dna_list() : blood_dna_info) // living mobs can just get it fresh, dropped limbs use blood_dna_info
+ brute_blood_overlay.color = get_color_from_blood_list(blood_dna_info)
var/mutable_appearance/brute_damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0_overlay", -DAMAGE_LAYER, appearance_flags = RESET_COLOR)
if(brute_damage_overlay)
brute_blood_overlay.overlays += brute_damage_overlay
@@ -1384,7 +1390,7 @@
for(var/datum/layer in .)
overlay.modify_bodypart_appearance(layer)
- SEND_SIGNAL(src, COMSIG_BODYPART_GET_LIMB_ICON, ., dropped, update_on)
+ SEND_SIGNAL(src, COMSIG_BODYPART_GET_LIMB_ICON, ., dropped)
return .
/obj/item/bodypart/proc/huskify_image(image/thing_to_husk)
@@ -1396,11 +1402,7 @@
husk_blood.blend_mode = BLEND_INSET_OVERLAY
husk_blood.dir = thing_to_husk.dir
husk_blood.layer = thing_to_husk.layer
- var/list/blood_dna = blood_dna_info || owner?.get_blood_dna_list()
- if (LAZYLEN(blood_dna))
- husk_blood.color = get_color_from_blood_list(blood_dna)
- else
- husk_blood.color = BLOOD_COLOR_RED
+ husk_blood.color = LAZYLEN(blood_dna_info) ? get_color_from_blood_list(blood_dna_info) : BLOOD_COLOR_RED
return husk_blood
///Add a bodypart overlay and call the appropriate update procs
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 2960dee5577..72108859d3e 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -17,7 +17,7 @@
if(!silent)
limb_owner.visible_message(span_danger("[limb_owner]'s [name] is violently dismembered!"))
INVOKE_ASYNC(limb_owner, TYPE_PROC_REF(/mob, emote), "scream")
- playsound(get_turf(limb_owner), 'sound/effects/dismember.ogg', 80, TRUE)
+ playsound(limb_owner, 'sound/effects/dismember.ogg', 80, TRUE)
limb_owner.add_mood_event("dismembered_[body_zone]", /datum/mood_event/dismembered, src)
limb_owner.add_mob_memory(/datum/memory/was_dismembered, lost_limb = src)
@@ -123,7 +123,7 @@
if(!special)
phantom_owner.hud_used?.update_locked_slots()
- if(bodypart_flags & BODYPART_PSEUDOPART)
+ if(bodypart_flags & (BODYPART_PSEUDOPART|BODYPART_STUMP))
drop_organs(phantom_owner) //Psuedoparts shouldn't have organs, but just in case
if(!QDELING(src)) // we might be removed as a part of something qdeling us
qdel(src)
@@ -281,6 +281,13 @@
if(!can_attach_limb(new_limb_owner, special))
return FALSE
+ var/obj/item/bodypart/existing_limb = new_limb_owner.get_bodypart(body_zone, include_stumps = TRUE)
+ if(existing_limb)
+ if(existing_limb.type != stump_typepath)
+ stack_trace("Attempted to attach a limb to [new_limb_owner] in zone [body_zone] where they already have a non-stump limb")
+ existing_limb.drop_limb(special = TRUE)
+ qdel(existing_limb)
+
SEND_SIGNAL(new_limb_owner, COMSIG_CARBON_ATTACH_LIMB, src, special, lazy)
SEND_SIGNAL(src, COMSIG_BODYPART_ATTACHED, new_limb_owner, special, lazy)
new_limb_owner.add_bodypart(src)
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 73a526361f0..88f4cc912f2 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -27,6 +27,7 @@
bodypart_trait_source = HEAD_TRAIT
butcher_replacement = /obj/item/bodypart/head/skeleton/nonfunctional
base_meat_amount = 0
+ stump_typepath = /obj/item/bodypart/head/stump
/// Do we show the information about missing organs upon being examined? Defaults to TRUE, useful for Dullahan heads.
var/show_organs_on_examine = TRUE
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index c5fc38a8b6c..afb7c18d1e3 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -1,15 +1,55 @@
-
-/mob/living/proc/get_bodypart(zone)
+/**
+ * Returns a bodypart of the specified zone that this mob has
+ *
+ * * zone: the zone to get.
+ * Defaults to chest, allowing for skilling zone nullchecks if you don't care what bodypart you get.
+ * * include_stumps: whether or not to consider stumps as valid bodyparts to return.
+ * Defaults to FALSE, meaning that if a limb is missing (is a stump), nothing will be returned.
+ *
+ * Returns a bodypart, or null.
+ */
+/mob/living/proc/get_bodypart(zone = BODY_ZONE_CHEST, include_stumps = FALSE)
return
-/mob/living/carbon/get_bodypart(zone)
+/mob/living/carbon/get_bodypart(zone = BODY_ZONE_CHEST, include_stumps = FALSE)
RETURN_TYPE(/obj/item/bodypart)
- if(!zone)
- zone = BODY_ZONE_CHEST
for(var/obj/item/bodypart/bodypart as anything in bodyparts)
- if(bodypart.body_zone == zone)
- return bodypart
+ if(!include_stumps && IS_STUMP(bodypart))
+ continue
+ if(bodypart.body_zone != zone)
+ continue
+ return bodypart
+
+/**
+ * Returns all bodyparts this mob has, optionally including stumps.
+ *
+ * include_stumps: whether or not to consider stumps as valid bodyparts to return.
+ * Defaults to FALSE, meaning that if a limb is missing (is a stump), it won't be included in the returned list.
+ *
+ * Returns a list of bodyparts, which may be empty.
+ */
+/mob/living/proc/get_bodyparts(include_stumps = FALSE)
+ var/list/parts = list()
+ for(var/zone in get_all_limbs())
+ var/obj/item/bodypart/bodypart = get_bodypart(zone, include_stumps)
+ if(bodypart)
+ parts += bodypart
+
+ return parts
+
+/**
+ * Returns all bodyparts this mob has, indexed by their body zone
+ * Also includes stumps and nulls, so be sure to check for those if you use this proc.
+ * (Note: nulls will be very rare - as 95% of missing limbs are represented as stumps - but not impossible due to some edge cases)
+ *
+ * Returns a list of bodyparts indexed by their body zone
+ */
+/mob/living/proc/get_bodyparts_by_zones() as /list
+ var/list/parts = list()
+ for(var/zone in get_all_limbs())
+ parts[zone] = get_bodypart(zone)
+ return parts
///Returns TRUE/FALSE on whether the mob should have a limb in a given zone, used for species-restrictions.
/mob/living/carbon/proc/should_have_limb(zone)
@@ -128,13 +168,14 @@
///Returns a list of all limbs this mob should have.
/mob/living/carbon/get_all_limbs()
- if(dna)
- return dna.species.bodypart_overrides.Copy()
- return ..()
+ // gets the "normal list", ie chest-head-legs-arms. order matters for human rendering!
+ . = dna?.species?.bodypart_overrides.Copy() || ..()
+ // includes any additional adminbussed hands
+ for(var/obj/item/bodypart/hand in hand_bodyparts)
+ . |= hand.body_zone
///Returns a list of all missing limbs this mob should have on them, but don't.
/mob/living/carbon/proc/get_missing_limbs() as /list
- RETURN_TYPE(/list)
var/list/full = get_all_limbs()
for(var/zone in full)
if(get_bodypart(zone))
@@ -177,12 +218,12 @@
///Remove all embedded objects from all limbs on the carbon mob
/mob/living/carbon/proc/remove_all_embedded_objects()
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts(include_stumps = TRUE))
for(var/obj/item/embedded as anything in bodypart.embedded_objects)
remove_embedded_object(embedded)
/mob/living/carbon/proc/has_embedded_objects(include_harmless = FALSE)
- for(var/obj/item/bodypart/bodypart as anything in bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in get_bodyparts(include_stumps = TRUE))
for(var/obj/item/embedded as anything in bodypart.embedded_objects)
if(!include_harmless && embedded.get_embed().is_harmless(consider_stamina = TRUE))
continue
@@ -228,7 +269,7 @@
/// Makes sure that the owner's bodytype flags match the flags of all of its parts and organs
/mob/living/carbon/proc/synchronize_bodytypes()
var/all_limb_flags = NONE
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts(include_stumps = TRUE))
for(var/obj/item/organ/organ in limb)
all_limb_flags |= organ.external_bodytypes
all_limb_flags |= limb.bodytype
@@ -238,7 +279,7 @@
/// Makes sure that the owner's bodyshape flags match the flags of all of its parts and organs
/mob/living/carbon/proc/synchronize_bodyshapes()
var/all_limb_flags = NONE
- for(var/obj/item/bodypart/limb as anything in bodyparts)
+ for(var/obj/item/bodypart/limb as anything in get_bodyparts(include_stumps = TRUE))
for(var/obj/item/organ/organ in limb)
all_limb_flags |= organ.external_bodyshapes
all_limb_flags |= limb.bodyshape
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index c888271cfc2..7c112950265 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -149,6 +149,7 @@
/// Parent Type for arms, should not appear in game.
/obj/item/bodypart/arm
+ abstract_type = /obj/item/bodypart/arm
name = "arm"
desc = "Hey buddy give me a HAND and report this to the github because you shouldn't be seeing this."
abstract_type = /obj/item/bodypart/arm
@@ -324,6 +325,7 @@
px_y = 0
bodypart_trait_source = LEFT_ARM_TRAIT
butcher_replacement = /obj/item/bodypart/arm/left/skeleton/nonfunctional
+ stump_typepath = /obj/item/bodypart/arm/left/stump
/obj/item/bodypart/arm/left/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_ARM))
@@ -406,6 +408,7 @@
px_y = 0
bodypart_trait_source = RIGHT_ARM_TRAIT
butcher_replacement = /obj/item/bodypart/arm/right/skeleton/nonfunctional
+ stump_typepath = /obj/item/bodypart/arm/right/stump
/obj/item/bodypart/arm/right/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_ARM))
@@ -475,6 +478,7 @@
/// Parent Type for legs, should not appear in game.
/obj/item/bodypart/leg
+ abstract_type = /obj/item/bodypart/leg
name = "leg"
desc = "This item shouldn't exist. Talk about breaking a leg. Badum-Tss!"
abstract_type = /obj/item/bodypart/leg
@@ -565,6 +569,7 @@
can_be_disabled = TRUE
bodypart_trait_source = LEFT_LEG_TRAIT
butcher_replacement = /obj/item/bodypart/leg/left/skeleton/nonfunctional
+ stump_typepath = /obj/item/bodypart/leg/left/stump
/obj/item/bodypart/leg/left/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_LEG))
@@ -644,6 +649,7 @@
px_y = 12
bodypart_trait_source = RIGHT_LEG_TRAIT
butcher_replacement = /obj/item/bodypart/leg/right/skeleton/nonfunctional
+ stump_typepath = /obj/item/bodypart/leg/right/stump
/obj/item/bodypart/leg/right/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_LEG))
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index 4d17428fc9b..fe5d9c6e14d 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -277,7 +277,7 @@
SIGNAL_HANDLER
var/all_robotic = TRUE
- for(var/obj/item/bodypart/part in owner.bodyparts)
+ for(var/obj/item/bodypart/part as anything in owner.get_bodyparts())
all_robotic = all_robotic && IS_ROBOTIC_LIMB(part)
if(all_robotic)
diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
index acb4b65a821..41037f538c4 100644
--- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
@@ -547,6 +547,7 @@
throwforce = 25 // It's also a potent weapon
show_organs_on_examine = FALSE
speech_span = null
+ stump_typepath = null
/obj/item/bodypart/head/dullahan/Entered(obj/item/organ/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
diff --git a/code/modules/surgery/bodyparts/stumps.dm b/code/modules/surgery/bodyparts/stumps.dm
new file mode 100644
index 00000000000..49e4cdf2955
--- /dev/null
+++ b/code/modules/surgery/bodyparts/stumps.dm
@@ -0,0 +1,72 @@
+// Invisible bodyparts that serve as placeholders for a missing limb
+// Used so we can add behavior to "missing limbs" without putting it on the mob itself
+
+/obj/item/bodypart/head/stump
+ limb_id = null
+ plaintext_zone = "neck stump"
+ stump_typepath = null
+ scarrable = FALSE
+ biological_state = NONE
+ bodypart_flags = BODYPART_UNREMOVABLE | BODYPART_STUMP | BODYPART_VIRGIN
+
+ head_flags = NONE
+ teeth_count = 0 // lol?
+
+/obj/item/bodypart/head/stump/Initialize(mapload)
+ . = ..()
+ name = "stump"
+ // these traits are largely redundant, as many places that check for disabled limbs filter stumps.
+ // however, marking them as unusable for the sake of completeness might make it easier to work with.
+ ADD_TRAIT(src, TRAIT_PARALYSIS, INNATE_TRAIT)
+
+/obj/item/bodypart/leg/left/stump
+ limb_id = null
+ plaintext_zone = "left leg stump"
+ stump_typepath = null
+ scarrable = FALSE
+ biological_state = NONE
+ bodypart_flags = BODYPART_UNREMOVABLE | BODYPART_STUMP | BODYPART_VIRGIN
+
+/obj/item/bodypart/leg/left/stump/Initialize(mapload)
+ . = ..()
+ name = "stump"
+ ADD_TRAIT(src, TRAIT_PARALYSIS, INNATE_TRAIT)
+
+/obj/item/bodypart/leg/right/stump
+ limb_id = null
+ plaintext_zone = "right leg stump"
+ stump_typepath = null
+ scarrable = FALSE
+ biological_state = NONE
+ bodypart_flags = BODYPART_UNREMOVABLE | BODYPART_STUMP | BODYPART_VIRGIN
+
+/obj/item/bodypart/leg/right/stump/Initialize(mapload)
+ . = ..()
+ name = "stump"
+ ADD_TRAIT(src, TRAIT_PARALYSIS, INNATE_TRAIT)
+
+/obj/item/bodypart/arm/left/stump
+ limb_id = null
+ plaintext_zone = "left arm stump"
+ stump_typepath = null
+ scarrable = FALSE
+ biological_state = NONE
+ bodypart_flags = BODYPART_UNREMOVABLE | BODYPART_STUMP | BODYPART_VIRGIN
+
+/obj/item/bodypart/arm/left/stump/Initialize(mapload)
+ . = ..()
+ name = "stump"
+ ADD_TRAIT(src, TRAIT_PARALYSIS, INNATE_TRAIT)
+
+/obj/item/bodypart/arm/right/stump
+ limb_id = null
+ plaintext_zone = "right arm stump"
+ stump_typepath = null
+ scarrable = FALSE
+ biological_state = NONE
+ bodypart_flags = BODYPART_UNREMOVABLE | BODYPART_STUMP | BODYPART_VIRGIN
+
+/obj/item/bodypart/arm/right/stump/Initialize(mapload)
+ . = ..()
+ name = "stump"
+ ADD_TRAIT(src, TRAIT_PARALYSIS, INNATE_TRAIT)
diff --git a/code/modules/surgery/operations/_operation.dm b/code/modules/surgery/operations/_operation.dm
index 95ad653cd3d..8d49b07c9f7 100644
--- a/code/modules/surgery/operations/_operation.dm
+++ b/code/modules/surgery/operations/_operation.dm
@@ -1297,6 +1297,9 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
abstract_type = /datum/surgery_operation/limb
/// Body type required to perform this operation
var/required_bodytype = NONE
+ /// If TRUE, this operation can be performed on stumps.
+ /// If FALSE, the target limb must be a full limb.
+ var/allow_stumps = FALSE
/datum/surgery_operation/limb/all_blocked_strings()
. = ..()
@@ -1308,7 +1311,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
/datum/surgery_operation/limb/get_operation_target(atom/movable/operating_on, body_zone)
if (isliving(operating_on))
var/mob/living/patient = operating_on
- return patient.get_bodypart(deprecise_zone(body_zone))
+ return patient.get_bodypart(deprecise_zone(body_zone), allow_stumps)
if (!isbodypart(operating_on))
return null
return operating_on
diff --git a/code/modules/surgery/operations/operation_add_limb.dm b/code/modules/surgery/operations/operation_add_limb.dm
index 3f12368ff12..ab837aafbcb 100644
--- a/code/modules/surgery/operations/operation_add_limb.dm
+++ b/code/modules/surgery/operations/operation_add_limb.dm
@@ -1,7 +1,7 @@
#define OPERATION_REJECTION_DAMAGE "tox_damage"
// This surgery is so snowflake that it doesn't use any of the operation subtypes, it forges its own path
-/datum/surgery_operation/prosthetic_replacement
+/datum/surgery_operation/limb/prosthetic_replacement
name = "prosthetic replacement"
desc = "Replace a missing limb with a prosthetic (or arbitrary) item."
implements = list(
@@ -12,6 +12,7 @@
operation_flags = OPERATION_STANDING_ALLOWED | OPERATION_PRIORITY_NEXT_STEP | OPERATION_NOTABLE | OPERATION_IGNORE_CLOTHES
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
+ allow_stumps = TRUE
/// List of items that are always allowed to be an arm replacement, even if they fail another requirement.
var/list/always_accepted_prosthetics = list(
/obj/item/chainsaw, // the OG, too large otherwise
@@ -21,25 +22,20 @@
/// Radial slice datums for every augment type
VAR_PRIVATE/list/cached_prosthetic_options
-/datum/surgery_operation/prosthetic_replacement/get_default_radial_image()
- return image(/obj/item/bodypart/chest)
-
-/datum/surgery_operation/prosthetic_replacement/get_recommended_tool()
+/datum/surgery_operation/limb/prosthetic_replacement/get_recommended_tool()
return "any limb / any item"
-/datum/surgery_operation/prosthetic_replacement/get_any_tool()
+/datum/surgery_operation/limb/prosthetic_replacement/get_any_tool()
return "Any suitable arm replacement"
-/datum/surgery_operation/prosthetic_replacement/all_required_strings()
- . = list()
- . += "operate on chest (target chest)"
- . += ..()
- . += "when the chest is prepared, target the zone of the limb you are attaching"
+/datum/surgery_operation/limb/prosthetic_replacement/all_required_strings()
+ . = ..()
+ . += "the limb must be missing / a stump"
-/datum/surgery_operation/prosthetic_replacement/any_required_strings()
+/datum/surgery_operation/limb/prosthetic_replacement/any_required_strings()
return list("arms may receive any suitable item in lieu of a replacement limb") + ..()
-/datum/surgery_operation/prosthetic_replacement/get_radial_options(obj/item/bodypart/chest/chest, obj/item/tool, operating_zone)
+/datum/surgery_operation/limb/prosthetic_replacement/get_radial_options(obj/item/bodypart/chest/chest, obj/item/tool, operating_zone)
var/datum/radial_menu_choice/option = LAZYACCESS(cached_prosthetic_options, tool.type)
if(!option)
option = new()
@@ -50,32 +46,10 @@
return option
-/datum/surgery_operation/prosthetic_replacement/get_operation_target(atom/movable/operating_on, body_zone)
- if (!isliving(operating_on))
- return null
- var/mob/living/patient = operating_on
- // We always operate on the chest even if we're targeting left leg or w/e
- return patient.get_bodypart(BODY_ZONE_CHEST)
+/datum/surgery_operation/limb/prosthetic_replacement/state_check(obj/item/bodypart/limb)
+ return IS_STUMP(limb)
-/datum/surgery_operation/prosthetic_replacement/has_surgery_state(obj/item/bodypart/chest/chest, state)
- return LIMB_HAS_SURGERY_STATE(chest, state)
-
-/datum/surgery_operation/prosthetic_replacement/has_any_surgery_state(obj/item/bodypart/chest/chest, state)
- return LIMB_HAS_ANY_SURGERY_STATE(chest, state)
-
-/datum/surgery_operation/prosthetic_replacement/get_patient(obj/item/bodypart/chest/chest)
- return chest.owner
-
-/datum/surgery_operation/prosthetic_replacement/is_available(obj/item/bodypart/chest/chest, operated_zone)
- var/real_operated_zone = deprecise_zone(operated_zone)
- // Operate on the chest but target another zone
- if(!HAS_TRAIT(chest, TRAIT_READY_TO_OPERATE) || real_operated_zone == BODY_ZONE_CHEST)
- return FALSE
- if(chest.owner.get_bodypart(real_operated_zone))
- return FALSE
- return ..()
-
-/datum/surgery_operation/prosthetic_replacement/snowflake_check_availability(obj/item/bodypart/chest, mob/living/surgeon, obj/item/tool, operated_zone)
+/datum/surgery_operation/limb/prosthetic_replacement/snowflake_check_availability(obj/item/bodypart/chest, mob/living/surgeon, obj/item/tool, operated_zone)
if(!surgeon.canUnEquip(tool))
return FALSE
var/real_operated_zone = deprecise_zone(operated_zone)
@@ -91,7 +65,7 @@
return FALSE
return TRUE
-/datum/surgery_operation/prosthetic_replacement/tool_check(obj/item/tool)
+/datum/surgery_operation/limb/prosthetic_replacement/tool_check(obj/item/tool)
if(tool.item_flags & (ABSTRACT|DROPDEL|HAND_ITEM))
return FALSE
if(isbodypart(tool))
@@ -104,41 +78,41 @@
return FALSE
return TRUE
-/datum/surgery_operation/prosthetic_replacement/pre_preop(atom/movable/operating_on, mob/living/surgeon, tool, list/operation_args)
+/datum/surgery_operation/limb/prosthetic_replacement/pre_preop(atom/movable/operating_on, mob/living/surgeon, tool, list/operation_args)
. = ..()
// always operate on absolute body zones
operation_args[OPERATION_TARGET_ZONE] = deprecise_zone(operation_args[OPERATION_TARGET_ZONE])
-/datum/surgery_operation/prosthetic_replacement/on_preop(obj/item/bodypart/chest/chest, mob/living/surgeon, obj/item/tool, list/operation_args)
- var/target_zone_readable = parse_zone(operation_args[OPERATION_TARGET_ZONE])
+/datum/surgery_operation/limb/prosthetic_replacement/on_preop(obj/item/bodypart/limb, mob/living/surgeon, obj/item/tool, list/operation_args)
display_results(
surgeon,
- chest.owner,
- span_notice("You begin to replace [chest.owner]'s missing [target_zone_readable] with [tool]..."),
- span_notice("[surgeon] begins to replace [chest.owner]'s missing [target_zone_readable] with [tool]."),
- span_notice("[surgeon] begins to replace [chest.owner]'s missing [target_zone_readable]."),
+ limb.owner,
+ // "You begin to attach the right arm to john doe's right arm stump"
+ span_notice("You begin to attach [tool]'s to [FORMAT_LIMB_OWNER(limb)]..."),
+ span_notice("[surgeon] begins to attach [tool]'s to [FORMAT_LIMB_OWNER(limb)]."),
+ span_notice("[surgeon] begins to attach [tool]'s to [FORMAT_LIMB_OWNER(limb)]."),
)
- display_pain(chest.owner, "You feel an uncomfortable sensation where your [target_zone_readable] should be!")
+ display_pain(limb.owner, "You feel an uncomfortable sensation where your [parse_zone(limb.body_zone)] should be!")
operation_args[OPERATION_REJECTION_DAMAGE] = 10
if(isbodypart(tool))
var/obj/item/bodypart/new_limb = tool
if(IS_ROBOTIC_LIMB(new_limb))
operation_args[OPERATION_REJECTION_DAMAGE] = 0
- else if(new_limb.check_for_frankenstein(chest.owner))
+ else if(new_limb.check_for_frankenstein(limb.owner))
operation_args[OPERATION_REJECTION_DAMAGE] = 30
-/datum/surgery_operation/prosthetic_replacement/on_success(obj/item/bodypart/chest/chest, mob/living/surgeon, obj/item/tool, list/operation_args)
+/datum/surgery_operation/limb/prosthetic_replacement/on_success(obj/item/bodypart/limb, mob/living/surgeon, obj/item/tool, list/operation_args)
if(!surgeon.temporarilyRemoveItemFromInventory(tool))
return // should never happen
if(operation_args[OPERATION_REJECTION_DAMAGE] > 0)
- chest.owner.apply_damage(operation_args[OPERATION_REJECTION_DAMAGE], TOX)
+ limb.owner.apply_damage(operation_args[OPERATION_REJECTION_DAMAGE], TOX)
if(isbodypart(tool))
- handle_bodypart(chest.owner, surgeon, tool)
+ handle_bodypart(limb.owner, surgeon, tool)
return
- handle_arbitrary_prosthetic(chest.owner, surgeon, tool, operation_args[OPERATION_TARGET_ZONE])
+ handle_arbitrary_prosthetic(limb.owner, surgeon, tool, operation_args[OPERATION_TARGET_ZONE])
-/datum/surgery_operation/prosthetic_replacement/proc/handle_bodypart(mob/living/carbon/patient, mob/living/surgeon, obj/item/bodypart/bodypart_to_attach)
+/datum/surgery_operation/limb/prosthetic_replacement/proc/handle_bodypart(mob/living/carbon/patient, mob/living/surgeon, obj/item/bodypart/bodypart_to_attach)
bodypart_to_attach.try_attach_limb(patient)
if(bodypart_to_attach.check_for_frankenstein(patient))
bodypart_to_attach.bodypart_flags |= BODYPART_IMPLANTED
@@ -150,7 +124,7 @@
)
display_pain(patient, "You feel synthetic sensation wash from your [bodypart_to_attach.plaintext_zone], which you can feel again!", TRUE)
-/datum/surgery_operation/prosthetic_replacement/proc/handle_arbitrary_prosthetic(mob/living/carbon/patient, mob/living/surgeon, obj/item/thing_to_attach, target_zone)
+/datum/surgery_operation/limb/prosthetic_replacement/proc/handle_arbitrary_prosthetic(mob/living/carbon/patient, mob/living/surgeon, obj/item/thing_to_attach, target_zone)
SSblackbox.record_feedback("tally", "arbitrary_prosthetic", 1, initial(thing_to_attach.name))
var/obj/item/bodypart/new_limb = patient.make_item_prosthetic(thing_to_attach, target_zone, 80)
new_limb.add_surgical_state(SURGERY_PROSTHETIC_UNSECURED)
@@ -187,8 +161,7 @@
span_notice("[surgeon] begins to [tool.singular_name] [limb] to [limb.owner]'s body."),
span_notice("[surgeon] begins to [tool.singular_name] something to [limb.owner]'s body."),
)
- var/obj/item/bodypart/chest = limb.owner.get_bodypart(BODY_ZONE_CHEST)
- display_pain(limb.owner, "[surgeon] begins to [tool.singular_name] [limb] to your body!", IS_ROBOTIC_LIMB(chest))
+ display_pain(limb.owner, "[surgeon] begins to [tool.singular_name] [limb] to your body!", IS_ROBOTIC_LIMB(limb))
/datum/surgery_operation/limb/secure_arbitrary_prosthetic/on_success(obj/item/bodypart/limb, mob/living/surgeon, obj/item/stack/medical/tool, list/operation_args)
display_results(
@@ -198,8 +171,7 @@
span_notice("[surgeon] finishes [tool.apply_verb] [limb] to [limb.owner]'s body."),
span_notice("[surgeon] finishes the [tool.apply_verb] procedure!"),
)
- var/obj/item/bodypart/chest = limb.owner.get_bodypart(BODY_ZONE_CHEST)
- display_pain(limb.owner, "You feel more secure as your prosthetic is firmly attached to your body!", IS_ROBOTIC_LIMB(chest))
+ display_pain(limb.owner, "You feel more secure as your prosthetic is firmly attached to your body!", IS_ROBOTIC_LIMB(limb))
limb.remove_surgical_state(SURGERY_PROSTHETIC_UNSECURED)
limb.AddComponent(/datum/component/item_as_prosthetic_limb, null, 0) // updates drop probability to zero
tool.use(1)
diff --git a/code/modules/surgery/operations/operation_generic.dm b/code/modules/surgery/operations/operation_generic.dm
index 8288971a4a5..fac2fcdc051 100644
--- a/code/modules/surgery/operations/operation_generic.dm
+++ b/code/modules/surgery/operations/operation_generic.dm
@@ -21,6 +21,7 @@
success_sound = 'sound/items/handling/surgery/scalpel2.ogg'
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NO_PATIENT_REQUIRED
any_surgery_states_blocked = ALL_SURGERY_SKIN_STATES
+ allow_stumps = TRUE
/// We can't cut mobs with this biostate
var/biostate_blacklist = BIO_CHITIN
@@ -115,6 +116,7 @@
preop_sound = 'sound/items/handling/surgery/retractor1.ogg'
success_sound = 'sound/items/handling/surgery/retractor2.ogg'
all_surgery_states_required = SURGERY_SKIN_CUT
+ allow_stumps = TRUE
/datum/surgery_operation/limb/retract_skin/get_default_radial_image()
return image(/obj/item/retractor)
@@ -165,6 +167,7 @@
/obj/item = 'sound/items/handling/surgery/cautery2.ogg',
)
any_surgery_states_required = ALL_SURGERY_SKIN_STATES
+ allow_stumps = TRUE
/datum/surgery_operation/limb/close_skin/get_any_tool()
return "Any heat source"
@@ -225,6 +228,7 @@
time = 2.4 SECONDS
preop_sound = 'sound/items/handling/surgery/hemostat1.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_UNCLAMPED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/clamp_bleeders/get_default_radial_image()
return image(/obj/item/hemostat)
@@ -268,6 +272,7 @@
time = 2.4 SECONDS
preop_sound = 'sound/items/handling/surgery/hemostat1.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/unclamp_bleeders/get_default_radial_image()
return image(/obj/item/hemostat)
@@ -325,6 +330,7 @@
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NO_PATIENT_REQUIRED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_BONE_SAWED|SURGERY_BONE_DRILLED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/saw_bones/get_any_tool()
return "Any sharp edged item with decent force"
@@ -381,6 +387,7 @@
time = 4 SECONDS
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_required = SURGERY_BONE_SAWED|SURGERY_BONE_DRILLED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/fix_bones/get_default_radial_image()
return image(/obj/item/stack/medical/bone_gel)
@@ -425,6 +432,7 @@
success_sound = 'sound/items/handling/surgery/organ2.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_BONE_SAWED|SURGERY_BONE_DRILLED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/drill_bones/get_any_tool()
return "Any sharp pointed item with decent force"
@@ -477,6 +485,7 @@
success_sound = 'sound/items/handling/surgery/organ1.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_ORGANS_CUT
+ allow_stumps = TRUE
/datum/surgery_operation/limb/incise_organs/get_any_tool()
return "Any sharp edged item"
diff --git a/code/modules/surgery/operations/operation_generic_mechanic.dm b/code/modules/surgery/operations/operation_generic_mechanic.dm
index bbcdfd55fd2..54a97c7348c 100644
--- a/code/modules/surgery/operations/operation_generic_mechanic.dm
+++ b/code/modules/surgery/operations/operation_generic_mechanic.dm
@@ -16,6 +16,7 @@
preop_sound = 'sound/items/tools/screwdriver.ogg'
success_sound = 'sound/items/tools/screwdriver2.ogg'
any_surgery_states_blocked = ALL_SURGERY_SKIN_STATES
+ allow_stumps = TRUE
/datum/surgery_operation/limb/mechanical_incision/get_any_tool()
return "Any sharp item"
@@ -56,6 +57,7 @@
preop_sound = 'sound/items/tools/ratchet.ogg'
success_sound = 'sound/machines/airlock/doorclick.ogg'
all_surgery_states_required = SURGERY_SKIN_CUT
+ allow_stumps = TRUE
/datum/surgery_operation/limb/mechanical_open/get_default_radial_image()
return image('icons/hud/screen_gen.dmi', "arrow_large_still")
@@ -93,6 +95,7 @@
preop_sound = 'sound/items/tools/screwdriver.ogg'
success_sound = 'sound/items/tools/screwdriver2.ogg'
any_surgery_states_required = ALL_SURGERY_SKIN_STATES
+ allow_stumps = TRUE
/datum/surgery_operation/limb/mechanical_close/get_any_tool()
return "Any sharp item"
@@ -137,6 +140,7 @@
success_sound = 'sound/items/taperecorder/taperecorder_close.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_ORGANS_CUT
+ allow_stumps = TRUE
/datum/surgery_operation/limb/prepare_electronics/get_default_radial_image()
return image(/obj/item/multitool)
@@ -170,6 +174,7 @@
preop_sound = 'sound/items/tools/ratchet.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_BONE_SAWED|SURGERY_BONE_DRILLED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/mechanic_unwrench/get_default_radial_image()
return image(/obj/item/wrench)
@@ -198,10 +203,11 @@
TOOL_WRENCH = 1,
TOOL_RETRACTOR = 1.33,
)
- operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
+ operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
time = 2.4 SECONDS
preop_sound = 'sound/items/tools/ratchet.ogg'
- all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED | OPERATION_NO_PATIENT_REQUIRED
+ all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
+ allow_stumps = TRUE
/datum/surgery_operation/limb/mechanic_wrench/state_check(obj/item/bodypart/limb)
return LIMB_HAS_BONES(limb)
diff --git a/code/modules/surgery/surgery_tools.dm b/code/modules/surgery/surgery_tools.dm
index ed1218394a7..69f97210b30 100644
--- a/code/modules/surgery/surgery_tools.dm
+++ b/code/modules/surgery/surgery_tools.dm
@@ -591,7 +591,7 @@
/obj/item/shears/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] is pinching [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
var/timer = 1 SECONDS
- for(var/obj/item/bodypart/thing in user.bodyparts)
+ for(var/obj/item/bodypart/thing in user.get_bodyparts())
if(thing.body_part == CHEST)
continue
addtimer(CALLBACK(thing, TYPE_PROC_REF(/obj/item/bodypart/, dismember)), timer)
diff --git a/code/modules/unit_tests/limbsanity.dm b/code/modules/unit_tests/limbsanity.dm
index 6efec37ab76..13f6a4d7d35 100644
--- a/code/modules/unit_tests/limbsanity.dm
+++ b/code/modules/unit_tests/limbsanity.dm
@@ -1,8 +1,11 @@
/datum/unit_test/limbsanity
/datum/unit_test/limbsanity/Run()
- for(var/path in subtypesof(/obj/item/bodypart) - list(/obj/item/bodypart/arm, /obj/item/bodypart/leg)) /// removes the abstract items.
+ for(var/path in valid_subtypesof(/obj/item/bodypart)) /// removes the abstract items.
var/obj/item/bodypart/part = path
+ if(part::bodypart_flags & BODYPART_STUMP)
+ continue // stumps don't need to have icons
+
if(part::is_dimorphic)
if(!icon_exists(UNLINT(part::should_draw_greyscale ? part::icon_greyscale : part::icon_static), "[part::limb_id]_[part::body_zone]_m"))
TEST_FAIL("[path] does not have a valid icon for male variants")
diff --git a/code/modules/unit_tests/organ_bodypart_shuffle.dm b/code/modules/unit_tests/organ_bodypart_shuffle.dm
index e05c6bd0bd9..ffb2210756a 100644
--- a/code/modules/unit_tests/organ_bodypart_shuffle.dm
+++ b/code/modules/unit_tests/organ_bodypart_shuffle.dm
@@ -20,7 +20,7 @@
TEST_ASSERT_NULL(organ.bodypart_owner, "Organ '[organ.name] kept reference to bodypart after forceMove into nullspace.")
// 3. replace all bodyparts with new ones and place the previously removed organs into the new bodyparts
- for(var/obj/item/bodypart/bodypart as anything in hollow_boy.bodyparts)
+ for(var/obj/item/bodypart/bodypart as anything in hollow_boy.get_bodyparts())
var/obj/item/bodypart/replacement = allocate(bodypart.type)
for(var/obj/item/organ/organ as anything in removed_organs)
if(replacement.body_zone != deprecise_zone(organ.zone))
@@ -35,3 +35,22 @@
TEST_ASSERT(organ in hollow_boy.organs, "Organ '[organ.name] was put in an empty bodypart that replaced a humans, but the organ did not come with.")
TEST_ASSERT(organ.owner == hollow_boy, "Organ '[organ.name]'s owner was not properly updated to the new human after being placed in a replacement bodypart.")
TEST_ASSERT(organ.bodypart_owner in hollow_boy.bodyparts, "Organ '[organ.name]'s bodypart_owner was not properly updated to the new bodypart after being placed in a replacement bodypart.")
+
+/// Tests that gibbing results in a head with a brain
+/datum/unit_test/gibbing_organ_transfer
+
+/datum/unit_test/gibbing_organ_transfer/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+ var/list/bodyparts_for_cleanup = dummy.bodyparts.Copy()
+ var/list/organs_for_cleanup = dummy.organs.Copy()
+ var/obj/item/organ/brain/original_brain = dummy.get_organ_slot(ORGAN_SLOT_BRAIN)
+ var/obj/item/bodypart/head/original_head = dummy.get_bodypart(BODY_ZONE_HEAD)
+ dummy.gib(ALL)
+
+ TEST_ASSERT(QDELETED(dummy), "Dummy was not deleted after gibbing.")
+ TEST_ASSERT(!QDELETED(original_head), "Original head was deleted after gibbing.")
+ TEST_ASSERT(!QDELETED(original_brain), "Original brain was deleted after gibbing.")
+ TEST_ASSERT(original_brain.loc == original_head, "Original brain was not transferred to the head after gibbing.")
+
+ QDEL_LIST(organs_for_cleanup)
+ QDEL_LIST(bodyparts_for_cleanup)
diff --git a/code/modules/unit_tests/spawn_humans.dm b/code/modules/unit_tests/spawn_humans.dm
index f89f59a4cbf..a0691b16c87 100644
--- a/code/modules/unit_tests/spawn_humans.dm
+++ b/code/modules/unit_tests/spawn_humans.dm
@@ -14,3 +14,23 @@
TEST_ASSERT(!HAS_TRAIT_FROM(dummy, TRAIT_AGEUSIA, NO_TONGUE_TRAIT), "Dummy has ageusia on init, when it should've been removed by its default tongue.")
TEST_ASSERT(!dummy.is_blind_from(NO_EYES), "Dummy is blind on init, when it should've been removed by its default eyes.")
TEST_ASSERT(!HAS_TRAIT_FROM(dummy, TRAIT_DEAF, NO_EARS), "Dummy is deaf on init, when it should've been removed by its default ears.")
+
+/// Tests that we can change a mob's hand count without everything breaking
+/datum/unit_test/many_armed_humans
+
+/datum/unit_test/many_armed_humans/Run()
+ var/mob/living/carbon/human/consistent/dummy = allocate(/mob/living/carbon/human/consistent)
+ dummy.change_number_of_hands(4)
+
+/// Tests spawned humans have the correct bodypart order
+/datum/unit_test/human_bodypart_order
+
+/datum/unit_test/human_bodypart_order/Run()
+ var/mob/living/carbon/human/consistent/dummy = allocate(/mob/living/carbon/human/consistent)
+ var/list/obj/item/bodypart/bodyparts = dummy.get_bodyparts()
+ TEST_ASSERT(bodyparts[1].body_zone == BODY_ZONE_CHEST, "First bodypart in bodyparts list is not the chest, this is important for human rendering")
+ TEST_ASSERT(bodyparts[2].body_zone == BODY_ZONE_HEAD, "Second bodypart in bodyparts list is not the head, this is important for human rendering")
+
+ var/list/obj/item/bodypart/bodyparts_by_zone = dummy.get_bodyparts_by_zones()
+ TEST_ASSERT(bodyparts_by_zone[1] == BODY_ZONE_CHEST, "First bodypart in bodyparts_by_zone list is not the chest, this is important for human rendering")
+ TEST_ASSERT(bodyparts_by_zone[2] == BODY_ZONE_HEAD, "Second bodypart in bodyparts_by_zone list is not the head, this is important for human rendering")
diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm
index 69bc29fb148..7a538da8fbb 100644
--- a/code/modules/unit_tests/surgeries.dm
+++ b/code/modules/unit_tests/surgeries.dm
@@ -57,9 +57,9 @@
TEST_ASSERT_EQUAL(bobs_head.real_name, "Bob", "Bob's head does not remember that it is from Bob")
// Put Bob's head onto Alice's body
- var/datum/surgery_operation/prosthetic_replacement/surgery = GLOB.operations.operations_by_typepath[__IMPLIED_TYPE__]
+ var/datum/surgery_operation/limb/prosthetic_replacement/surgery = GLOB.operations.operations_by_typepath[__IMPLIED_TYPE__]
user.put_in_active_hand(bobs_head)
- UNLINT(surgery.success(alice.get_bodypart(BODY_ZONE_CHEST), user, bobs_head, list()))
+ UNLINT(surgery.success(alice.get_bodypart(BODY_ZONE_HEAD, TRUE), user, bobs_head, list()))
TEST_ASSERT(!isnull(alice.get_bodypart(BODY_ZONE_HEAD)), "Alice has no head after prosthetic replacement")
TEST_ASSERT_EQUAL(alice.get_visible_name(), "Bob", "Bob's head was transplanted onto Alice's body, but their name is not Bob")
diff --git a/code/modules/vehicles/cars/clowncar.dm b/code/modules/vehicles/cars/clowncar.dm
index 0672586220c..6cff8a743f6 100644
--- a/code/modules/vehicles/cars/clowncar.dm
+++ b/code/modules/vehicles/cars/clowncar.dm
@@ -143,14 +143,16 @@
for(var/mob/living/carbon/carbon_occupant in occupants)
if(prob(35)) //Note: The randomstep on dump_mobs throws occupants into each other and often causes wounds regardless.
continue
- for(var/obj/item/bodypart/head/head_to_wound as anything in carbon_occupant.bodyparts)
- var/pick_mode = text2num(pick(list(
- "[WOUND_PICK_LOWEST_SEVERITY]",
- "[WOUND_PICK_HIGHEST_SEVERITY]"
- )))
- carbon_occupant.cause_wound_of_type_and_severity(WOUND_BLUNT, head_to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, pick_mode)
- carbon_occupant.playsound_local(src, 'sound/items/weapons/flash_ring.ogg', 50)
- carbon_occupant.set_eye_blur_if_lower(rand(10 SECONDS, 20 SECONDS))
+ var/obj/item/bodypart/head/head_to_wound = carbon_occupant.get_bodypart(BODY_ZONE_HEAD)
+ if(isnull(head_to_wound))
+ return
+ var/pick_mode = text2num(pick(list(
+ "[WOUND_PICK_LOWEST_SEVERITY]",
+ "[WOUND_PICK_HIGHEST_SEVERITY]"
+ )))
+ carbon_occupant.cause_wound_of_type_and_severity(WOUND_BLUNT, head_to_wound, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, pick_mode)
+ carbon_occupant.playsound_local(src, 'sound/items/weapons/flash_ring.ogg', 50)
+ carbon_occupant.set_eye_blur_if_lower(rand(10 SECONDS, 20 SECONDS))
hittarget_living.add_splatter_floor(small_drip = FALSE)
hittarget_living.adjust_brute_loss(200)
diff --git a/code/modules/vending/vendor/tilting.dm b/code/modules/vending/vendor/tilting.dm
index 1d7d899c0ea..971633c683b 100644
--- a/code/modules/vending/vendor/tilting.dm
+++ b/code/modules/vending/vendor/tilting.dm
@@ -180,7 +180,7 @@
if (!iscarbon(atom_target))
return FALSE
var/mob/living/carbon/carbon_target = atom_target
- for(var/obj/item/bodypart/squish_part in carbon_target.bodyparts)
+ for(var/obj/item/bodypart/squish_part in carbon_target.get_bodyparts())
var/severity = pick(WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_SEVERE, WOUND_SEVERITY_CRITICAL)
if (!carbon_target.cause_wound_of_type_and_severity(WOUND_BLUNT, squish_part, severity, wound_source = "crushed by [src]"))
squish_part.receive_damage(brute = 30)
diff --git a/tgstation.dme b/tgstation.dme
index da8503ddcfc..67e316b9900 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -6434,6 +6434,7 @@
#include "code\modules\surgery\bodyparts\helpers.dm"
#include "code\modules\surgery\bodyparts\parts.dm"
#include "code\modules\surgery\bodyparts\robot_bodyparts.dm"
+#include "code\modules\surgery\bodyparts\stumps.dm"
#include "code\modules\surgery\bodyparts\worn_feature_offset.dm"
#include "code\modules\surgery\bodyparts\wounds.dm"
#include "code\modules\surgery\bodyparts\species_parts\android_parts.dm"