Files
1467508036 Teshari Specific Limb Damage States and Bloody Clothing (#6038)
## About The Pull Request
Teshari have long had to deal with ill-fitting overlays applied to them.
I have chosen to bite the bullet and do the labour by creating species
specific states for:
- bloody clothes
- damaged clothes
- body wounds
- bleeding animations

How it works is simple: if our icon override exists for our species, we
use it. If it doesn't exist, we default back to the original. What this
means is that future species overrides can be added without code
changes.

## Why It's Good For The Game
<img width="91" height="85" alt="image"
src="https://github.com/user-attachments/assets/30f1c91a-27aa-441e-9026-8d441855e7b9"
/>

This sucks! They look like they're wearing clown shoes for crying out
loud!


<img width="88" height="91" alt="image"
src="https://github.com/user-attachments/assets/0aa2febd-728b-4108-b64d-56173958cf27"
/>

This doesn't suck!

</details>

## Changelog

🆑 Robwo
fix: Teshari can now get properly bloody and bruised.
/🆑

---------

Co-authored-by: Alexis <catmc8565@gmail.com>
Co-authored-by: Waterpig <49160555+Maia-J@users.noreply.github.com>
2026-08-15 18:12:22 +02:00

596 lines
21 KiB
Plaintext

/obj/item/clothing/under
name = "under"
icon = 'icons/obj/clothing/under/default.dmi'
worn_icon = 'icons/mob/clothing/under/default.dmi'
lefthand_file = 'icons/mob/inhands/clothing/suits_lefthand.dmi'
righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi'
abstract_type = /obj/item/clothing/under
body_parts_covered = CHEST|GROIN|LEGS|ARMS
slot_flags = ITEM_SLOT_ICLOTHING
interaction_flags_click = NEED_DEXTERITY|ALLOW_RESTING
armor_type = /datum/armor/clothing_under
supports_variations_flags = CLOTHING_DIGITIGRADE_MASK
bodyshapes_with_variations = BODYSHAPE_DIGITIGRADE
equip_sound = 'sound/items/equip/jumpsuit_equip.ogg'
drop_sound = 'sound/items/handling/cloth/cloth_drop1.ogg'
pickup_sound = 'sound/items/handling/cloth/cloth_pickup1.ogg'
limb_integrity = 30
/// Has this undersuit been freshly laundered and, as such, imparts a mood bonus for wearing
var/freshly_laundered = FALSE
// Alt style handling
/// Can this suit be adjustd up or down to an alt style
var/can_adjust = TRUE
/// If adjusted what style are we currently using?
var/adjusted = NORMAL_STYLE
/// For adjusted/rolled-down jumpsuits. FALSE = exposes chest and arms, TRUE = exposes arms only
var/alt_covers_chest = FALSE
/// The variable containing the flags for how the woman uniform cropping is supposed to interact with the sprite.
var/female_sprite_flags = FEMALE_UNIFORM_FULL
// Sensor handling
/// Does this undersuit have suit sensors in general
var/has_sensor = HAS_SENSORS
/// Does this undersuit spawn with a random sensor value
var/random_sensor = TRUE
/// What is the active sensor mode of this udnersuit
var/sensor_mode = SENSOR_OFF
// Accessory handling (Can be componentized eventually)
/// The max number of accessories we can have on this suit.
var/max_number_of_accessories = 5
/// A list of all accessories attached to us.
var/list/obj/item/clothing/accessory/attached_accessories
/datum/armor/clothing_under
bio = 10
wound = 5
/obj/item/clothing/under/Initialize(mapload)
. = ..()
if(random_sensor)
//make the sensor mode favor higher levels, except coords.
set_sensor_mode(pick(SENSOR_VITALS, SENSOR_VITALS, SENSOR_VITALS, SENSOR_LIVING, SENSOR_LIVING, SENSOR_COORDS, SENSOR_COORDS, SENSOR_OFF))
//ensure we add or remove relevant clothing traits based on base sensor status and mode
update_wearer_status()
register_context()
AddElement(/datum/element/update_icon_updates_onmob, flags = ITEM_SLOT_ICLOTHING|ITEM_SLOT_OCLOTHING|ITEM_SLOT_NECK, body = TRUE)
/obj/item/clothing/under/on_craft_completion(list/components, datum/crafting_recipe/current_recipe, atom/crafter)
. = ..()
var/obj/item/clothing/under/any_original = locate() in components
if(!any_original)
set_has_sensor(NO_SENSORS)
return
set_has_sensor(any_original.has_sensor)
set_sensor_mode(any_original.sensor_mode)
/obj/item/clothing/under/used_in_craft(atom/result, datum/crafting_recipe/current_recipe)
. = ..()
dump_attachments()
/obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
. = ..()
var/changed = FALSE
if(has_sensor == HAS_SENSORS && (isnull(held_item) || held_item == src))
context[SCREENTIP_CONTEXT_RMB] = "Toggle suit sensors"
context[SCREENTIP_CONTEXT_CTRL_LMB] = "Set suit sensors to tracking"
changed = TRUE
if(istype(held_item, /obj/item/clothing/accessory) && length(attached_accessories) < max_number_of_accessories)
context[SCREENTIP_CONTEXT_LMB] = "Attach accessory"
changed = TRUE
if(LAZYLEN(attached_accessories))
context[SCREENTIP_CONTEXT_ALT_RMB] = "Remove accessory"
changed = TRUE
if(has_sensor == BROKEN_SENSORS && istype(held_item, /obj/item/stack/cable_coil))
context[SCREENTIP_CONTEXT_LMB] = "Repair suit sensors"
changed = TRUE
if(has_sensor == NO_SENSORS)
if(istype(held_item, /obj/item/suit_sensor))
context[SCREENTIP_CONTEXT_LMB] = "Install suit sensors"
changed = TRUE
else if(held_item?.tool_behaviour == TOOL_WIRECUTTER)
context[SCREENTIP_CONTEXT_LMB] = "Cut suit sensors"
changed = TRUE
if(can_adjust && adjusted != DIGITIGRADE_STYLE)
context[SCREENTIP_CONTEXT_ALT_LMB] = "Wear [adjusted == ALT_STYLE ? "normally" : "casually"]"
changed = TRUE
return changed ? CONTEXTUAL_SCREENTIP_SET : .
/obj/item/clothing/under/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file, bodyshape = NONE, file2use = null, mutant_styles = NONE) // SKYRAT EDIT - customisation
. = ..()
if(isinhands)
return
if(damaged_clothes)
//BUBBER EDIT BEGIN
//. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") //ORIGINAL
var/mob/living/carbon/human/wearer = loc
if(ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damageduniform_[wearer.dna.species.id]"))
. += mutable_appearance('modular_zubbers/icons/effects/item_damage_species.dmi', "damageduniform_[wearer.dna.species.id]")
else
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
//BUBBER EDIT END
. += get_accessory_overlays()
/obj/item/clothing/under/separate_worn_overlays(mutable_appearance/standing, mutable_appearance/draw_target, isinhands = FALSE, icon_file, bodyshape = NONE)
. = ..()
if (isinhands)
return
var/blood_overlay = get_blood_overlay("uniform", bodyshape)
if (blood_overlay)
. += blood_overlay
/obj/item/clothing/under/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(istype(tool, /obj/item/stack/cable_coil))
if(!repair_sensors(user))
return ITEM_INTERACT_BLOCKING
var/obj/item/stack/cable_coil/cabling = tool
cabling.use(1)
cabling.visible_message(span_notice("[user] repairs the suit sensors on [src] with [cabling]."))
return ITEM_INTERACT_SUCCESS
if(istype(tool, /obj/item/clothing/accessory))
return attach_accessory(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
if(istype(tool, /obj/item/suit_sensor))
if(has_sensor != NO_SENSORS)
balloon_alert(user, "already has sensors!")
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "installing sensors...")
if(!do_after(user, 5 SECONDS, target = src))
return ITEM_INTERACT_BLOCKING
var/obj/item/suit_sensor/sensor = tool
if(sensor.broken)
set_has_sensor(BROKEN_SENSORS)
else
set_has_sensor(HAS_SENSORS)
set_sensor_mode(sensor.sensor_mode)
qdel(tool)
balloon_alert(user, "sensors installed")
playsound(source = src, soundin = 'sound/effects/sparks/sparks4.ogg', vol = 50, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
return ITEM_INTERACT_SUCCESS
return ..()
/obj/item/clothing/under/wirecutter_act(mob/living/user, obj/item/tool)
if(has_sensor == NO_SENSORS)
balloon_alert(user, "doesn't have sensors!")
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "cutting out sensors...")
if(!do_after(user, 5 SECONDS, target = src))
return ITEM_INTERACT_BLOCKING
var/obj/item/suit_sensor/sensor = new (drop_location())
if(sensor.IsReachableBy(user))
user.put_in_hands(sensor)
if(has_sensor == BROKEN_SENSORS)
sensor.broken = TRUE
else
sensor.set_mode(sensor_mode)
set_has_sensor(NO_SENSORS)
return ITEM_INTERACT_SUCCESS
/obj/item/clothing/under/attack_hand_secondary(mob/user, params)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
toggle()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/clothing/under/attack_self_secondary(mob/user, modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
toggle()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/clothing/under/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
. = ..()
if(damaged_state == CLOTHING_SHREDDED && has_sensor > NO_SENSORS)
break_sensors()
else if(damaged_state == CLOTHING_PRISTINE && has_sensor == BROKEN_SENSORS)
repair_sensors()
update_appearance()
/obj/item/clothing/under/visual_equipped(mob/user, slot)
. = ..()
if(adjusted == ALT_STYLE)
adjust_to_normal()
/* SKYRAT EDIT REMOVAL - This breaks jumpsuit adjustment. Plus, we don't support it.
if((supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && ishuman(user))
var/mob/living/carbon/human/wearer = user
if(wearer.bodyshape & BODYSHAPE_DIGITIGRADE)
adjusted = DIGITIGRADE_STYLE
update_appearance()
*/ // SKYRAT EDIT END
/obj/item/clothing/under/generate_digitigrade_icons(icon/base_icon, greyscale_colors)
var/icon/legs = icon(SSgreyscale.GetColoredIconByType(/datum/greyscale_config/digitigrade, greyscale_colors), "jumpsuit_worn")
return replace_icon_legs(base_icon, legs)
/obj/item/clothing/under/machine_wash()
. = ..()
if(stubborn_stains)
return
var/fresh_mood = AddComponent( \
/datum/component/onwear_mood, \
saved_event_type = /datum/mood_event/fresh_laundry, \
)
QDEL_IN(fresh_mood, 2 MINUTES)
/obj/item/clothing/under/equipped(mob/living/user, slot)
..()
if(slot & ITEM_SLOT_ICLOTHING)
if(freshly_laundered)
freshly_laundered = FALSE
user.add_mood_event("fresh_laundry", /datum/mood_event/fresh_laundry)
update_wearer_status()
/obj/item/clothing/under/dropped(mob/living/user)
. = ..()
if(user.get_item_by_slot(ITEM_SLOT_ICLOTHING) == src)
GLOB.suit_sensors_list -= user
// Start suit sensor handling
/// Change the suit sensor state to broken and update the mob's status on the global sensor list
/obj/item/clothing/under/proc/break_sensors()
if(has_sensor == BROKEN_SENSORS || has_sensor == NO_SENSORS)
return
visible_message(span_warning("[src]'s medical sensors short out!"), blind_message = span_warning("The [src] makes an electronic sizzling sound!"), vision_distance = COMBAT_MESSAGE_RANGE)
set_has_sensor(BROKEN_SENSORS)
sensor_malfunction()
/**
* Repair the suit sensors and update the mob's status on the global sensor list.
* Can be called either through player action such as repairing with coil, or as part of a general fixing proc
*/
/obj/item/clothing/under/proc/repair_sensors(mob/user)
if(has_sensor != BROKEN_SENSORS)
if(user)
balloon_alert(user, "sensors [has_sensor == NO_SENSORS ? "missing" : "not broken"]!")
return FALSE
playsound(source = src, soundin = 'sound/effects/sparks/sparks4.ogg', vol = 100, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
set_has_sensor(HAS_SENSORS)
return TRUE
/// If the item is being worn, a gentle reminder every 3-5 minutes that the sensors are broken
/obj/item/clothing/under/proc/sensor_malfunction()
if(!QDELETED(src) && has_sensor == BROKEN_SENSORS && ishuman(loc))
do_sparks(number = 2, cardinal_only = FALSE, source = src)
addtimer(CALLBACK(src, PROC_REF(sensor_malfunction)), rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX * 0.5), TIMER_UNIQUE | TIMER_NO_HASH_WAIT)
/// Changes whether the suit sensor has a sensor, or if it's broken, etc. and handles updating mob status if applicable
/obj/item/clothing/under/proc/set_has_sensor(new_has_sensor)
if(new_has_sensor == has_sensor)
return FALSE
if(new_has_sensor < BROKEN_SENSORS || new_has_sensor > LOCKED_SENSORS)
stack_trace("Invalid has_sensor value [new_has_sensor] passed to set_has_sensor()")
return FALSE
has_sensor = new_has_sensor
update_wearer_status()
return TRUE
/// Changes the active sensor mode of the suit and handles updating mob status if applicable
/obj/item/clothing/under/proc/set_sensor_mode(new_sensor_mode)
if(new_sensor_mode == sensor_mode)
return FALSE
if(new_sensor_mode < SENSOR_OFF || new_sensor_mode > SENSOR_COORDS)
stack_trace("Invalid sensor_mode value [new_sensor_mode] passed to set_sensor_mode()")
return FALSE
sensor_mode = new_sensor_mode
update_wearer_status()
return TRUE
/// Updates the sensor status and any mobs status if applicable
/obj/item/clothing/under/proc/update_wearer_status()
if(has_sensor <= NO_SENSORS || sensor_mode <= SENSOR_VITALS)
detach_clothing_traits(TRAIT_BASIC_HEALTH_HUD_VISIBLE)
else
attach_clothing_traits(TRAIT_BASIC_HEALTH_HUD_VISIBLE)
if(!ishuman(loc) || isdummy(loc))
return
var/mob/living/carbon/human/wearer = loc
if(wearer.get_item_by_slot(ITEM_SLOT_ICLOTHING) != src)
return
if(has_sensor >= HAS_SENSORS && sensor_mode >= SENSOR_LIVING)
GLOB.suit_sensors_list |= wearer
else
GLOB.suit_sensors_list -= wearer
wearer.med_hud_set_status()
/* BUBBERSTATION CHANGE: REWORKS SENSOR EMP
/obj/item/clothing/under/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
if(has_sensor == NO_SENSORS || has_sensor == BROKEN_SENSORS)
return
if(severity <= EMP_HEAVY)
break_sensors()
return
set_sensor_mode(pick(SENSOR_OFF, SENSOR_OFF, SENSOR_OFF, SENSOR_LIVING, SENSOR_LIVING, SENSOR_VITALS, SENSOR_VITALS, SENSOR_COORDS))
playsound(source = src, soundin = 'sound/effects/sparks/sparks3.ogg', vol = 75, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE, ignore_walls = FALSE)
visible_message(span_warning("The [src]'s medical sensors flash and change rapidly!"), blind_message = span_warning("The [src] makes an electronic sizzling sound!"), vision_distance = COMBAT_MESSAGE_RANGE)
BUBBERSTATION CHANGE END */
/**
* Called by medical scanners a simple summary of the status
*
* Arguments:
* * silent: If TRUE, will return blank if everything is fine
*/
/obj/item/clothing/under/proc/get_sensor_text(silent = TRUE)
if(has_sensor == BROKEN_SENSORS)
return "<font color='#ffcc33'>Non-Functional: Repair with cable coil</font>"
if(silent)
return ""
switch(has_sensor)
if(NO_SENSORS)
return "Not Present"
if(LOCKED_SENSORS)
return "Functional, Locked"
if(HAS_SENSORS)
return "Functional"
// End suit sensor handling
/// Attach the passed accessory to the clothing item
/obj/item/clothing/under/proc/attach_accessory(obj/item/clothing/accessory/accessory, mob/living/user, attach_message = TRUE)
if(!istype(accessory))
return
if(!accessory.can_attach_accessory(src, user))
return
if(user && !user.temporarilyRemoveItemFromInventory(accessory))
return
if(!accessory.try_attach(src, user))
return
// Allow for accessories to react to the acccessory list now
accessory.attach(src)
if(user && attach_message)
balloon_alert(user, "accessory attached")
update_appearance()
return TRUE
/// Removes (pops) the topmost accessory from the accessories list and puts it in the user's hands if supplied
/obj/item/clothing/under/proc/pop_accessory(mob/living/user, attach_message = TRUE)
var/obj/item/clothing/accessory/popped_accessory = attached_accessories[1]
remove_accessory(popped_accessory)
if(!user)
return
user.put_in_hands(popped_accessory)
if(attach_message)
popped_accessory.balloon_alert(user, "accessory removed")
/// Removes the passed accesory from our accessories list
/obj/item/clothing/under/proc/remove_accessory(obj/item/clothing/accessory/removed, update = TRUE)
// Remove it from the list before detaching
LAZYREMOVE(attached_accessories, removed)
removed.detach(src, update)
/// Get a list of all accessory overlays
/obj/item/clothing/under/proc/get_accessory_overlays()
. = list()
for(var/obj/item/clothing/accessory/accessory as anything in attached_accessories)
. += accessory.generate_accessory_overlay(src)
/obj/item/clothing/under/Exited(atom/movable/gone, direction)
. = ..()
// If one of our accessories was moved out, handle it
if(gone in attached_accessories)
remove_accessory(gone)
/// Helper to remove all attachments to the passed location
/obj/item/clothing/under/proc/dump_attachments(atom/drop_to = drop_location())
for(var/obj/item/clothing/accessory/worn_accessory as anything in attached_accessories)
remove_accessory(worn_accessory, update = FALSE)
worn_accessory.forceMove(drop_to)
if (ishuman(loc))
var/mob/living/carbon/human/wearer = loc
wearer.update_clothing(slot_flags)
/obj/item/clothing/under/atom_destruction(damage_flag)
dump_attachments()
return ..()
/obj/item/clothing/under/Destroy()
QDEL_LAZYLIST(attached_accessories)
return ..()
/obj/item/clothing/under/examine(mob/user)
. = ..()
if(can_adjust)
. += "Alt-click on [src] to wear it [adjusted == ALT_STYLE ? "normally" : "casually"]."
if(has_sensor == BROKEN_SENSORS)
. += span_warning("The medical sensors appear to be shorted out. You could repair it with some cabling.")
else if(has_sensor > NO_SENSORS)
switch(sensor_mode)
if(SENSOR_OFF)
. += "Its sensors appear to be disabled."
if(SENSOR_LIVING)
. += "Its binary life sensors appear to be enabled."
if(SENSOR_VITALS)
. += "Its vital tracker appears to be enabled."
if(SENSOR_COORDS)
. += "Its vital tracker and tracking beacon appear to be enabled."
else
. += span_tooltip("You can always get new suit sensors to install from a lathe.", "It isn't equipped with medical sensors.")
if(LAZYLEN(attached_accessories))
var/list/accessories = list_accessories_with_icon(user)
. += "It has [english_list(accessories)] attached."
. += "Alt-Right-Click to remove [attached_accessories[1]]."
/// Helper to list out all accessories with an icon besides it, for use in examine
/obj/item/clothing/under/proc/list_accessories_with_icon(mob/user)
var/list/all_accessories = list()
for(var/obj/item/clothing/accessory/attached as anything in attached_accessories)
all_accessories += attached.examine_title(user)
return all_accessories
GAME_VERB_SRC(/obj/item/clothing/under, toggle, usr, "Adjust Suit Sensors", null)
var/mob/user_mob = usr
if(!can_toggle_sensors(user_mob))
return
var/current_mode_text = GLOB.suit_sensor_mode_to_defines[sensor_mode + 1]
var/new_mode = tgui_input_list(user_mob, "Select a sensor mode", "Suit Sensors", GLOB.suit_sensor_mode_to_defines, current_mode_text)
if(isnull(new_mode))
return
if(!can_toggle_sensors(user_mob))
return
set_sensor_mode(GLOB.suit_sensor_mode_to_defines[new_mode])
if (loc == user_mob)
switch(sensor_mode)
if(SENSOR_OFF)
to_chat(user_mob, span_notice("You disable your suit's remote sensing equipment."))
if(SENSOR_LIVING)
to_chat(user_mob, span_notice("Your suit will now only report whether you are alive or dead."))
if(SENSOR_VITALS)
to_chat(user_mob, span_notice("Your suit will now only report your exact vital lifesigns."))
if(SENSOR_COORDS)
to_chat(user_mob, span_notice("Your suit will now report your exact vital lifesigns as well as your coordinate position."))
/obj/item/clothing/under/item_ctrl_click(mob/user)
if(!can_toggle_sensors(user))
return CLICK_ACTION_BLOCKING
set_sensor_mode(SENSOR_COORDS)
balloon_alert(user, "set to tracking")
return CLICK_ACTION_SUCCESS
/// Checks if the toggler is allowed to toggle suit sensors currently
/obj/item/clothing/under/proc/can_toggle_sensors(mob/toggler)
if(!can_use(toggler) || toggler.stat == DEAD) //make sure they didn't hold the window open.
return FALSE
if(get_dist(toggler, src) > 1)
balloon_alert(toggler, "too far!")
return FALSE
switch(has_sensor)
if(LOCKED_SENSORS)
balloon_alert(toggler, "sensor controls locked!")
return FALSE
if(BROKEN_SENSORS)
balloon_alert(toggler, "sensors shorted!")
return FALSE
if(NO_SENSORS)
balloon_alert(toggler, "no sensors to adjust!")
return FALSE
return TRUE
/obj/item/clothing/under/click_alt(mob/user)
if(!can_adjust)
balloon_alert(user, "can't be adjusted!")
return CLICK_ACTION_BLOCKING
if(!can_use(user))
return NONE
rolldown()
return CLICK_ACTION_SUCCESS
/obj/item/clothing/under/click_alt_secondary(mob/user)
if(!LAZYLEN(attached_accessories))
balloon_alert(user, "no accessories to remove!")
return
pop_accessory(user)
GAME_VERB_SRC(/obj/item/clothing/under, jumpsuit_adjust, usr, "Adjust Jumpsuit Style", null)
if(!can_adjust)
balloon_alert(usr, "can't be adjusted!")
return
if(!can_use(usr))
return
rolldown()
/obj/item/clothing/under/proc/rolldown()
if(toggle_jumpsuit_adjust())
to_chat(usr, span_notice("You adjust the suit to wear it more casually."))
else
to_chat(usr, span_notice("You adjust the suit back to normal."))
update_appearance()
/// Helper to toggle the jumpsuit style, if possible
/// Returns the new state
/obj/item/clothing/under/proc/toggle_jumpsuit_adjust()
switch(adjusted)
if(DIGITIGRADE_STYLE)
return
if(NORMAL_STYLE)
adjust_to_alt()
if(ALT_STYLE)
adjust_to_normal()
SEND_SIGNAL(src, COMSIG_CLOTHING_UNDER_ADJUSTED)
return adjusted
/// Helper to reset to normal jumpsuit state
/obj/item/clothing/under/proc/adjust_to_normal()
adjusted = NORMAL_STYLE
female_sprite_flags = initial(female_sprite_flags)
if(!alt_covers_chest)
body_parts_covered |= CHEST
body_parts_covered |= ARMS
if(LAZYLEN(damage_by_parts))
// ugly check to make sure we don't reenable protection on a disabled part
for(var/zone in list(BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
if(damage_by_parts[zone] > limb_integrity)
body_parts_covered &= body_zone2cover_flags(zone)
/// Helper to adjust to alt jumpsuit state
/obj/item/clothing/under/proc/adjust_to_alt()
adjusted = ALT_STYLE
if(!(female_sprite_flags & FEMALE_UNIFORM_TOP_ONLY))
female_sprite_flags = NO_FEMALE_UNIFORM
if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted (and also the arms, realistically)
body_parts_covered &= ~CHEST
body_parts_covered &= ~ARMS
/obj/item/clothing/under/can_use(mob/user)
if(ismob(user) && !user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING))
return FALSE
return ..()
/obj/item/clothing/under/rank
abstract_type = /obj/item/clothing/under/rank
dying_key = DYE_REGISTRY_UNDER