From ea92ff906dbaf4bde61c98400f60b1b8cd94d8b8 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Wed, 30 Aug 2023 21:23:58 +0100 Subject: [PATCH 01/12] heavy wip overlay limbs --- code/__DEFINES/human.dm | 15 ++-- .../mob/living/carbon/human/update_icons.dm | 29 +++++-- code/modules/organs/limbs.dm | 83 ++++++++++++++++++- 3 files changed, 109 insertions(+), 18 deletions(-) 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/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 88887126b1c1..3bd2927a4f60 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -76,11 +76,16 @@ There are several things that need to be remembered: /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 + var/list/images = overlays_standing[cache_index] + + if(!islist(images)) + images = list(images) + + if(length(images)) + for(var/image/current_image as anything in images) + current_image.appearance_flags |= RESET_COLOR + 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 +137,17 @@ 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() + var/list/new_limbs = list() for(var/obj/limb/part in limbs) - vis_contents += part - part.update_icon(TRUE) + var/bodypart_icon = part.get_limb_icon() + new_limbs += bodypart_icon + + remove_overlay(BODYPARTS_LAYER) + + if(length(new_limbs)) + overlays_standing[BODYPARTS_LAYER] = new_limbs + + apply_overlay(BODYPARTS_LAYER) if(species.flags & HAS_UNDERWEAR) //Underwear @@ -739,7 +751,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..f9503ee54ce8 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -81,11 +81,11 @@ if(mob_owner) owner = mob_owner - wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0") + wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0", -DAMAGE_LAYER) wound_overlay.blend_mode = BLEND_INSET_OVERLAY wound_overlay.color = owner?.species.blood_color - burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0") + burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0", -DAMAGE_LAYER) burn_overlay.blend_mode = BLEND_INSET_OVERLAY if(owner) @@ -739,6 +739,74 @@ This function completely restores a damaged organ to perfect condition. burn_overlay.icon_state = "burn_[burnstate]" overlays += burn_overlay +/obj/limb/proc/get_limb_icon(dropped) + SHOULD_CALL_PARENT(TRUE) + RETURN_TYPE(/list) + + icon_state = "" + + . = list() + + if(parent?.status & LIMB_DESTROYED) + return + + var/image_dir = dropped ? SOUTH : NONE + + if(status & LIMB_DESTROYED) + if(has_stump_icon && !(status & LIMB_AMPUTATED)) + . += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER, image_dir) + return + + damage_state = damage_state_text() + var/brutestate = copytext(damage_state, 1, 2) + if(brutestate != "0") + wound_overlay.dir = image_dir + wound_overlay.icon_state = "grayscale_[brutestate]" + . += wound_overlay + + var/burnstate = copytext(damage_state, 2) + if(burnstate != "0") + burn_overlay.dir = image_dir + burn_overlay.icon_state = "burn_[burnstate]" + . += burn_overlay + + var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) + + var/race_icon = owner.species.icobase + + if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) + limb.icon = 'icons/mob/robotic.dmi' + limb.icon_state = "[icon_name]" + . += limb + return + + var/datum/ethnicity/E = GLOB.ethnicities_list[owner.ethnicity] + var/datum/body_type/B = GLOB.body_types_list[owner.body_type] + + var/e_icon + var/b_icon + + if (!E) + e_icon = "western" + else + e_icon = E.icon_name + + if (!B) + b_icon = "mesomorphic" + else + b_icon = B.icon_name + + if(isspeciesyautja(owner)) + e_icon = owner.ethnicity + b_icon = owner.body_type + + limb.icon = race_icon + limb.icon_state = "[get_limb_icon_name(owner.species, b_icon, owner.gender, icon_name, e_icon)]" + + . += limb + + return + // new damage icon system // returns just the brute/burn damage code /obj/limb/proc/damage_state_text() @@ -1401,6 +1469,17 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit var/icon/lips = new /icon('icons/mob/humans/onmob/human_face.dmi', "paint_[owner.lip_style]") overlays += lips +/obj/limb/head/get_limb_icon(dropped) + . = ..() + + var/image/eyes = image('icons/mob/humans/onmob/human_face.dmi', owner.species.eyes, layer = -BODYPARTS_LAYER) + eyes.color = list(null, null, null, null, rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) + . += eyes + + if(owner.lip_style && (owner.species && owner.species.flags & HAS_LIPS)) + var/image/lips = image('icons/mob/humans/onmob/human_face.dmi', "paint_[owner.lip_style]", layer = -BODYPARTS_LAYER) + . += lips + /obj/limb/head/take_damage(brute, burn, sharp, edge, used_weapon = null,\ list/forbidden_limbs = list(), no_limb_loss,\ mob/attack_source = null,\ From 76024e21e0e61916e4b7779d6c780708ee8869d6 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Wed, 30 Aug 2023 23:15:27 +0100 Subject: [PATCH 02/12] ci fix --- .../mob/living/carbon/human/update_icons.dm | 24 +++++++++++++---- code/modules/organs/limbs.dm | 27 ++++++++++--------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 3bd2927a4f60..a1e827f26cf6 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -137,16 +137,16 @@ There are several things that need to be remembered: //BASE MOB SPRITE /mob/living/carbon/human/proc/update_body() appearance_flags |= KEEP_TOGETHER // sanity + + update_damage_overlays() + var/list/new_limbs = list() - for(var/obj/limb/part in limbs) + for(var/obj/limb/part as anything in limbs) var/bodypart_icon = part.get_limb_icon() new_limbs += bodypart_icon remove_overlay(BODYPARTS_LAYER) - - if(length(new_limbs)) - overlays_standing[BODYPARTS_LAYER] = new_limbs - + overlays_standing[BODYPARTS_LAYER] = new_limbs apply_overlay(BODYPARTS_LAYER) if(species.flags & HAS_UNDERWEAR) @@ -166,6 +166,20 @@ There are several things that need to be remembered: overlays_standing[UNDERSHIRT_LAYER] = undershirt_icon apply_overlay(UNDERSHIRT_LAYER) +/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) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index f9503ee54ce8..0ea59711171c 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -757,19 +757,6 @@ This function completely restores a damaged organ to perfect condition. . += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER, image_dir) return - damage_state = damage_state_text() - var/brutestate = copytext(damage_state, 1, 2) - if(brutestate != "0") - wound_overlay.dir = image_dir - wound_overlay.icon_state = "grayscale_[brutestate]" - . += wound_overlay - - var/burnstate = copytext(damage_state, 2) - if(burnstate != "0") - burn_overlay.dir = image_dir - burn_overlay.icon_state = "burn_[burnstate]" - . += burn_overlay - var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) var/race_icon = owner.species.icobase @@ -1311,6 +1298,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_[brutestate]" + . += wound_overlay + + var/burnstate = copytext(damage_state, 2) + if(burnstate != "0") + burn_overlay.icon_state = "burn_[burnstate]" + . += wound_overlay + /* LIMB TYPES */ From d561774a317282c06daaea08f7fd4a7fb1e067f7 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Wed, 30 Aug 2023 23:47:30 +0100 Subject: [PATCH 03/12] turning in your stomach and making you feel sick --- .../mob/living/carbon/human/update_icons.dm | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index a1e827f26cf6..92291daa38f4 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -76,16 +76,20 @@ There are several things that need to be remembered: /mob/living/carbon/human/apply_overlay(cache_index) - var/list/images = overlays_standing[cache_index] + var/image/images = overlays_standing[cache_index] - if(!islist(images)) - images = list(images) + if(!images) + return - if(length(images)) - for(var/image/current_image as anything in images) + if(islist(images)) + var/list/overlays = images + for(var/image/current_image as anything in overlays) current_image.appearance_flags |= RESET_COLOR - SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, images) - overlays += images + else + images.appearance_flags |= RESET_COLOR + + 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]) From 749cad0814cc6aece74a8bf44bb26453966fc9f5 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:05:51 +0100 Subject: [PATCH 04/12] improved caching and refactor --- .../mob/living/carbon/human/human_defines.dm | 3 + .../mob/living/carbon/human/update_icons.dm | 19 ++- code/modules/organs/limbs.dm | 159 ++++++------------ 3 files changed, 75 insertions(+), 106 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 7c7ad7a0166b..e392df74f56a 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -162,6 +162,9 @@ ///list of weakrefs of recently dropped objects var/list/remembered_dropped_objects = list() + var/list/icon_render_keys = list() + 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 92291daa38f4..a7f0c26d7f76 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -144,10 +144,25 @@ There are several things that need to be remembered: 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) - var/bodypart_icon = part.get_limb_icon() - new_limbs += bodypart_icon + 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 diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 0ea59711171c..718e1c7a0b6f 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -71,6 +71,13 @@ var/status = LIMB_ORGANIC var/processing = FALSE + var/ethnicity = "western" + var/body_type = "mesomorphic" + + var/datum/species/species + var/limb_gender = MALE + + /obj/limb/Initialize(mapload, obj/limb/P, mob/mob_owner) . = ..() if(P) @@ -361,7 +368,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 +658,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,76 +677,31 @@ 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 - - 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/race_icon = owner.species.icobase - - 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/ethnicity/E = GLOB.ethnicities_list[owner.ethnicity] - var/datum/body_type/B = GLOB.body_types_list[owner.body_type] +/obj/limb/proc/update_limb() + SHOULD_CALL_PARENT(TRUE) - var/e_icon - var/b_icon + var/datum/ethnicity/owner_ethnicity = GLOB.ethnicities_list[owner.ethnicity] - if (!E) - e_icon = "western" + if(owner_ethnicity) + ethnicity = owner_ethnicity.icon_name else - e_icon = E.icon_name + ethnicity = "western" + + var/datum/body_type/owner_body_type = GLOB.body_types_list[owner.body_type] - if (!B) - b_icon = "mesomorphic" + if(owner_body_type) + body_type = owner_body_type.icon_name else - b_icon = B.icon_name + body_type = "mesomorphic" if(isspeciesyautja(owner)) - e_icon = owner.ethnicity - b_icon = owner.body_type - - 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 - - var/n_is = damage_state_text() - if (forced || n_is != damage_state) - overlays.Cut() - damage_state = n_is - update_overlays() - - -/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 + ethnicity = owner.ethnicity + body_type = owner.body_type - if(burnstate != "0") - burn_overlay.icon_state = "burn_[burnstate]" - overlays += burn_overlay + species = owner.species + limb_gender = owner.gender -/obj/limb/proc/get_limb_icon(dropped) +/obj/limb/proc/get_limb_icon() SHOULD_CALL_PARENT(TRUE) RETURN_TYPE(/list) @@ -750,16 +712,14 @@ This function completely restores a damaged organ to perfect condition. if(parent?.status & LIMB_DESTROYED) return - var/image_dir = dropped ? SOUTH : NONE - if(status & LIMB_DESTROYED) if(has_stump_icon && !(status & LIMB_AMPUTATED)) - . += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER, image_dir) + . += image('icons/mob/humans/dam_human.dmi', "stump_[icon_name]_blood", -DAMAGE_LAYER) return - var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir) + var/image/limb = image(layer = -BODYPARTS_LAYER) - var/race_icon = owner.species.icobase + var/race_icon = species.icobase if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) limb.icon = 'icons/mob/robotic.dmi' @@ -767,33 +727,16 @@ This function completely restores a damaged organ to perfect condition. . += limb return - var/datum/ethnicity/E = GLOB.ethnicities_list[owner.ethnicity] - var/datum/body_type/B = GLOB.body_types_list[owner.body_type] - - var/e_icon - var/b_icon - - if (!E) - e_icon = "western" - else - e_icon = E.icon_name - - if (!B) - b_icon = "mesomorphic" - else - b_icon = B.icon_name - - if(isspeciesyautja(owner)) - e_icon = owner.ethnicity - b_icon = owner.body_type - limb.icon = race_icon - limb.icon_state = "[get_limb_icon_name(owner.species, b_icon, owner.gender, icon_name, e_icon)]" + limb.icon_state = "[get_limb_icon_name(species, body_type, limb_gender, icon_name, ethnicity)]" . += limb return +/obj/limb/proc/get_limb_icon_key() + return "[species.name]-[body_type]-[limb_gender]-[icon_name]-[ethnicity]" + // new damage icon system // returns just the brute/burn damage code /obj/limb/proc/damage_state_text() @@ -829,7 +772,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() @@ -1195,7 +1138,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 @@ -1458,29 +1401,37 @@ 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/image/eyes = new/image('icons/mob/humans/onmob/human_face.dmi', owner.species.eyes) - eyes.color = list(null, null, null, null, rgb(owner.r_eyes, owner.g_eyes, owner.b_eyes)) - overlays += eyes + var/lip_style - 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 +/obj/limb/head/update_limb() + . = ..() -/obj/limb/head/get_limb_icon(dropped) + eyes_r = owner.r_eyes + eyes_g = owner.g_eyes + eyes_b = owner.b_eyes + + lip_style = owner.lip_style + +/obj/limb/head/get_limb_icon() . = ..() - var/image/eyes = image('icons/mob/humans/onmob/human_face.dmi', owner.species.eyes, layer = -BODYPARTS_LAYER) + 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)) . += eyes - if(owner.lip_style && (owner.species && owner.species.flags & HAS_LIPS)) - var/image/lips = image('icons/mob/humans/onmob/human_face.dmi', "paint_[owner.lip_style]", layer = -BODYPARTS_LAYER) + 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() + . = ..() + + 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,\ mob/attack_source = null,\ From 4c7e73df6fb259a27622f7997d98da0decbdbc39 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:21:27 +0100 Subject: [PATCH 05/12] fixes damage overlays --- .../mob/living/carbon/human/update_icons.dm | 12 ------------ code/modules/organs/limbs.dm | 4 ++-- icons/mob/humans/dam_human.dmi | Bin 14394 -> 19005 bytes 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index a7f0c26d7f76..d56c4efd1c9c 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -73,21 +73,9 @@ 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 - - if(islist(images)) - var/list/overlays = images - for(var/image/current_image as anything in overlays) - current_image.appearance_flags |= RESET_COLOR - else - images.appearance_flags |= RESET_COLOR - SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, images) overlays += images diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 718e1c7a0b6f..459ebb7103b4 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -1247,12 +1247,12 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit damage_state = damage_state_text() var/brutestate = copytext(damage_state, 1, 2) if(brutestate != "0") - wound_overlay.icon_state = "grayscale_[brutestate]" + wound_overlay.icon_state = "grayscale_[icon_name]_[brutestate]" . += wound_overlay var/burnstate = copytext(damage_state, 2) if(burnstate != "0") - burn_overlay.icon_state = "burn_[burnstate]" + burn_overlay.icon_state = "burn_[icon_name1]_[burnstate]" . += wound_overlay /* diff --git a/icons/mob/humans/dam_human.dmi b/icons/mob/humans/dam_human.dmi index 88cbb883db18d280918c9b9098a41eca6ae5e41d..10f20ab2df616cdaeefe16d0e39483ba737acd0d 100644 GIT binary patch literal 19005 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 z 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 B6&U~k literal 14394 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 From 8eda2d4b5d3720a53696c2f5c641ac62651a5032 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 31 Aug 2023 15:31:16 +0100 Subject: [PATCH 06/12] greyscale -> grayscale (dumbdumb) --- code/modules/organs/limbs.dm | 4 +--- icons/mob/humans/dam_human.dmi | Bin 19005 -> 19005 bytes 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 459ebb7103b4..a3a774a73ba7 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -89,11 +89,9 @@ owner = mob_owner wound_overlay = image('icons/mob/humans/dam_human.dmi', "grayscale_0", -DAMAGE_LAYER) - wound_overlay.blend_mode = BLEND_INSET_OVERLAY wound_overlay.color = owner?.species.blood_color burn_overlay = image('icons/mob/humans/dam_human.dmi', "burn_0", -DAMAGE_LAYER) - burn_overlay.blend_mode = BLEND_INSET_OVERLAY if(owner) forceMove(owner) @@ -1252,7 +1250,7 @@ treat_grafted var tells it to apply to grafted but unsalved wounds, for burn kit var/burnstate = copytext(damage_state, 2) if(burnstate != "0") - burn_overlay.icon_state = "burn_[icon_name1]_[burnstate]" + burn_overlay.icon_state = "burn_[icon_name]_[burnstate]" . += wound_overlay /* diff --git a/icons/mob/humans/dam_human.dmi b/icons/mob/humans/dam_human.dmi index 10f20ab2df616cdaeefe16d0e39483ba737acd0d..ba8a2556569343931a020ae32f110330b3960980 100644 GIT binary patch delta 442 zcmV;r0Y(13lmWez0gzA(a*6{;21gH*Dz`7-kz5&nYw2p+W^dX4%vvTVz*6` zO4nuO{GxNp>EUrz^^Iy*X;ReE4eL#sTtzk7KmS(cn_0L2PqzhiyQr>neRIoAUa7Xo zFUHz}wAfaI4&jFgJ;dZn8ge6(gV_f=Lf8=|zgp|aZFmc_4|<5uLriXTNp56vF#BLf z2s@&G(uymtHy{Jdcx6obu7XcvX+j1yx~Thxo%F|rj2hJU2RmtLLI&NG(a!1U?OKX@ zbYFwmA58q3T^Qo`?ZObhcrU%QXqs6Y4>D`x8RpQX*cy5LEFBCO?*Pf5fdVne28}TX ze_pK&ou`Gt^R$3`;7p+!Bm^g!!wZi{ctk>fA%Zi7Y7h~eBs|~gTZU`VWZ_ygS>P6d znL;((A}~pKzBD4?5ebC|&J?QQ7SV|O*AZ8u(ZO|SbiftD0tI5YKv<0MWLY>u!x07! z8YmFM)nVcI-#J`!MhDlN(E&FH3lxaq=3p_xQ)S@@4M!L_XrMq0H;0AetaO%w;~fkf k9Pa?(pn(E02qzL_ogL4I>0h89b_jr5JH^k*vkn3;NErXkSpWb4 delta 442 zcmV;r0Y(13lmWez0gzA(BE`=EyiJw)ePRpdsTgV_f= zLf8?1wJNycdIK^*PgjQ1_ceSPOA|7vRb?}@?4&;~WYnm>KiEl26Ef&lXl1R6-maCX zNB=d7{lUbq*@Yo~-!2UCi}x}}ho+ge@gTD{o?#AMiD{76&(gtw@eYs-8YmEhY|t2U z@aNUa(0N)IJWmVA2hJ3#K|*knIlSSh9e9d zG*BRhtHZ+azjL_eOb)I&lLKxJ7AO$I&B0=Xr^><+8jdh<&_ID0ZVn5_8tDxM$2%At kINkxmK?4P15Kbh Date: Thu, 31 Aug 2023 16:32:02 +0100 Subject: [PATCH 07/12] readds an important null check --- code/modules/mob/living/carbon/human/human_defines.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index e392df74f56a..4416ba74fda3 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -162,7 +162,10 @@ ///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 From f66dd5c4ca0a507abe2fc9c9a5e0dbf5abbb5f11 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:32:13 +0100 Subject: [PATCH 08/12] adds some dmdoc --- code/modules/mob/living/carbon/human/update_icons.dm | 4 ++++ code/modules/organs/limbs.dm | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index d56c4efd1c9c..5fa8b577e8c2 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -76,6 +76,9 @@ 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 + SEND_SIGNAL(src, COMSIG_HUMAN_OVERLAY_APPLIED, cache_index, images) overlays += images @@ -173,6 +176,7 @@ 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) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index a3a774a73ba7..5b851d1c376d 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -71,10 +71,16 @@ 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 @@ -675,6 +681,7 @@ This function completely restores a damaged organ to perfect condition. number_wounds += W.amount +/// updates the various internal variables of the limb from the owner /obj/limb/proc/update_limb() SHOULD_CALL_PARENT(TRUE) @@ -699,6 +706,7 @@ This function completely restores a damaged organ to perfect condition. species = owner.species limb_gender = owner.gender +/// 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) @@ -732,7 +740,10 @@ This function completely restores a damaged organ to perfect condition. 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]" // new damage icon system From dc54271b37b9fb387d6c6eb6f009641283d61d1a Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:08:20 +0100 Subject: [PATCH 09/12] cache busting --- code/modules/organs/limbs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 5b851d1c376d..4ebb79cedf5f 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -744,7 +744,7 @@ This function completely restores a damaged organ to perfect condition. /obj/limb/proc/get_limb_icon_key() SHOULD_CALL_PARENT(TRUE) - return "[species.name]-[body_type]-[limb_gender]-[icon_name]-[ethnicity]" + return "[species.name]-[body_type]-[limb_gender]-[icon_name]-[ethnicity]-[status]" // new damage icon system // returns just the brute/burn damage code From 1b80bb7b4b878cbfa667451b275db41e8c2dd0ea Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:18:06 +0100 Subject: [PATCH 10/12] cleanup --- code/modules/organs/limbs.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 4ebb79cedf5f..fe49b6284b5c 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -711,8 +711,6 @@ This function completely restores a damaged organ to perfect condition. SHOULD_CALL_PARENT(TRUE) RETURN_TYPE(/list) - icon_state = "" - . = list() if(parent?.status & LIMB_DESTROYED) @@ -725,15 +723,13 @@ This function completely restores a damaged organ to perfect condition. var/image/limb = image(layer = -BODYPARTS_LAYER) - var/race_icon = species.icobase - if ((status & LIMB_ROBOT) && !(owner.species && owner.species.flags & IS_SYNTHETIC)) limb.icon = 'icons/mob/robotic.dmi' limb.icon_state = "[icon_name]" . += limb return - limb.icon = race_icon + limb.icon = species.icobase limb.icon_state = "[get_limb_icon_name(species, body_type, limb_gender, icon_name, ethnicity)]" . += limb From 1a742a876132a3fe9df890d85fa21876d63c7cd5 Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:47:21 +0100 Subject: [PATCH 11/12] runtime fix --- code/modules/organs/limbs.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index fe49b6284b5c..58d0a4780681 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -685,14 +685,14 @@ This function completely restores a damaged organ to perfect condition. /obj/limb/proc/update_limb() SHOULD_CALL_PARENT(TRUE) - var/datum/ethnicity/owner_ethnicity = GLOB.ethnicities_list[owner.ethnicity] + var/datum/ethnicity/owner_ethnicity = GLOB.ethnicities_list[owner?.ethnicity] if(owner_ethnicity) ethnicity = owner_ethnicity.icon_name else ethnicity = "western" - var/datum/body_type/owner_body_type = GLOB.body_types_list[owner.body_type] + var/datum/body_type/owner_body_type = GLOB.body_types_list[owner?.body_type] if(owner_body_type) body_type = owner_body_type.icon_name @@ -703,8 +703,8 @@ This function completely restores a damaged organ to perfect condition. ethnicity = owner.ethnicity body_type = owner.body_type - species = owner.species - limb_gender = owner.gender + species = owner?.species ? owner.species : GLOB.all_species[SPECIES_HUMAN] + limb_gender = owner?.gender ? owner.gender : FEMALE /// generates a list of overlays that should be applied to the owner /obj/limb/proc/get_limb_icon() From 302706625680530c223bef4b4de8e2afed21fa5f Mon Sep 17 00:00:00 2001 From: harryob <55142896+harryob@users.noreply.github.com> Date: Fri, 1 Sep 2023 18:59:39 +0100 Subject: [PATCH 12/12] getFlatIcon improvements --- code/__HELPERS/icons.dm | 276 ++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 153 deletions(-) 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.