diff --git a/code/__DEFINES/human.dm b/code/__DEFINES/human.dm index 846119d6b55d..ebf08f495752 100644 --- a/code/__DEFINES/human.dm +++ b/code/__DEFINES/human.dm @@ -116,14 +116,15 @@ #define ORDER_FOCUS_MAX_LEVEL 50 //Human Overlays Indexes used in update_icons///////// -#define UNDERWEAR_LAYER 41 -#define UNDERSHIRT_LAYER 40 -#define MUTANTRACE_LAYER 39 +#define BODYPARTS_LAYER 42 +#define DAMAGE_LAYER 41 -/// For use by Hunter Flay -#define FLAY_LAYER 38 +#define UNDERWEAR_LAYER 40 +#define UNDERSHIRT_LAYER 39 +#define MUTANTRACE_LAYER 38 -#define DAMAGE_LAYER 37 +/// For use by Hunter Flay +#define FLAY_LAYER 37 #define UNIFORM_LAYER 36 /// bs12 specific. this hack is probably gonna come back to haunt me @@ -176,7 +177,7 @@ /// If you're hit by an acid DoT #define EFFECTS_LAYER 1 -#define TOTAL_LAYERS 41 +#define TOTAL_LAYERS 42 ////////////////////////////////// //Synthetic Defines diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 39d91b2ada26..b2ac00098c69 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -323,215 +323,185 @@ world . = list(r, g, b) if(usealpha) . += alpha +/// Create a single [/icon] from a given [/atom] or [/image]. +/// +/// Very low-performance. Should usually only be used for HTML, where BYOND's +/// appearance system (overlays/underlays, etc.) is not available. +/// +/// Only the first argument is required. +/proc/getFlatIcon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE) + // Loop through the underlays, then overlays, sorting them into the layers list + #define PROCESS_OVERLAYS_OR_UNDERLAYS(flat, process, base_layer) \ + for (var/i in 1 to process.len) { \ + var/image/current = process[i]; \ + if (!current) { \ + continue; \ + } \ + if (current.plane != FLOAT_PLANE && current.plane != appearance.plane) { \ + continue; \ + } \ + var/current_layer = current.layer; \ + if (current_layer < 0) { \ + if (current_layer <= -1000) { \ + return flat; \ + } \ + current_layer = base_layer + appearance.layer + current_layer / 1000; \ + } \ + for (var/index_to_compare_to in 1 to layers.len) { \ + var/compare_to = layers[index_to_compare_to]; \ + if (current_layer < layers[compare_to]) { \ + layers.Insert(index_to_compare_to, current); \ + break; \ + } \ + } \ + layers[current] = current_layer; \ + } - -// Creates a single icon from a given /atom or /image. Only the first argument is required. -/proc/getFlatIcon(image/A, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE) - //Define... defines. var/static/icon/flat_template = icon('icons/effects/effects.dmi', "nothing") - #define BLANK icon(flat_template) - #define SET_SELF(SETVAR) do { \ - var/icon/SELF_ICON = icon(icon(curicon, curstate, base_icon_dir), "", SOUTH, no_anim ? 1 : null); \ - if(A.alpha < 255) { \ - SELF_ICON.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY);\ - } \ - if(A.color) { \ - if(islist(A.color)){ \ - SELF_ICON.MapColors(arglist(A.color))} \ - else{ \ - SELF_ICON.Blend(A.color, ICON_MULTIPLY)} \ - } \ - ##SETVAR=SELF_ICON;\ - } while (0) - #define INDEX_X_LOW 1 - #define INDEX_X_HIGH 2 - #define INDEX_Y_LOW 3 - #define INDEX_Y_HIGH 4 - - #define flatX1 flat_size[INDEX_X_LOW] - #define flatX2 flat_size[INDEX_X_HIGH] - #define flatY1 flat_size[INDEX_Y_LOW] - #define flatY2 flat_size[INDEX_Y_HIGH] - #define addX1 add_size[INDEX_X_LOW] - #define addX2 add_size[INDEX_X_HIGH] - #define addY1 add_size[INDEX_Y_LOW] - #define addY2 add_size[INDEX_Y_HIGH] - - if(!A || A.alpha <= 0) - return BLANK - - var/noIcon = FALSE + if(!appearance || appearance.alpha <= 0) + return icon(flat_template) + if(start) if(!defdir) - defdir = A.dir + defdir = appearance.dir if(!deficon) - deficon = A.icon + deficon = appearance.icon if(!defstate) - defstate = A.icon_state + defstate = appearance.icon_state if(!defblend) - defblend = A.blend_mode + defblend = appearance.blend_mode - var/curicon = A.icon || deficon - var/curstate = A.icon_state || defstate + var/curicon = appearance.icon || deficon + var/curstate = appearance.icon_state || defstate + var/curdir = (!appearance.dir || appearance.dir == SOUTH) ? defdir : appearance.dir - if(!(noIcon = (!curicon))) + var/render_icon = curicon + + if (render_icon) var/curstates = icon_states(curicon) if(!(curstate in curstates)) - if("" in curstates) + if ("" in curstates) curstate = "" else - noIcon = TRUE // Do not render this object. + render_icon = FALSE - var/curdir var/base_icon_dir //We'll use this to get the icon state to display if not null BUT NOT pass it to overlays as the dir we have - //These should use the parent's direction (most likely) - if(!A.dir || A.dir == SOUTH) - curdir = defdir - else - curdir = A.dir - //Try to remove/optimize this section ASAP, CPU hog. //Determines if there's directionals. - if(!noIcon && curdir != SOUTH) - var/exist = FALSE - var/static/list/checkdirs = list(NORTH, EAST, WEST) - for(var/i in checkdirs) //Not using GLOB for a reason. - if(length(icon_states(icon(curicon, curstate, i)))) - exist = TRUE - break - if(!exist) + if(render_icon && curdir != SOUTH) + if ( + !length(icon_states(icon(curicon, curstate, NORTH))) \ + && !length(icon_states(icon(curicon, curstate, EAST))) \ + && !length(icon_states(icon(curicon, curstate, WEST))) \ + ) base_icon_dir = SOUTH if(!base_icon_dir) base_icon_dir = curdir - ASSERT(!BLEND_DEFAULT) //I might just be stupid but lets make sure this define is 0. - - var/curblend = A.blend_mode || defblend + var/curblend = appearance.blend_mode || defblend - if(length(A.overlays) || length(A.underlays)) - var/icon/flat = BLANK + if(appearance.overlays.len || appearance.underlays.len) + var/icon/flat = icon(flat_template) // Layers will be a sorted list of icons/overlays, based on the order in which they are displayed var/list/layers = list() var/image/copy // Add the atom's icon itself, without pixel_x/y offsets. - if(!noIcon) - copy = image(icon = curicon, icon_state = curstate, layer = A.layer, dir = base_icon_dir) - copy.color = A.color - copy.alpha = A.alpha + if(render_icon) + copy = image(icon=curicon, icon_state=curstate, layer=appearance.layer, dir=base_icon_dir) + copy.color = appearance.color + copy.alpha = appearance.alpha copy.blend_mode = curblend - layers[copy] = A.layer - - // Loop through the underlays, then overlays, sorting them into the layers list - for(var/process_set in 0 to 2) - var/list/process = process_set ? A.overlays : A.underlays - switch(process_set) - if(0) - process = A.underlays - if(1) - process = A.vis_contents - if(2) - process = A.overlays - for(var/i in 1 to length(process)) - var/image/current = process[i] - if(!current) - continue - if(current.plane != FLOAT_PLANE && current.plane != A.plane) - continue - if(process_set == 1 && !istype(current)) - current = image(icon = current.icon, icon_state = current.icon_state, layer = current.layer, dir = current.dir) - var/current_layer = current.layer - if(current_layer < 0) - if(current_layer <= -1000) - return flat - current_layer = process_set + A.layer + current_layer / 1000 - - for(var/p in 1 to length(layers)) - var/image/cmp = layers[p] - if(current_layer < layers[cmp]) - layers.Insert(p, current) - break - layers[current] = current_layer + layers[copy] = appearance.layer + + PROCESS_OVERLAYS_OR_UNDERLAYS(flat, appearance.underlays, 0) + PROCESS_OVERLAYS_OR_UNDERLAYS(flat, appearance.overlays, 1) var/icon/add // Icon of overlay being added - // Current dimensions of flattened icon - var/list/flat_size = list(1, flat.Width(), 1, flat.Height()) - // Dimensions of overlay being added - var/list/add_size[4] + var/flatX1 = 1 + var/flatX2 = flat.Width() + var/flatY1 = 1 + var/flatY2 = flat.Height() + + var/addX1 = 0 + var/addX2 = 0 + var/addY1 = 0 + var/addY2 = 0 - for(var/V in layers) - var/image/I = V - if(I.alpha == 0) + for(var/image/layer_image as anything in layers) + if(layer_image.alpha == 0) continue - if(I == copy) // 'I' is an /image based on the object being flattened. + if(layer_image == copy) // 'layer_image' is an /image based on the object being flattened. curblend = BLEND_OVERLAY - add = icon(I.icon, I.icon_state, base_icon_dir) + add = icon(layer_image.icon, layer_image.icon_state, base_icon_dir) else // 'I' is an appearance object. - add = getFlatIcon(image(I), curdir, curicon, curstate, curblend, FALSE, no_anim) + add = getFlatIcon(image(layer_image), curdir, curicon, curstate, curblend, FALSE, no_anim) if(!add) continue + // Find the new dimensions of the flat icon to fit the added overlay - add_size = list( - min(flatX1, I.pixel_x+1), - max(flatX2, I.pixel_x+add.Width()), - min(flatY1, I.pixel_y+1), - max(flatY2, I.pixel_y+add.Height()) + addX1 = min(flatX1, layer_image.pixel_x + 1) + addX2 = max(flatX2, layer_image.pixel_x + add.Width()) + addY1 = min(flatY1, layer_image.pixel_y + 1) + addY2 = max(flatY2, layer_image.pixel_y + add.Height()) + + if ( + addX1 != flatX1 \ + && addX2 != flatX2 \ + && addY1 != flatY1 \ + && addY2 != flatY2 \ ) - - if(flat_size ~! add_size) // Resize the flattened icon so the new icon fits flat.Crop( - addX1 - flatX1 + 1, - addY1 - flatY1 + 1, - addX2 - flatX1 + 1, - addY2 - flatY1 + 1 + addX1 - flatX1 + 1, + addY1 - flatY1 + 1, + addX2 - flatX1 + 1, + addY2 - flatY1 + 1 ) - flat_size = add_size.Copy() + + flatX1 = addX1 + flatX2 = addY1 + flatY1 = addX2 + flatY2 = addY2 // Blend the overlay into the flattened icon - flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1) + flat.Blend(add, blendMode2iconMode(curblend), layer_image.pixel_x + 2 - flatX1, layer_image.pixel_y + 2 - flatY1) - if(A.color) - if(islist(A.color)) - flat.MapColors(arglist(A.color)) + if(appearance.color) + if(islist(appearance.color)) + flat.MapColors(arglist(appearance.color)) else - flat.Blend(A.color, ICON_MULTIPLY) + flat.Blend(appearance.color, ICON_MULTIPLY) - if(A.alpha < 255) - flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) + if(appearance.alpha < 255) + flat.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY) if(no_anim) //Clean up repeated frames var/icon/cleaned = new /icon() cleaned.Insert(flat, "", SOUTH, 1, 0) - . = cleaned + return cleaned else - . = icon(flat, "", SOUTH) - else //There's no overlays. - if(!noIcon) - SET_SELF(.) - - //Clear defines - #undef flatX1 - #undef flatX2 - #undef flatY1 - #undef flatY2 - #undef addX1 - #undef addX2 - #undef addY1 - #undef addY2 - - #undef INDEX_X_LOW - #undef INDEX_X_HIGH - #undef INDEX_Y_LOW - #undef INDEX_Y_HIGH - - #undef BLANK - #undef SET_SELF + return icon(flat, "", SOUTH) + else if (render_icon) // There's no overlays. + var/icon/final_icon = icon(icon(curicon, curstate, base_icon_dir), "", SOUTH, no_anim ? TRUE : null) + + if (appearance.alpha < 255) + final_icon.Blend(rgb(255,255,255, appearance.alpha), ICON_MULTIPLY) + + if (appearance.color) + if (islist(appearance.color)) + final_icon.MapColors(arglist(appearance.color)) + else + final_icon.Blend(appearance.color, ICON_MULTIPLY) + + return final_icon + + #undef PROCESS_OVERLAYS_OR_UNDERLAYS /proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 7c7ad7a0166b..4416ba74fda3 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -162,6 +162,12 @@ ///list of weakrefs of recently dropped objects var/list/remembered_dropped_objects = list() + /// associated list of body part zone -> currently active limb key + var/list/icon_render_keys = list() + + /// static associated list of limb key -> image to avoid unnecessary overlay generation + var/static/list/icon_render_image_cache = list() + /client/var/cached_human_playtime /client/proc/get_total_human_playtime(skip_cache = FALSE) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 88887126b1c1..5fa8b577e8c2 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -73,14 +73,14 @@ There are several things that need to be remembered: */ +/mob/living/carbon/human/apply_overlay(cache_index) + var/image/images = overlays_standing[cache_index] + if(!images) + return -/mob/living/carbon/human/apply_overlay(cache_index) - var/image/I = overlays_standing[cache_index] - if(I) - I.appearance_flags |= RESET_COLOR - SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, I) - overlays += I + SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, images) + overlays += images /mob/living/carbon/human/remove_overlay(cache_index) if(overlays_standing[cache_index]) @@ -132,10 +132,32 @@ There are several things that need to be remembered: //BASE MOB SPRITE /mob/living/carbon/human/proc/update_body() appearance_flags |= KEEP_TOGETHER // sanity - vis_contents.Cut() - for(var/obj/limb/part in limbs) - vis_contents += part - part.update_icon(TRUE) + + update_damage_overlays() + + var/list/needs_update = list() + for(var/obj/limb/part as anything in limbs) + part.update_limb() + + var/old_key = icon_render_keys?[part.icon_name] + icon_render_keys[part.icon_name] = part.get_limb_icon_key() + if(icon_render_keys[part.icon_name] == old_key) + continue + + needs_update += part + + var/list/new_limbs = list() + for(var/obj/limb/part as anything in limbs) + if(part in needs_update) + var/bodypart_icon = part.get_limb_icon() + new_limbs += bodypart_icon + icon_render_image_cache[icon_render_keys[part.icon_name]] = bodypart_icon + else + new_limbs += icon_render_image_cache[icon_render_keys[part.icon_name]] + + remove_overlay(BODYPARTS_LAYER) + overlays_standing[BODYPARTS_LAYER] = new_limbs + apply_overlay(BODYPARTS_LAYER) if(species.flags & HAS_UNDERWEAR) //Underwear @@ -154,6 +176,21 @@ There are several things that need to be remembered: overlays_standing[UNDERSHIRT_LAYER] = undershirt_icon apply_overlay(UNDERSHIRT_LAYER) +/// Recalculates and reapplies damage overlays to every limb +/mob/living/carbon/human/proc/update_damage_overlays() + remove_overlay(DAMAGE_LAYER) + + var/list/damage_overlays = list() + for(var/obj/limb/part as anything in limbs) + if(part.status & LIMB_DESTROYED) + continue + + damage_overlays += part.get_damage_overlays() + + overlays_standing[DAMAGE_LAYER] = damage_overlays + + apply_overlay(DAMAGE_LAYER) + /mob/living/carbon/human/proc/remove_underwear() // :flushed: - geeves remove_overlay(UNDERSHIRT_LAYER) remove_overlay(UNDERWEAR_LAYER) @@ -739,7 +776,6 @@ Applied by gun suicide and high impact bullet executions, removed by rejuvenate, //Human Overlays Indexes///////// #undef MUTANTRACE_LAYER -#undef DAMAGE_LAYER #undef UNIFORM_LAYER #undef TAIL_LAYER #undef ID_LAYER diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 7d0261d971b9..58d0a4780681 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -71,6 +71,19 @@ var/status = LIMB_ORGANIC var/processing = FALSE + /// ethnicity of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()] + var/ethnicity = "western" + + /// body type of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()] + var/body_type = "mesomorphic" + + /// species of the owner, used for limb appearance, set in [/obj/limb/proc/update_limb()] + var/datum/species/species + + /// defines which sprite the limb should use if dimorphic, set in [/obj/limb/proc/update_limb()] + var/limb_gender = MALE + + /obj/limb/Initialize(mapload, obj/limb/P, mob/mob_owner) . = ..() if(P) @@ -81,12 +94,10 @@ if(mob_owner) owner = mob_owner - wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0") - wound_overlay.blend_mode = BLEND_INSET_OVERLAY + wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0", -DAMAGE_LAYER) wound_overlay.color = owner?.species.blood_color - burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0") - burn_overlay.blend_mode = BLEND_INSET_OVERLAY + burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0", -DAMAGE_LAYER) if(owner) forceMove(owner) @@ -361,7 +372,7 @@ SEND_SIGNAL(src, COMSIG_LIMB_TAKEN_DAMAGE, is_ff, previous_brute, previous_burn) owner.updatehealth() - update_icon() + owner.update_damage_overlays() start_processing() ///Special delimbs for different limbs @@ -651,7 +662,7 @@ This function completely restores a damaged organ to perfect condition. // sync the organ's damage with its wounds update_damages() - update_icon() + owner.update_damage_overlays() if(wound_disappeared) owner.update_med_icon() remove_wound_bleeding() @@ -670,74 +681,66 @@ This function completely restores a damaged organ to perfect condition. number_wounds += W.amount -/obj/limb/update_icon(forced = FALSE) - if(parent && parent.status & LIMB_DESTROYED) - overlays.Cut() - icon_state = "" - return +/// updates the various internal variables of the limb from the owner +/obj/limb/proc/update_limb() + SHOULD_CALL_PARENT(TRUE) - if(status & LIMB_DESTROYED) - if(forced) - overlays.Cut() - if(has_stump_icon && !(status & LIMB_AMPUTATED)) - icon = 'icons/mob/humans/dam_human.dmi' - icon_state = "stump_[icon_name]_bone" - var/image/blood_overlay = new('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood") - blood_overlay.color = owner.species.blood_color - overlays += blood_overlay - else - icon_state = "" - return + var/datum/ethnicity/owner_ethnicity = GLOB.ethnicities_list[owner?.ethnicity] - var/race_icon = owner.species.icobase + if(owner_ethnicity) + ethnicity = owner_ethnicity.icon_name + else + ethnicity = "western" - if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) - overlays.Cut() - icon = 'icons/mob/robotic.dmi' - icon_state = "[icon_name]" - return + var/datum/body_type/owner_body_type = GLOB.body_types_list[owner?.body_type] - var/datum/ethnicity/E = GLOB.ethnicities_list[owner.ethnicity] - var/datum/body_type/B = GLOB.body_types_list[owner.body_type] + if(owner_body_type) + body_type = owner_body_type.icon_name + else + body_type = "mesomorphic" - var/e_icon - var/b_icon + if(isspeciesyautja(owner)) + ethnicity = owner.ethnicity + body_type = owner.body_type - if (!E) - e_icon = "western" - else - e_icon = E.icon_name + species = owner?.species ? owner.species : GLOB.all_species[SPECIES_HUMAN] + limb_gender = owner?.gender ? owner.gender : FEMALE - if (!B) - b_icon = "mesomorphic" - else - b_icon = B.icon_name +/// generates a list of overlays that should be applied to the owner +/obj/limb/proc/get_limb_icon() + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) - if(isspeciesyautja(owner)) - e_icon = owner.ethnicity - b_icon = owner.body_type + . = list() - icon = race_icon - icon_state = "[get_limb_icon_name(owner.species, b_icon, owner.gender, icon_name, e_icon)]" - wound_overlay.color = owner.species.blood_color + if(parent?.status & LIMB_DESTROYED) + return - var/n_is = damage_state_text() - if (forced || n_is != damage_state) - overlays.Cut() - damage_state = n_is - update_overlays() + if(status & LIMB_DESTROYED) + if(has_stump_icon && !(status & LIMB_AMPUTATED)) + . += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER) + return + var/image/limb = image(layer = -BODYPARTS_LAYER) -/obj/limb/proc/update_overlays() - var/brutestate = copytext(damage_state, 1, 2) - var/burnstate = copytext(damage_state, 2) - if(brutestate != "0") - wound_overlay.icon_state = "grayscale_[brutestate]" - overlays += wound_overlay + if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) + limb.icon = 'icons/mob/robotic.dmi' + limb.icon_state = "[icon_name]" + . += limb + return - if(burnstate != "0") - burn_overlay.icon_state = "burn_[burnstate]" - overlays += burn_overlay + limb.icon = species.icobase + limb.icon_state = "[get_limb_icon_name(species, body_type, limb_gender, icon_name, ethnicity)]" + + . += limb + + return + +/// generates a key for the purpose of caching the icon to avoid duplicate generations +/obj/limb/proc/get_limb_icon_key() + SHOULD_CALL_PARENT(TRUE) + + return "[species.name]-[body_type]-[limb_gender]-[icon_name]-[ethnicity]-[status]" // new damage icon system // returns just the brute/burn damage code @@ -774,7 +777,7 @@ This function completely restores a damaged organ to perfect condition. //Recursive setting of self and all child organs to amputated /obj/limb/proc/setAmputatedTree() status |= LIMB_AMPUTATED - update_icon(TRUE) + owner.update_body() for(var/obj/limb/O as anything in children) O.setAmputatedTree() @@ -1140,7 +1143,7 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit for(var/obj/limb/T as anything in children) T.robotize(uncalibrated = uncalibrated, synth_skin = synth_skin) - update_icon(TRUE) + owner.update_body(TRUE) /obj/limb/proc/calibrate_prosthesis() status &= ~LIMB_UNCALIBRATED_PROSTHETIC @@ -1243,6 +1246,20 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit owner.incision_depths[name] = SURGERY_DEPTH_SURFACE owner.active_surgeries[name] = null +/obj/limb/proc/get_damage_overlays() + . = list() + + damage_state = damage_state_text() + var/brutestate = copytext(damage_state, 1, 2) + if(brutestate != "0") + wound_overlay.icon_state = "grayscale_[icon_name]_[brutestate]" + . += wound_overlay + + var/burnstate = copytext(damage_state, 2) + if(burnstate != "0") + burn_overlay.icon_state = "burn_[icon_name]_[burnstate]" + . += wound_overlay + /* LIMB TYPES */ @@ -1389,17 +1406,36 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit bandage_icon_amount = 4 var/disfigured = 0 //whether the head is disfigured. -///Specifically, damage overlays. Severed limb gore effects are applied elsewhere. -/obj/limb/head/update_overlays() - ..() + var/eyes_r + var/eyes_g + var/eyes_b + + var/lip_style + +/obj/limb/head/update_limb() + . = ..() + + eyes_r = owner.r_eyes + eyes_g = owner.g_eyes + eyes_b = owner.b_eyes - var/image/eyes = new/image('icons/mob/humans/onmob/human_face.dmi', owner.species.eyes) + lip_style = owner.lip_style + +/obj/limb/head/get_limb_icon() + . = ..() + + var/image/eyes = image('icons/mob/humans/onmob/human_face.dmi', species.eyes, layer = -BODYPARTS_LAYER) eyes.color = list(null, null, null, null, rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) - overlays += eyes + . += eyes + + if(lip_style && (species && species.flags & HAS_LIPS)) + var/image/lips = image('icons/mob/humans/onmob/human_face.dmi', "paint_[lip_style]", layer = -BODYPARTS_LAYER) + . += lips + +/obj/limb/head/get_limb_icon_key() + . = ..() - if(owner.lip_style && (owner.species && owner.species.flags & HAS_LIPS)) - var/icon/lips = new /icon('icons/mob/humans/onmob/human_face.dmi', "paint_[owner.lip_style]") - overlays += lips + return "[.]-[eyes_r]-[eyes_g]-[eyes_b]-[lip_style]" /obj/limb/head/take_damage(brute, burn, sharp, edge, used_weapon = null,\ list/forbidden_limbs = list(), no_limb_loss,\ diff --git a/icons/mob/humans/dam_human.dmi b/icons/mob/humans/dam_human.dmi index 88cbb883db18..ba8a25565693 100644 Binary files a/icons/mob/humans/dam_human.dmi and b/icons/mob/humans/dam_human.dmi differ