Files
BatrachophrenoandGitHub 8111a8489b Restore many missing inhand sprites for items, add/port others (#21831)
Many, many, many items have inhand sprites in their .dmis but for
whatever reasons do not display them in-game. This PR:

1. Updates many item definitions to point to their already-existing
inhands correctly. This consists largely of held tools, but also gas
tanks and jetpacks mounted in the suit storage slot.

2. Adds a few codersprites made by me for objects with either missing
inhands or poorly matching mishands (IE, the tape recorder, which has a
black case, reused the white inhand sprites of the health analyzer). The
new sprites are modified or recolored variations of other inhand sprites
from our repo, except for circuitboards which are new.
<img width="444" height="400" alt="image"
src="https://github.com/user-attachments/assets/7f107b9a-fe24-4e31-8f16-4d34768ee117"
/>


3. Adds inhand sprites for Inflatables and Inflatable Boxes made by
Tomixcomics.
<img width="424" height="101" alt="image"
src="https://github.com/user-attachments/assets/434107c4-8577-49a2-a58e-d6b014c03933"
/>

4. Ports inhand sprites for the Hydraulic Rescue Tool from tg's Jaws of
Life.
<img width="224" height="94" alt="Screenshot 2026-02-07 172931"
src="https://github.com/user-attachments/assets/070c7956-f6a8-4fb5-870f-10c64afcc8b3"
/>

5. Some additional cleanup while in the area. The 'analyzer' has been
renamed the 'gas analyzer' to be consistent with the other analyzer
objects, standardized icon_state naming conventions where I saw
oddballs, updated code docs to use DMDocs when in the area, etc.

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| icons/obj/item/hydraulic_rescue_tool.dmi | [SomeAngryMiner (bee
station)](https://github.com/BeeStation/BeeStation-Hornet/pull/2487),
[maxymax
(/tg/station)](https://github.com/tgstation/tgstation/pull/58616) |
CC-BY-SA |
| icons/obj/item/inflatables.dmi |
[Tomixcomics](https://github.com/tomixcomics) | CC-BY-SA |
2026-02-17 17:51:22 +00:00

1678 lines
54 KiB
Plaintext

// Human caches have been moved to SSicon_cache.
///////////////////////
//UPDATE_ICONS SYSTEM//
///////////////////////
/*
Calling this a system is perhaps a bit trumped up. It is essentially update_clothing dismantled into its
core parts. The key difference is that when we generate overlays we do not generate either lying or standing
versions. Instead, we generate one set of "raw" (non-overlay-list friendly) overlays which are further processed
by SSoverlays when update_icon() runs. A single entry may be an /icon, an /image, or a /list of the former two.
var/overlays_raw[26]
This system involves a bit more list churn than the old (bay) system, but should involve significantly less appearance
churn, plus has the benefit of reducing the number of overlays-with-overlays (compound overlays).
We also can put raw /icon instances directly in the list this way and SSoverlays will automatically convert them into
a more client-friendly format.
In the old system, we updated all our overlays every life() call, even if we were standing still inside a crate!
or dead!. 25ish overlays, all generated from scratch every second for every xeno/human/monkey and then applied.
More often than not update_clothing was being called a few times in addition to that! CPU was not the only issue,
all those icons had to be sent to every client. So really the cost was extremely cumulative. To the point where
update_clothing would frequently appear in the top 10 most CPU intensive procs during profiling.
Like the bay system, our list is indexed. This means we can update specific overlays!
So we only regenerate icons when we need them to be updated!
Also like bay, we use transforms to handle lying states instead of a separate set of icons.
There are several things that need to be remembered:
> Whenever we do something that should cause an overlay to update (which doesn't use standard procs)
( i.e. you do something like l_hand = /obj/item/something new(src) )
You will need to call the relevant update_inv_* proc:
update_inv_head()
update_inv_wear_suit()
update_inv_gloves()
update_inv_shoes()
update_inv_w_uniform()
update_inv_glasses()
update_inv_l_hand()
update_inv_r_hand()
update_inv_belt()
update_inv_wear_id()
update_inv_l_ear()
update_inv_r_ear()
update_inv_s_store()
update_inv_pockets()
update_inv_back()
update_inv_handcuffed()
update_inv_wear_mask()
All of these are named after the variable they update from. They are defined at the mob/ level like
update_clothing was, so you won't cause undefined proc runtimes with usr.update_inv_wear_id() if the usr is a
slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such.
> There are also these special cases:
update_mutations() //handles updating your appearance for certain mutations. e.g TK head-glows
UpdateDamageIcon() //handles damage overlays for brute/burn damage //(will rename this when I geta round to it)
update_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc
update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and
...eyes were merged into update_body)
update_targeted() // Updates the target overlay when someone points a gun at you
> All of these procs update overlays_raw, and then call update_icon() by default.
If you wish to update several overlays at once, you can set the argument to 0 to disable the update and call
it manually:
e.g.
update_inv_head(0)
update_inv_l_hand(0)
update_inv_r_hand() //<---calls update_icon()
or equivalently:
update_inv_head(0)
update_inv_l_hand(0)
update_inv_r_hand(0)
update_icon()
> If you need to update all overlays you can use regenerate_icons(). it works exactly like update_clothing used to.
> I reimplemented an old unused variable which was in the code called (coincidentally) var/update_icon
It can be used as another method of triggering regenerate_icons(). It's basically a flag that when set to non-zero
will call regenerate_icons() at the next life() call and then reset itself to 0.
The idea behind it is icons are regenerated only once, even if multiple events requested it.
*/
#define GET_BODY_TYPE (cached_bodytype || (cached_bodytype = species.get_bodytype()))
#define GET_TAIL_LAYER (dir == NORTH ? TAIL_NORTH_LAYER : TAIL_SOUTH_LAYER)
#define GET_TAIL_ACC_LAYER (dir == NORTH ? TAIL_NORTH_ACC_LAYER : TAIL_SOUTH_ACC_LAYER)
/proc/overlay_image(icon, icon_state,color, flags, plane, layer)
var/image/ret = image(icon,icon_state)
ret.color = color
ret.appearance_flags = PIXEL_SCALE | flags
if(plane)
ret.plane = plane
if(layer)
ret.layer = layer
return ret
/mob/living/carbon/human
var/list/overlays_raw[TOTAL_LAYERS] // Our set of "raw" overlays that can be modified, but cannot be directly applied to the mob without preprocessing.
var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed
// Updates overlays from overlays_raw.
/mob/living/carbon/human/update_icon(var/forceDirUpdate = FALSE)
if (QDELETED(src))
return // No point.
var/update_lying = (lying_prev != lying) || forceDirUpdate || size_multiplier != 1
var/draw_specific_icon = (!lying || species.prone_icon)
if(update_lying && draw_specific_icon)
update_inv_l_hand(FALSE)
update_inv_r_hand(FALSE)
update_hud() //TODO: remove the need for this
if(cloaked)
icon = 'icons/mob/human.dmi'
icon_state = "body_cloaked"
SetOverlays(list(overlays_raw[L_HAND_LAYER], overlays_raw[R_HAND_LAYER]))
else
var/list/ovr = list()
if (icon != stand_icon)
icon = stand_icon
// We manually add each element instead of just using Copy() so that lists are appended instead of inserted.
for (var/item in overlays_raw)
if (item)
ovr += item
if(species.has_floating_eyes)
ovr += species.get_eyes(src)
for(var/aura in auras)
var/obj/aura/A = aura
var/icon/aura_overlay = icon(A.icon, icon_state = A.icon_state)
ovr += aura_overlay
SetOverlays(ovr)
if(update_lying) //Only rotate them if we're not drawing a specific icon for being prone.
var/matrix/M = matrix()
M.Scale(size_multiplier)
if(draw_specific_icon)
M.Translate(0, 16*(size_multiplier-1))
animate(src, transform = M, time = ANIM_LYING_TIME)
else
switch(src.dir)
if(SOUTH,EAST)
M.Turn(90)
else
M.Turn(-90)
M.Translate(1,-6)
animate(src, transform = M, time = (forceDirUpdate ? 0 : ANIM_LYING_TIME))
if(istype(src.l_hand, /obj/item/gun) && lying)
HeldObjectDirTransform(slot_l_hand, src.dir)
if(istype(src.r_hand, /obj/item/gun) && lying)
HeldObjectDirTransform(slot_r_hand, src.dir)
UpdateOverlays()
lying_prev = lying
/mob/living/carbon/human/proc/HeldObjectDirTransform(var/hand = slot_l_hand, var/direction)
var/layer = null
if(hand == slot_r_hand)
update_inv_r_hand(FALSE)
layer = R_HAND_LAYER
else
update_inv_l_hand(FALSE)
layer = L_HAND_LAYER
switch(direction)
if(EAST)
TransformLayerIcon(layer, -90)
if(WEST)
TransformLayerIcon(layer, 90)
if(NORTH)
TransformLayerIcon(layer, 0)
if(SOUTH)
TransformLayerIcon(layer, 180)
/mob/living/carbon/human/proc/TransformLayerIcon(var/layer, var/rotation = 0)
var/image/item_image = overlays_raw[layer]
var/matrix/item_transform = matrix()
item_transform.Turn(rotation)
animate(item_image, transform = item_transform)
overlays_raw[layer] = item_image
update_icon()
//DAMAGE OVERLAYS
//constructs damage icon for each organ from mask * damage field and saves it in our overlays_raw list (as a list of icons).
/mob/living/carbon/human/UpdateDamageIcon(var/update_icons = 1)
// first check whether something actually changed about damage appearance
var/damage_appearance = ""
for(var/obj/item/organ/external/O in organs)
if(QDELETED(O) || O.is_stump())
continue
//if(O.status & ORGAN_DESTROYED) damage_appearance += "d" //what is this?
//else
// damage_appearance += O.damage_state
damage_appearance += O.damage_state
if(damage_appearance == previous_damage_appearance)
// nothing to do here
return
previous_damage_appearance = damage_appearance
// The overlays we're going to add to the mob.
var/list/ovr
// blend the individual damage states with our icons
for(var/obj/item/organ/external/O in organs)
if(QDELETED(O) || O.is_stump())
continue
O.update_icon()
if(O.damage_state == "00") continue
var/cache_index = "[O.damage_state]/[O.icon_name]/[get_blood_color()]/[GET_BODY_TYPE]"
var/list/damage_icon_parts = SSicon_cache.damage_icon_parts
var/icon/DI = damage_icon_parts[cache_index]
if(!DI)
DI = new /icon(species.damage_overlays, O.damage_state) // the damage icon for whole human
DI.Blend(new /icon(species.damage_mask, O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels
DI.Blend(get_blood_color(), ICON_MULTIPLY)
damage_icon_parts[cache_index] = DI
LAZYADD(ovr, DI)
overlays_raw[MOB_DAMAGE_LAYER] = ovr
update_bandages(update_icons)
if(update_icons)
update_icon()
/// Handles displaying bandages on the mob icon, and whether the mob should have the add/remove bandages verb attached to it
/mob/living/carbon/human/proc/update_bandages(var/update_icons = TRUE)
var/bandage_icon = species.bandages_icon
if(!bandage_icon)
return
var/list/ovr
for(var/obj/item/organ/external/O in organs)
if(O.is_stump())
continue
var/bandage_level = O.bandage_level
if(bandage_level)
LAZYADD(ovr, image(bandage_icon, "[O.icon_name][bandage_level]"))
// this next part handles whether the mob should have the Remove Bandages verb available
// obviously this is a little hacky, since this is the icon update function, but it's also the best place we loop through
// the various organs and calculate their bandage level
var/had_bandages = LAZYLEN(overlays_raw[BANDAGE_LAYER])
var/has_bandages = LAZYLEN(ovr)
// gained bandages
if(!had_bandages && has_bandages)
add_verb(src, /mob/living/carbon/human/proc/remove_bandages)
// lost bandages
else if(had_bandages && !has_bandages)
remove_verb(src, /mob/living/carbon/human/proc/remove_bandages)
overlays_raw[BANDAGE_LAYER] = ovr
if(update_icons)
update_icon()
/**
* Overlays for the worn overlay so you can overlay while you overlay
* eg: ammo counters, primed grenade flashing, etc.
* "icon_file" is used automatically for inhands etc. to make sure it gets the correct inhand file
*/
/obj/item/proc/worn_overlays(icon_file)
. = list()
var/mutable_appearance/M = null
if(build_from_parts)
M = mutable_appearance(icon_file, "[item_state]_[worn_overlay]")
M.appearance_flags = RESET_COLOR|RESET_ALPHA
if(worn_overlay_color)
M.color = worn_overlay_color
. += M
/proc/slot_str_to_contained_flag(var/slot_str)
switch(slot_str)
if(slot_back_str)
return WORN_BACK
if(slot_l_hand_str)
return WORN_LHAND
if(slot_r_hand_str)
return WORN_RHAND
if(slot_wear_id_str)
return WORN_ID
if(slot_w_uniform_str)
return WORN_UNDER
if(slot_head_str)
return WORN_HEAD
if(slot_glasses_str)
return WORN_EYES
if(slot_wear_mask_str)
return WORN_MASK
if(slot_belt_str)
return WORN_BELT
if(slot_wear_suit_str)
return WORN_SUIT
if(slot_pants_str)
return WORN_PANTS
if(slot_l_ear_str)
return WORN_LEAR
if(slot_r_ear_str)
return WORN_REAR
if(slot_shoes_str)
return WORN_SHOES
if(slot_wrists_str)
return WORN_WRISTS
if(slot_gloves_str)
return WORN_GLOVES
return ""
/// BASE MOB SPRITE
/mob/living/carbon/human/proc/update_body(var/update_icons=1, var/force_base_icon = FALSE)
if (QDELETED(src))
return
var/husk_color_mod = rgb(96,88,80)
var/husk = (mutations & HUSK)
var/fat = (mutations & FAT)
var/skeleton = (mutations & SKELETON)
var/g = (gender == FEMALE ? "f" : "m")
pixel_x = species.icon_x_offset
pixel_y = species.icon_y_offset
//CACHING: Generate an index key from visible bodyparts.
//0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic.
//Create a new, blank icon for our mob to use.
if(stand_icon)
qdel(stand_icon)
stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank")
var/is_frenzied = "nofrenzy"
if(mind)
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
if(vampire && (vampire.status & VAMP_FRENZIED))
is_frenzied = "frenzy"
var/icon_key = "[species.race_key][g][s_tone][r_skin][g_skin][b_skin][lipstick_color || "nolips"][!!husk][!!fat][!!skeleton][is_frenzied]"
var/obj/item/organ/internal/eyes/eyes = get_eyes()
if(eyes)
icon_key += "[rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3])]"
else
icon_key += "#000000"
for(var/organ_tag in species.has_limbs)
var/obj/item/organ/external/part = organs_by_name[organ_tag]
if (!part)
continue
icon_key += SSicon_cache.get_organ_shortcode(part)
var/icon/base_icon = SSicon_cache.human_icon_cache[icon_key]
if (!base_icon || force_base_icon) // Icon ain't in the cache, so generate it.
//BEGIN CACHED ICON GENERATION.
var/obj/item/organ/external/chest = get_organ(BP_CHEST)
base_icon = chest.get_icon(skeleton)
for(var/obj/item/organ/external/part in organs)
if(isnull(part) || part.is_stump())
continue
var/icon/temp = part.get_icon(skeleton)//The color comes from this function
//That part makes left and right legs drawn topmost and lowermost when human looks WEST or EAST
//And no change in rendering for other parts (they icon_position is 0, so goes to 'else' part)
if(part.icon_position&(LEFT|RIGHT))
var/icon/temp2 = new('icons/mob/human.dmi',"blank")
temp2.Insert(new /icon(temp ,dir = NORTH), dir = NORTH)
temp2.Insert(new /icon(temp, dir = SOUTH), dir = SOUTH)
if(!(part.icon_position & LEFT))
temp2.Insert(new /icon(temp, dir = EAST), dir = EAST)
if(!(part.icon_position & RIGHT))
temp2.Insert(new /icon(temp, dir = WEST), dir = WEST)
base_icon.Blend(temp2, ICON_OVERLAY)
if(part.icon_position & LEFT)
temp2.Insert(new /icon(temp, dir = EAST), dir = EAST)
if(part.icon_position & RIGHT)
temp2.Insert(new /icon(temp, dir = WEST), dir = WEST)
base_icon.Blend(temp2, ICON_UNDERLAY)
else
base_icon.Blend(temp, ICON_OVERLAY)
if(!(species.flags & NO_SCAN))
if(husk)
base_icon.ColorTone(husk_color_mod)
//Handle husk overlay.
if(husk && ("overlay_husk" in icon_states(species.icobase)))
var/icon/mask = new(base_icon)
var/icon/husk_over = new(species.icobase,"overlay_husk")
mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)
husk_over.Blend(mask, ICON_ADD)
base_icon.Blend(husk_over, ICON_OVERLAY)
SSicon_cache.human_icon_cache[icon_key] = base_icon
for(var/obj/item/organ/external/part in organs)
part.cut_additional_images(src)
var/list/add_images = part.get_additional_images(src)
if(add_images)
AddOverlays(add_images, ATOM_ICON_CACHE_PROTECTED)
UpdateOverlays()
//END CACHED ICON GENERATION.
stand_icon.Blend(base_icon,ICON_OVERLAY)
//tail
update_tail_showing(0)
if(update_icons)
update_icon()
/mob/living/carbon/human/proc/update_underwear(update_icons = TRUE)
overlays_raw[UNDERWEAR_LAYER] = list()
if(species.appearance_flags & HAS_UNDERWEAR)
for(var/category in all_underwear)
if(hide_underwear[category])
continue
if(category == "Underwear, top" && hide_underwear["Undershirt"] == FALSE && !istype(all_underwear["Undershirt"], /datum/category_item/underwear/undershirt/none))
continue //This piece of "code" is here to prevent tops from showing up over undershirts.
var/datum/category_item/underwear/UWI = all_underwear[category]
overlays_raw[UNDERWEAR_LAYER] += UWI.generate_image(all_underwear_metadata[category])
if(update_icons)
update_icon()
/**
* This proc generates & returns an icon representing a human's hair, using a cached icon from SSicon_cache if possible.
* If `hair_is_visible` is FALSE, only facial hair will be drawn.
*/
/mob/living/carbon/human/proc/generate_hair_icon(hair_is_visible = TRUE)
var/cache_key = "[f_style ? "[f_style][r_facial][g_facial][b_facial]" : "nofacial"]_[(h_style && hair_is_visible) ? "[h_style][r_hair][g_hair][b_hair]" : "nohair"]_[(g_style && g_style != "None" && hair_is_visible) ? "[g_style][r_grad][g_grad][b_grad]" : "nograd"]"
var/icon/face_standing = SSicon_cache.human_hair_cache[cache_key]
if (!face_standing) // Not cached, generate it from scratch.
face_standing = new /icon(species.canvas_icon, "blank")
// Beard.
if(f_style)
var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hair_styles_list[f_style]
if(facial_hair_style && facial_hair_style.species_allowed && (species.type in facial_hair_style.species_allowed))
var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = facial_hair_style.icon_state)
if(facial_hair_style.do_colouration)
facial_s.Blend(rgb(r_facial, g_facial, b_facial), facial_hair_style.icon_blend_mode)
face_standing.Blend(facial_s, ICON_OVERLAY)
// Hair.
if(hair_is_visible)
var/icon/grad_s = null
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_list[h_style]
if(hair_style && (species.type in hair_style.species_allowed))
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = hair_style.icon_state)
if(hair_style.do_colouration)
if(g_style)
var/datum/sprite_accessory/gradient_style = GLOB.hair_gradient_styles_list[g_style]
if(gradient_style && gradient_style.species_allowed && (species.type in gradient_style.species_allowed))
grad_s = new/icon("icon" = gradient_style.icon, "icon_state" = gradient_style.icon_state)
grad_s.Blend(hair_s, ICON_AND)
grad_s.Blend(rgb(r_grad, g_grad, b_grad), ICON_MULTIPLY)
hair_s.Blend(rgb(r_hair, g_hair, b_hair), hair_style.icon_blend_mode)
if(!isnull(grad_s))
var/icon/grad_s_final = new/icon("icon" = hair_style.icon, "icon_state" = hair_style.icon_state)
grad_s_final.Blend(grad_s, hair_style.icon_blend_mode)
hair_s.Blend(grad_s_final, ICON_OVERLAY)
face_standing.Blend(hair_s, ICON_OVERLAY)
// Add it to the cache.
SSicon_cache.human_hair_cache[cache_key] = face_standing
return face_standing
/// HAIR OVERLAY
/mob/living/carbon/human/proc/update_hair(var/update_icons=1)
if (QDELETED(src))
return
//Reset our hair
overlays_raw[HAIR_LAYER] = null
overlays_raw[HAIR_LAYER_ALT] = null
overlays_raw[HAIR_LAYER_EMISSIVE] = null
overlays_raw[HAIR_LAYER_ALT_EMISSIVE] = null
var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD)
if(!head_organ || head_organ.is_stump() )
if(update_icons) update_icon()
return
//masks and helmets can obscure our hair.
if( (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR)) || (l_ear && (l_ear.flags_inv & BLOCKHAIR)) || (r_ear && (r_ear.flags_inv & BLOCKHAIR)))
if(update_icons) update_icon()
return
var/has_visible_hair = h_style && !(head && (head.flags_inv & BLOCKHEADHAIR)) && !(l_ear && (l_ear.flags_inv & BLOCKHEADHAIR)) && !(r_ear && (r_ear.flags_inv & BLOCKHEADHAIR)) && !(wear_suit && (wear_suit.flags_inv & BLOCKHEADHAIR))
var/icon/hair_icon = generate_hair_icon(has_visible_hair)
// Handle light emission.
if (species.light_range)
if (has_visible_hair)
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_list[h_style]
if (hair_style)
var/col = species.get_light_color(src) || "#FFFFFF"
set_light(species.light_range, species.light_power, col)
else
set_light(0)
var/hair_layer = species.use_alt_hair_layer ? HAIR_LAYER_ALT : HAIR_LAYER
overlays_raw[hair_layer] = hair_icon
if(has_visible_hair)
var/datum/sprite_accessory/hair_style = GLOB.hair_styles_list[h_style]
if(hair_style)
var/hair_emissive_layer = species.use_alt_hair_layer ? HAIR_LAYER_ALT_EMISSIVE : HAIR_LAYER_EMISSIVE
overlays_raw[hair_emissive_layer] = emissive_blocker(hair_icon, hair_style.icon_state, MOB_SHADOW_UPPER_LAYER)
if(update_icons)
update_icon()
/mob/living/carbon/human/update_mutations(var/update_icons=1)
if (QDELETED(src))
return
var/fat
if((mutations & FAT))
fat = "fat"
var/image/standing = image("icon" = 'icons/effects/genetics.dmi')
var/add_image = 0
var/g = "m"
if(gender == FEMALE) g = "f"
// DNA2 - Drawing underlays.
for(var/datum/dna/gene/gene in dna_genes)
if(!gene.block)
continue
if(gene.is_active(src))
var/underlay=gene.OnDrawUnderlays(src,g,fat)
if(underlay)
standing.underlays += underlay
add_image = 1
if((mutations & LASER_EYES))
standing.overlays += "lasereyes_s"
add_image = 1
if(add_image)
overlays_raw[MUTATIONS_LAYER] = standing
else
overlays_raw[MUTATIONS_LAYER] = null
if(update_icons)
update_icon()
/* --------------------------------------- */
/// For legacy support.
/mob/living/carbon/human/regenerate_icons()
..()
if(QDELETED(src))
return
if(transforming)
return
update_mutations(FALSE)
update_body(FALSE)
update_hair(FALSE)
update_inv_w_uniform(FALSE)
update_inv_wear_id(FALSE)
update_inv_gloves(FALSE)
update_inv_glasses(FALSE)
update_inv_l_ear(FALSE)
update_inv_r_ear(FALSE)
update_inv_shoes(FALSE)
update_inv_s_store(FALSE)
update_inv_wear_mask(FALSE)
update_inv_head(FALSE)
update_inv_belt(FALSE)
update_inv_back(FALSE)
update_inv_wear_suit(FALSE)
update_inv_r_hand(FALSE)
update_inv_l_hand(FALSE)
update_inv_handcuffed(FALSE)
update_inv_legcuffed(FALSE)
update_inv_pockets(FALSE)
update_fire(FALSE)
update_surgery(FALSE)
update_underwear(FALSE)
update_inv_wrists(FALSE)
UpdateDamageIcon()
update_icon()
//Hud Stuff
update_hud()
/* --------------------------------------- */
//vvvvvv UPDATE_INV PROCS vvvvvv
/mob/living/carbon/human/update_inv_w_uniform(var/update_icons=1)
if (QDELETED(src))
return
if(check_draw_underclothing())
var/mob_icon
var/mob_state = ""
if(w_uniform.contained_sprite)//Do all the containedsprite stuff in one place
w_uniform.auto_adapt_species(src)
if(w_uniform.icon_override)
mob_icon = w_uniform.icon_override
else if(w_uniform.sprite_sheets && w_uniform.sprite_sheets[GET_BODY_TYPE])
mob_icon = w_uniform.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = w_uniform.icon
if (w_uniform.icon_species_tag)
mob_state += "[w_uniform.icon_species_tag]_"
mob_state += w_uniform.item_state + WORN_UNDER
else if(w_uniform.icon_override)
mob_icon = w_uniform.icon_override
else if(w_uniform.sprite_sheets && w_uniform.sprite_sheets[GET_BODY_TYPE])
mob_icon = w_uniform.sprite_sheets[GET_BODY_TYPE]
else if(w_uniform.item_icons && w_uniform.item_icons[slot_w_uniform_str])
mob_icon = w_uniform.item_icons[slot_w_uniform_str]
else
mob_icon = INV_W_UNIFORM_DEF_ICON
//determine state to use
if (!mob_state)
if(w_uniform.item_state_slots && w_uniform.item_state_slots[slot_w_uniform_str])
mob_state = w_uniform.item_state_slots[slot_w_uniform_str] + "_s"
else if(w_uniform.item_state)
mob_state = w_uniform.item_state + "_s"
else
mob_state = w_uniform.icon_state + "_s"
overlays_raw[UNIFORM_LAYER] = w_uniform.get_mob_overlay(src, mob_icon, mob_state, slot_w_uniform_str)
else
overlays_raw[UNIFORM_LAYER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1)
if (QDELETED(src))
return
overlays_raw[ID_LAYER] = null
overlays_raw[ID_LAYER_ALT] = null
if(wear_id)
if(istype(w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/uniform = w_uniform
if(!uniform.displays_id)
return
var/mob_icon
var/mob_state
if(wear_id.contained_sprite)
wear_id.auto_adapt_species(src)
if(!(wear_id.overlay_state)) //legacy check
wear_id.overlay_state = wear_id.item_state
mob_icon = (wear_id.icon_override || wear_id.icon)
mob_state = "[wear_id.overlay_state][WORN_ID]"
else
mob_icon = 'icons/mob/card.dmi'
mob_state = wear_id.overlay_state
//Layering under/over suit
var/id_layer = ID_LAYER
if(istype(wear_id, /obj/item/storage/wallet/lanyard))
var/obj/item/storage/wallet/lanyard/lanyard = wear_id
if(lanyard.wear_over_suit)
id_layer = ID_LAYER_ALT
else if(istype(wear_id, /obj/item/card/id))
var/obj/item/card/id/id_card = wear_id
if(id_card.wear_over_suit)
id_layer = ID_LAYER_ALT
overlays_raw[id_layer] = wear_id.get_mob_overlay(src, mob_icon, mob_state, slot_wear_id_str)
BITSET(hud_updateflag, ID_HUD)
BITSET(hud_updateflag, WANTED_HUD)
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_gloves(var/update_icons=1)
if (QDELETED(src))
return
if(check_draw_gloves())
var/mob_icon
var/mob_state = gloves.item_state || gloves.icon_state
if(gloves.contained_sprite)
if(gloves.icon_override)
mob_icon = gloves.icon_override
else if(gloves.sprite_sheets && gloves.sprite_sheets[GET_BODY_TYPE])
mob_icon = gloves.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = gloves.icon
gloves.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(gloves.icon_species_tag)][gloves.item_state][WORN_GLOVES]"
else if(gloves.icon_override)
mob_icon = gloves.icon_override
else if(gloves.sprite_sheets && gloves.sprite_sheets[GET_BODY_TYPE])
mob_icon = gloves.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = 'icons/mob/hands.dmi'
overlays_raw[GLOVES_LAYER] = gloves.get_mob_overlay(src, mob_icon, mob_state, slot_gloves_str)
else if(blood_DNA)
var/image/bloodsies = image(species.blood_mask, "bloodyhands")
bloodsies.color = hand_blood_color
bloodsies.appearance_flags = RESET_ALPHA
overlays_raw[GLOVES_LAYER] = bloodsies
else
overlays_raw[GLOVES_LAYER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_glasses(var/update_icons=1)
if (QDELETED(src))
return
if(check_draw_glasses())
var/mob_icon
var/mob_state = glasses.icon_state
if(glasses.contained_sprite)
if(glasses.icon_override)
mob_icon = glasses.icon_override
else if(glasses.sprite_sheets && glasses.sprite_sheets[GET_BODY_TYPE])
mob_icon = glasses.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = glasses.icon
glasses.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(glasses.icon_species_tag)][glasses.item_state][WORN_EYES]"
else if(glasses.icon_override)
mob_icon = glasses.icon_override
else if(glasses.sprite_sheets && glasses.sprite_sheets[GET_BODY_TYPE])
mob_icon = glasses.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = 'icons/mob/eyes.dmi'
var/image/glasses_overlay = glasses.get_mob_overlay(src, mob_icon, mob_state, slot_glasses_str)
var/normal_layer = GLASSES_LAYER
if(istype(glasses, /obj/item/clothing/glasses))
var/obj/item/clothing/glasses/G = glasses
normal_layer = G.normal_layer
overlays_raw[GLASSES_LAYER] = null
overlays_raw[GLASSES_LAYER_ALT] = null
overlays_raw[GLASSES_LAYER_OVER] = null
overlays_raw[normal_layer] = glasses_overlay
else
overlays_raw[GLASSES_LAYER] = null
overlays_raw[GLASSES_LAYER_ALT] = null
overlays_raw[GLASSES_LAYER_OVER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_l_ear(var/update_icons=1)
if(QDELETED(src))
return
if(check_draw_left_ear())
if(l_ear)
var/mob_icon = INV_L_EAR_DEF_ICON
var/mob_state = l_ear.icon_state
if(l_ear.contained_sprite)
if(l_ear.icon_override)
mob_icon = l_ear.icon_override
else if(l_ear.sprite_sheets && l_ear.sprite_sheets[GET_BODY_TYPE])
mob_icon = l_ear.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = l_ear.icon
l_ear.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(l_ear.icon_species_tag)][l_ear.item_state][WORN_LEAR]"
else if(l_ear.icon_override)
mob_icon = l_ear.icon_override
else if(l_ear.sprite_sheets && l_ear.sprite_sheets[GET_BODY_TYPE])
mob_icon = l_ear.sprite_sheets[GET_BODY_TYPE]
else if(l_ear.item_icons && (slot_l_ear_str in l_ear.item_icons))
mob_icon = l_ear.item_icons[slot_l_ear_str]
var/layer = L_EAR_LAYER
var/layer_alt = L_EAR_LAYER_ALT
var/obj/item/radio/headset/wrist/W = l_ear
if(istype(W) && W.mob_wear_layer == ABOVE_SUIT_LAYER_WR)
layer = L_EAR_LAYER_ALT
layer_alt = L_EAR_LAYER
overlays_raw[layer] = l_ear.get_mob_overlay(src, mob_icon, mob_state, slot_l_ear_str)
overlays_raw[layer_alt] = null
else
overlays_raw[L_EAR_LAYER] = null
overlays_raw[L_EAR_LAYER_ALT] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_r_ear(var/update_icons=1)
if(QDELETED(src))
return
if(check_draw_right_ear())
if(r_ear)
var/mob_icon = INV_R_EAR_DEF_ICON
var/mob_state = r_ear.icon_state
if(r_ear.contained_sprite)
if(r_ear.icon_override)
mob_icon = r_ear.icon_override
else if(r_ear.sprite_sheets && r_ear.sprite_sheets[GET_BODY_TYPE])
mob_icon = r_ear.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = r_ear.icon
r_ear.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(r_ear.icon_species_tag)][r_ear.item_state][WORN_REAR]"
else if(r_ear.icon_override)
mob_icon = r_ear.icon_override
else if(r_ear.sprite_sheets && r_ear.sprite_sheets[GET_BODY_TYPE])
mob_icon = r_ear.sprite_sheets[GET_BODY_TYPE]
else if(r_ear.item_icons && (slot_r_ear_str in r_ear.item_icons))
mob_icon = r_ear.item_icons[slot_r_ear_str]
var/layer = R_EAR_LAYER
var/layer_alt = R_EAR_LAYER_ALT
var/obj/item/radio/headset/wrist/W = r_ear
if(istype(W) && W.mob_wear_layer == ABOVE_SUIT_LAYER_WR)
layer = R_EAR_LAYER_ALT
layer_alt = R_EAR_LAYER
overlays_raw[layer] = r_ear.get_mob_overlay(src, mob_icon, mob_state, slot_r_ear_str)
overlays_raw[layer_alt] = null
else
overlays_raw[R_EAR_LAYER] = null
overlays_raw[R_EAR_LAYER_ALT] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_shoes(var/update_icons=1)
if (QDELETED(src))
return
if(check_draw_shoes())
var/mob_icon = INV_SHOES_DEF_ICON
var/mob_state = shoes.icon_state
if(shoes.contained_sprite)
if(shoes.icon_override)
mob_icon = shoes.icon_override
if(shoes.sprite_sheets && shoes.sprite_sheets[GET_BODY_TYPE])
mob_icon = shoes.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = shoes.icon
shoes.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(shoes.icon_species_tag)][shoes.item_state][WORN_SHOES]"
else if(shoes.icon_override)
mob_icon = shoes.icon_override
else if(shoes.sprite_sheets && shoes.sprite_sheets[GET_BODY_TYPE])
mob_icon = shoes.sprite_sheets[GET_BODY_TYPE]
else if(shoes.item_icons && (slot_shoes_str in shoes.item_icons))
mob_icon = shoes.item_icons[slot_shoes_str]
else
mob_icon = INV_SHOES_DEF_ICON
//Shoe layer stuff from Polaris v1.0333a
var/shoe_layer = SHOES_LAYER
var/null_layer = SHOES_LAYER_ALT
if(istype(shoes, /obj/item/clothing/shoes))
var/obj/item/clothing/shoes/S = shoes
if(S.shoes_under_pants == TRUE)
shoe_layer = SHOES_LAYER_ALT
null_layer = SHOES_LAYER
overlays_raw[shoe_layer] = shoes.get_mob_overlay(src, mob_icon, mob_state, slot_shoes_str)
overlays_raw[null_layer] = null
else
if(footprint_color) // Handles bloody feet.
var/image/result_layer
for(var/limb_tag in list(BP_L_FOOT, BP_R_FOOT))
var/obj/item/organ/external/E = get_organ(limb_tag)
if(E && !E.is_stump())
var/image/bloodsies = image(species.blood_mask, "shoeblood_[E.limb_name]")
bloodsies.color = footprint_color
bloodsies.appearance_flags = RESET_ALPHA
if(!result_layer)
result_layer = bloodsies
else
result_layer.overlays.Add(bloodsies)
overlays_raw[SHOES_LAYER] = result_layer
overlays_raw[SHOES_LAYER_ALT] = null
else
overlays_raw[SHOES_LAYER] = null
overlays_raw[SHOES_LAYER_ALT] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_s_store(var/update_icons=1)
if (QDELETED(src))
return
if(s_store)
var/mob_icon = 'icons/mob/belt_mirror.dmi'
var/mob_state = (s_store.item_state || s_store.icon_state)
if(s_store.contained_sprite)
if(s_store.icon_override)
mob_icon = s_store.icon_override
else if(s_store.sprite_sheets && s_store.sprite_sheets[GET_BODY_TYPE])
mob_icon = s_store.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = s_store.icon
s_store.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(s_store.icon_species_tag)][s_store.item_state][WORN_SSTORE]"
overlays_raw[SUIT_STORE_LAYER] = s_store.get_mob_overlay(src, mob_icon, mob_state, slot_s_store_str)
else
overlays_raw[SUIT_STORE_LAYER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_head(update_icons = TRUE, recurse = TRUE)
if (QDELETED(src))
return
overlays_raw[HEAD_LAYER] = null
if(head)
var/mob_icon = INV_HEAD_DEF_ICON
var/mob_state = head.icon_state
if(head.contained_sprite)
if(head.icon_override)
mob_icon = head.icon_override
else if(head.sprite_sheets && head.sprite_sheets[GET_BODY_TYPE])
mob_icon = head.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = head.icon
head.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(head.icon_species_tag)][head.item_state][WORN_HEAD]"
else if(head.icon_override)
mob_icon = head.icon_override
else if(head.sprite_sheets && head.sprite_sheets[GET_BODY_TYPE])
mob_icon = head.sprite_sheets[GET_BODY_TYPE]
else if(head.item_icons && (slot_head_str in head.item_icons))
mob_icon = head.item_icons[slot_head_str]
else
mob_icon = INV_HEAD_DEF_ICON
overlays_raw[HEAD_LAYER] = head.get_mob_overlay(src, mob_icon, mob_state, slot_head_str)
if (recurse)
update_hair(FALSE)
update_inv_wear_mask(FALSE, FALSE)
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_belt(var/update_icons=1)
if (QDELETED(src))
return
if(belt)
var/mob_icon = INV_BELT_DEF_ICON
var/mob_state = belt.item_state
if(belt.contained_sprite)
if(belt.icon_override)
mob_icon = belt.icon_override
else if(belt.sprite_sheets && belt.sprite_sheets[GET_BODY_TYPE])
mob_icon = belt.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = belt.icon
belt.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(belt.icon_species_tag)][belt.item_state][WORN_BELT]"
else if(belt.icon_override)
mob_icon = belt.icon_override
else if(belt.sprite_sheets && belt.sprite_sheets[GET_BODY_TYPE])
mob_icon = belt.sprite_sheets[GET_BODY_TYPE]
else if(belt.item_icons && (slot_belt_str in belt.item_icons))
mob_icon = belt.item_icons[slot_belt_str]
var/belt_layer = BELT_LAYER
var/null_layer = BELT_LAYER_ALT
if(istype(belt, /obj/item/storage/belt))
var/obj/item/storage/belt/B = belt
if(B.show_above_suit)
belt_layer = BELT_LAYER_ALT
null_layer = BELT_LAYER
overlays_raw[belt_layer] = belt.get_mob_overlay(src, mob_icon, mob_state, slot_belt_str)
overlays_raw[null_layer] = null
else
overlays_raw[BELT_LAYER] = null
overlays_raw[BELT_LAYER_ALT] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1)
if (QDELETED(src))
return
if(wear_suit)
var/mob_icon = INV_SUIT_DEF_ICON
var/mob_state = wear_suit.icon_state
if(wear_suit.contained_sprite)
if(wear_suit.icon_override)
mob_icon = wear_suit.icon_override
else if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[GET_BODY_TYPE])
mob_icon = wear_suit.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = wear_suit.icon
wear_suit.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(wear_suit.icon_species_tag)][wear_suit.item_state][WORN_SUIT]"
else if(wear_suit.icon_override)
mob_icon = wear_suit.icon_override
else if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[GET_BODY_TYPE])
mob_icon = wear_suit.sprite_sheets[GET_BODY_TYPE]
else if(wear_suit.item_icons && (slot_wear_suit_str in wear_suit.item_icons))
mob_icon = wear_suit.item_icons[slot_wear_suit_str]
overlays_raw[SUIT_LAYER] = wear_suit.get_mob_overlay(src, mob_icon, mob_state, slot_wear_suit_str)
update_tail_showing(0)
else
overlays_raw[SUIT_LAYER] = null
update_tail_showing(0)
update_inv_shoes(0)
update_collar(0)
update_inv_w_uniform(0)
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_pockets(var/update_icons=1)
if (QDELETED(src))
return
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_wear_mask(update_icons = TRUE, recurse = TRUE)
if (QDELETED(src))
return
overlays_raw[FACEMASK_LAYER] = null
if(check_draw_mask())
var/mob_icon
var/mob_state
if(wear_mask.contained_sprite)
wear_mask.auto_adapt_species(src)
var/state = "[UNDERSCORE_OR_NULL(wear_mask.icon_species_tag)][wear_mask.item_state][WORN_MASK]"
if(wear_mask.icon_override)
mob_icon = wear_mask.icon_override
else if(wear_mask.sprite_sheets && wear_mask.sprite_sheets[GET_BODY_TYPE])
mob_icon = wear_mask.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = wear_mask.icon
mob_state = state
else if(wear_mask.icon_override)
mob_icon = wear_mask.icon_override
mob_state = wear_mask.icon_state
else if(wear_mask.sprite_sheets && wear_mask.sprite_sheets[GET_BODY_TYPE])
mob_icon = wear_mask.sprite_sheets[GET_BODY_TYPE]
mob_state = wear_mask.icon_state
else
mob_icon = 'icons/mob/mask.dmi'
mob_state = wear_mask.icon_state
overlays_raw[FACEMASK_LAYER] = wear_mask.get_mob_overlay(src, mob_icon, mob_state, slot_wear_mask_str)
if (recurse)
update_inv_head(FALSE, FALSE)
update_hair(FALSE)
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_back(var/update_icons=1)
if (QDELETED(src))
return
if(back)
var/mob_icon = INV_BACK_DEF_ICON
var/mob_state = back.icon_state
if(back.contained_sprite)
if(back.icon_override)
mob_icon = back.icon_override
else if(back.sprite_sheets && back.sprite_sheets[GET_BODY_TYPE])
mob_icon = back.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = back.icon
back.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(back.icon_species_tag)][back.item_state][WORN_BACK]"
else if(back.icon_override)
mob_icon = back.icon_override
else if(istype(back, /obj/item/rig))
//If this is a rig and a mob_icon is set, it will take species into account in the rig update_icon() proc.
var/obj/item/rig/rig = back
mob_icon = rig.mob_icon
else if(back.sprite_sheets && back.sprite_sheets[GET_BODY_TYPE])
mob_icon = back.sprite_sheets[GET_BODY_TYPE]
else if(back.item_icons && (slot_back_str in back.item_icons))
mob_icon = back.item_icons[slot_back_str]
if(!mob_state && back.item_state_slots && back.item_state_slots[slot_back_str])
mob_state = back.item_state_slots[slot_back_str]
overlays_raw[BACK_LAYER] = back.get_mob_overlay(src, mob_icon, mob_state, slot_back_str)
else
overlays_raw[BACK_LAYER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_hud() //TODO: do away with this if possible
if(client)
client.screen |= contents
if(hud_used)
update_hud_hands()
hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar
//update whether handcuffs appears on our hud.
/mob/living/carbon/proc/update_hud_hands()
if(hud_used?.l_hand_hud_object)
hud_used.l_hand_hud_object.update_icon()
if(hud_used?.r_hand_hud_object)
hud_used.r_hand_hud_object.update_icon()
/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1)
if (QDELETED(src))
return
if(handcuffed)
drop_r_hand()
drop_l_hand()
stop_pulling() //TODO: should be handled elsewhere
var/image/standing
if(handcuffed.icon_override)
standing = image(handcuffed.icon_override, "handcuff1")
else if(handcuffed.sprite_sheets && handcuffed.sprite_sheets[GET_BODY_TYPE])
standing = image(handcuffed.sprite_sheets[GET_BODY_TYPE], "handcuff1")
else
standing = image('icons/mob/mob.dmi', "handcuff1")
standing.appearance_flags = RESET_ALPHA
overlays_raw[HANDCUFF_LAYER] = standing
else
overlays_raw[HANDCUFF_LAYER] = null
update_hud_hands()
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1)
if (QDELETED(src))
return
if(legcuffed)
var/image/standing
if(legcuffed.icon_override)
standing = image(legcuffed.icon_override, "legcuff1")
else if(legcuffed.sprite_sheets && legcuffed.sprite_sheets[GET_BODY_TYPE])
standing = image(legcuffed.sprite_sheets[GET_BODY_TYPE], "legcuff1")
else
standing = image('icons/mob/mob.dmi', "legcuff1")
standing.appearance_flags = RESET_ALPHA
overlays_raw[LEGCUFF_LAYER] = standing
if(m_intent != M_WALK)
m_intent = M_WALK
if(hud_used && hud_used.move_intent)
hud_used.move_intent.icon_state = "walking"
else
overlays_raw[LEGCUFF_LAYER] = null
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_l_hand(update_icons = TRUE)
if (QDELETED(src))
return
if(l_hand)
var/mob_icon
var/mob_state = l_hand.item_state || l_hand.icon_state
if(l_hand.contained_sprite)
if(l_hand.icon_override)
mob_icon = l_hand.icon_override
else if(l_hand.sprite_sheets && l_hand.sprite_sheets[GET_BODY_TYPE])
mob_icon = l_hand.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = l_hand.icon
l_hand.auto_adapt_species(src)
if(l_hand.item_state_slots && l_hand.item_state_slots[slot_l_hand_str])
mob_state = "[l_hand.item_state_slots[slot_l_hand_str]][WORN_LHAND]"
else
mob_state = "[UNDERSCORE_OR_NULL(l_hand.icon_species_in_hand ? l_hand.icon_species_tag : null)][l_hand.item_state][WORN_LHAND]"
else
if(l_hand.item_state_slots && l_hand.item_state_slots[slot_l_hand_str])
mob_state = l_hand.item_state_slots[slot_l_hand_str]
if(l_hand.item_icons && (slot_l_hand_str in l_hand.item_icons))
mob_icon = l_hand.item_icons[slot_l_hand_str]
else if(l_hand.icon_override)
mob_icon = l_hand.icon_override
mob_state += WORN_LHAND
else
mob_icon = INV_L_HAND_DEF_ICON
overlays_raw[L_HAND_LAYER] = l_hand.get_mob_overlay(src, mob_icon, mob_state, slot_l_hand_str)
else
overlays_raw[L_HAND_LAYER] = null
if(update_icons)
update_icon(TRUE)
/mob/living/carbon/human/update_inv_r_hand(update_icons = TRUE)
if (QDELETED(src))
return
if(r_hand)
var/mob_icon
var/mob_state = r_hand.item_state || r_hand.icon_state
if(r_hand.contained_sprite)
if(r_hand.icon_override)
mob_icon = r_hand.icon_override
else if(r_hand.sprite_sheets && r_hand.sprite_sheets[GET_BODY_TYPE])
mob_icon = r_hand.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = r_hand.icon
r_hand.auto_adapt_species(src)
if(r_hand.item_state_slots && r_hand.item_state_slots[slot_r_hand_str])
mob_state = "[r_hand.item_state_slots[slot_r_hand_str]][WORN_RHAND]"
else
mob_state = "[UNDERSCORE_OR_NULL(r_hand.icon_species_in_hand ? r_hand.icon_species_tag : null)][r_hand.item_state][WORN_RHAND]"
else
if(r_hand.item_state_slots && r_hand.item_state_slots[slot_r_hand_str])
mob_state = r_hand.item_state_slots[slot_r_hand_str]
if(r_hand.item_icons && (slot_r_hand_str in r_hand.item_icons))
mob_icon = r_hand.item_icons[slot_r_hand_str]
else if(r_hand.icon_override)
mob_icon = r_hand.icon_override
mob_state += WORN_RHAND
else
mob_icon = INV_R_HAND_DEF_ICON
overlays_raw[R_HAND_LAYER] = r_hand.get_mob_overlay(src, mob_icon, mob_state, slot_r_hand_str)
else
overlays_raw[R_HAND_LAYER] = null
if(update_icons)
update_icon(TRUE)
/mob/living/carbon/human/update_inv_wrists(var/update_icons=1)
if (QDELETED(src))
return
overlays_raw[UNDER_UNIFORM_LAYER_WR] = null
overlays_raw[ABOVE_UNIFORM_LAYER_WR] = null
overlays_raw[ABOVE_SUIT_LAYER_WR] = null
if(check_draw_wrists())
var/mob_icon
var/mob_state = wrists.item_state || wrists.icon_state
if(wrists.contained_sprite)
if(wrists.icon_override)
mob_icon = wrists.icon_override
else if(wrists.sprite_sheets && wrists.sprite_sheets[GET_BODY_TYPE])
mob_icon = wrists.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = wrists.icon
wrists.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(wrists.icon_species_tag)][wrists.item_state][WORN_WRISTS]"
else
if(wrists.item_state_slots && wrists.item_state_slots[slot_wrists_str])
mob_state = wrists.item_state_slots[slot_wrists_str]
//determine icon to use
if(wrists.item_icons && (slot_wrists_str in wrists.item_icons))
mob_icon = wrists.item_icons[slot_wrists_str]
else if(wrists.icon_override)
mob_icon = wrists.icon_override
mob_state += WORN_WRISTS
else
mob_icon = INV_WRISTS_DEF_ICON
var/image/wrists_overlay = wrists.get_mob_overlay(src, mob_icon, mob_state, slot_wrists_str)
var/wrist_layer = ABOVE_SUIT_LAYER_WR
if(istype(wrists, /obj/item/clothing/wrists) || istype(wrists, /obj/item/radio/headset/wrist))
var/obj/item/clothing/wrists/W = wrists
wrist_layer = W.mob_wear_layer
overlays_raw[wrist_layer] = wrists_overlay
if(update_icons)
update_icon()
/mob/living/carbon/human/update_inv_pants(var/update_icons=1)
if (QDELETED(src))
return
overlays_raw[UNDER_UNIFORM_LAYER_PA] = null
overlays_raw[ABOVE_UNIFORM_LAYER_PA] = null
overlays_raw[ABOVE_SUIT_LAYER_PA] = null
if(check_draw_pants())
var/mob_icon
var/mob_state = pants.item_state || pants.icon_state
if(pants.contained_sprite)
if(pants.icon_override)
mob_icon = pants.icon_override
else if(pants.sprite_sheets && pants.sprite_sheets[GET_BODY_TYPE])
mob_icon = pants.sprite_sheets[GET_BODY_TYPE]
else
mob_icon = pants.icon
pants.auto_adapt_species(src)
mob_state = "[UNDERSCORE_OR_NULL(pants.icon_species_tag)][pants.item_state][WORN_PANTS]"
else
if(pants.item_state_slots && pants.item_state_slots[slot_pants_str])
mob_state = pants.item_state_slots[slot_pants_str]
//determine icon to use
if(pants.item_icons && (slot_pants_str in pants.item_icons))
mob_icon = pants.item_icons[slot_pants_str]
else if(pants.icon_override)
mob_icon = pants.icon_override
mob_state += WORN_PANTS
else
mob_icon = INV_PANTS_DEF_ICON
var/image/pants_overlay = pants.get_mob_overlay(src, mob_icon, mob_state, slot_pants_str)
var/pants_layer = ABOVE_SUIT_LAYER_PA
if(istype(pants, /obj/item/clothing/pants))
var/obj/item/clothing/pants/P = pants
pants_layer = P.mob_wear_layer
overlays_raw[pants_layer] = pants_overlay
if(update_icons)
update_icon()
/mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1)
if (QDELETED(src))
return
overlays_raw[TAIL_NORTH_LAYER] = null
overlays_raw[TAIL_SOUTH_LAYER] = null
var/tail_layer = GET_TAIL_LAYER
if(species.tail && !(mutations & HUSK) && !(mutations & SKELETON) && !(wear_suit && wear_suit.flags_inv & HIDETAIL))
var/icon/tail_s = get_tail_icon()
overlays_raw[tail_layer] = image(tail_s, icon_state = "[tail_style]_s")
animate_tail_reset(FALSE)
update_tail_accessory(FALSE)
if(update_icons)
update_icon()
/mob/living/carbon/human/proc/get_tail_icon()
if (QDELETED(src))
return
var/icon_key = "[species.race_key][r_skin][g_skin][b_skin][r_hair][g_hair][b_hair]"
var/icon/tail_icon = SSicon_cache.tail_icon_cache[icon_key]
if(!tail_icon)
//generate a new one
tail_icon = new/icon(icon = (species.tail_animation? species.tail_animation : 'icons/effects/species.dmi'))
tail_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
// The following will not work with animated tails.
if(species.tail_hair)
var/icon/hair_icon = icon('icons/effects/species.dmi', "[tail_style]_[species.tail_hair]")
hair_icon.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD)
tail_icon.Blend(hair_icon, ICON_OVERLAY)
SSicon_cache.tail_icon_cache[icon_key] = tail_icon
return tail_icon
/mob/living/carbon/human/proc/set_tail_state(var/mob_state, var/update = TRUE)
if(!tail_style)
return
var/tail_layer = GET_TAIL_LAYER
var/image/tail_overlay = overlays_raw[tail_layer]
var/obj/item/clothing/tail_accessory/TA = get_tail_accessory()
if(TA && !(tail_style in TA.compatible_animated_tail))
mob_state = "[tail_style]_static"
if(tail_overlay && species.tail_animation)
if(tail_overlay.icon_state != mob_state)
tail_overlay.icon_state = mob_state
update_tail_accessory(update)
return tail_overlay
return null
//Not really once, since BYOND can't do that.
//Update this if the ability to flick() images or make looping animation start at the first frame is ever added.
/mob/living/carbon/human/proc/animate_tail_once()
var/mob_state = "[tail_style]_once"
var/tail_layer = GET_TAIL_LAYER
var/image/tail_overlay = overlays_raw[tail_layer]
if(tail_overlay && tail_overlay.icon_state == mob_state)
return //let the existing animation finish
tail_overlay = set_tail_state(mob_state)
if(tail_overlay)
addtimer(CALLBACK(src, PROC_REF(end_animate_tail_once), tail_overlay), 20, TIMER_CLIENT_TIME)
/mob/living/carbon/human/proc/end_animate_tail_once(image/tail_overlay)
//check that the animation hasn't changed in the meantime
var/tail_layer = GET_TAIL_LAYER
if(overlays_raw[tail_layer] == tail_overlay && tail_overlay.icon_state == "[tail_style]_once")
animate_tail_stop()
update_tail_accessory()
/mob/living/carbon/human/proc/animate_tail_start()
set_tail_state("[tail_style]_slow")
/mob/living/carbon/human/proc/animate_tail_fast()
set_tail_state("[tail_style]_loop")
/mob/living/carbon/human/proc/animate_tail_reset(var/update = TRUE)
if(stat != DEAD && !lying)
set_tail_state("[tail_style]_idle", update)
else
set_tail_state("[tail_style]_static", update)
/mob/living/carbon/human/proc/animate_tail_stop(var/update_icons=1)
set_tail_state("[tail_style]_static")
/mob/living/carbon/human/proc/update_tail_accessory(var/update_icons=1)
overlays_raw[TAIL_NORTH_ACC_LAYER] = null
overlays_raw[TAIL_SOUTH_ACC_LAYER] = null
var/obj/item/clothing/tail_accessory/TA = get_tail_accessory()
if(!TA)
return
var/image/tail_overlay = overlays_raw[GET_TAIL_LAYER]
if(!tail_overlay)
return
overlays_raw[GET_TAIL_ACC_LAYER] = TA.get_mob_overlay(src, TA.icon, "[tail_overlay.icon_state]_to", slot_tail_str)
if(update_icons)
update_icon()
//Adds a collar overlay above the helmet layer if the suit has one
// Suit needs an identically named sprite in icons/mob/collar.dmi
/mob/living/carbon/human/proc/update_collar(var/update_icons=1)
if (QDELETED(src))
return
var/list/collar_mapping = SSicon_cache.collar_states
if (!collar_mapping)
SSicon_cache.setup_collar_mappings()
if(wear_suit && collar_mapping[wear_suit.icon_state])
overlays_raw[COLLAR_LAYER] = image('icons/mob/collar.dmi', wear_suit.icon_state)
else
overlays_raw[COLLAR_LAYER] = null
if(update_icons)
update_icon()
// update_fire()
/mob/living/carbon/human/update_fire(var/update_icons = TRUE)
if(QDELETED(src))
return
if(!on_fire)
set_light_on(FALSE)
else
set_light_on(TRUE)
var/image/fire_image_lower = on_fire ? image(species.onfire_overlay, "lower", layer = FIRE_LAYER_LOWER) : null
var/image/fire_image_upper = on_fire ? image(species.onfire_overlay, "upper", layer = FIRE_LAYER_UPPER) : null
overlays_raw[FIRE_LAYER_LOWER] = fire_image_lower
overlays_raw[FIRE_LAYER_UPPER] = fire_image_upper
if(update_icons)
update_icon()
/mob/living/carbon/human/proc/update_surgery(var/update_icons=1)
overlays_raw[SURGERY_LAYER] = null
var/image/total = new
for(var/obj/item/organ/external/E in organs)
if(E.status & ORGAN_ROBOT || E.is_stump())
continue
if(!E.open)
continue
var/surgery_icon = E.owner.species.get_surgery_overlay_icon(src)
if(!surgery_icon)
continue
var/list/surgery_states = icon_states(surgery_icon)
var/base_state = "[E.icon_name][E.open]"
var/overlay_state = "[base_state]-flesh"
var/list/overlays_to_add
if(overlay_state in surgery_states)
var/image/flesh = image(icon = surgery_icon, icon_state = overlay_state, layer = -SURGERY_LAYER)
flesh.color = E.owner.species.flesh_color
flesh.appearance_flags = RESET_ALPHA
LAZYADD(overlays_to_add, flesh)
overlay_state = "[base_state]-blood"
if(overlay_state in surgery_states)
var/image/blood = image(icon = surgery_icon, icon_state = overlay_state, layer = -SURGERY_LAYER)
blood.color = E.owner.get_blood_color()
blood.appearance_flags = RESET_ALPHA
LAZYADD(overlays_to_add, blood)
overlay_state = "[base_state]-bones"
if(overlay_state in surgery_states)
LAZYADD(overlays_to_add, image(icon = surgery_icon, icon_state = overlay_state, layer = -SURGERY_LAYER))
total.overlays |= overlays_to_add
overlays_raw[SURGERY_LAYER] = total
if(update_icons)
update_icon()
//Drawcheck functions
//These functions check if an item should be drawn, or if its covered up by something else
/mob/living/carbon/human/proc/check_draw_gloves()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!gloves)
return FALSE
else if (gloves.flags_inv & ALWAYSDRAW)
return TRUE
else if (wear_suit && (wear_suit.flags_inv & HIDEGLOVES))
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_right_ear()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!r_ear)
return FALSE
else if (r_ear.flags_inv & ALWAYSDRAW)
return TRUE
else if ((head && (head.flags_inv & (HIDEEARS))) || (wear_mask && (wear_mask.flags_inv & (HIDEEARS))))
return FALSE
return TRUE
/mob/living/carbon/human/proc/check_draw_left_ear()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!l_ear)
return FALSE
else if (l_ear.flags_inv & ALWAYSDRAW)
return TRUE
else if ((head && (head.flags_inv & (HIDEEARS))) || (wear_mask && (wear_mask.flags_inv & (HIDEEARS))))
return FALSE
return TRUE
/mob/living/carbon/human/proc/check_draw_glasses()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!glasses)
return FALSE
else if (glasses.flags_inv & ALWAYSDRAW)
return TRUE
else if( (head && (head.flags_inv & (HIDEEYES))) || (wear_mask && (wear_mask.flags_inv & (HIDEEYES))))
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_mask()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!wear_mask)
return FALSE
else if (wear_mask.flags_inv & ALWAYSDRAW)
return TRUE
else if( head && (head.flags_inv & HIDEEYES))
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_shoes()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!shoes)
return FALSE
else if (shoes.flags_inv & ALWAYSDRAW)
return TRUE
else if(wear_suit && (wear_suit.flags_inv & HIDESHOES))
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_underclothing()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!w_uniform)
return FALSE
else if (w_uniform.flags_inv & ALWAYSDRAW)
return TRUE
else if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT))
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_wrists()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!wrists)
return FALSE
else if (wrists.flags_inv & ALWAYSDRAW)
return TRUE
else if (wear_suit?.flags_inv & HIDEWRISTS)
return FALSE
else
return TRUE
/mob/living/carbon/human/proc/check_draw_pants()
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if (!pants)
return FALSE
else if (pants.flags_inv & ALWAYSDRAW)
return TRUE
else if (pants.flags_inv & HIDEPANTS)
return FALSE
else
return TRUE
#undef UNDERSCORE_OR_NULL
#undef GET_BODY_TYPE
#undef GET_TAIL_LAYER