Files
Matt Atlas f6037f893a Move limb image updating from life ticks to signals. (#21372)
title,should fix a lot of lag

---------

Co-authored-by: Matt Atlas <liermattia@gmail.com>
2025-10-05 17:23:35 +00:00

418 lines
15 KiB
Plaintext

/obj/item/organ/external/set_dir()
return
/obj/item/organ/external/proc/compile_icon()
ClearOverlays()
// This is a kludge, only one icon has more than one generation of children though.
for(var/obj/item/organ/external/organ in contents)
if(organ.children && organ.children.len)
for(var/obj/item/organ/external/child in organ.children)
AddOverlays(child.mob_icon)
AddOverlays(organ.mob_icon)
/obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/human)
s_tone = null
skin_color = null
hair_color = null
var/limb_exception = FALSE
if(robotize_type)
var/datum/robolimb/R = GLOB.all_robolimbs[robotize_type]
if(R?.paintable && (isnull(override_robotize_painted) || override_robotize_painted))
limb_exception = TRUE
if((status & ORGAN_ROBOT) && !limb_exception)
return
if(species && human.species && species.name != human.species.name)
return
if(!isnull(human.s_tone) && (human.species.appearance_flags & HAS_SKIN_TONE))
s_tone = human.s_tone
if((human.species.appearance_flags & HAS_SKIN_COLOR) || (human.species.appearance_flags & HAS_SKIN_PRESET))
skin_color = rgb(human.r_skin, human.g_skin, human.b_skin)
hair_color = rgb(human.r_hair, human.g_hair, human.b_hair)
/obj/item/organ/external/proc/sync_colour_to_dna()
s_tone = null
skin_color = null
hair_color = null
if(status & ORGAN_ROBOT && !force_skintone)
return
if(!isnull(dna.GetUIValue(DNA_UI_SKIN_TONE)) && (species.appearance_flags & HAS_SKIN_TONE))
s_tone = dna.GetUIValue(DNA_UI_SKIN_TONE)
if((species.appearance_flags & HAS_SKIN_COLOR) || (species.appearance_flags & HAS_SKIN_PRESET))
skin_color = rgb(dna.GetUIValue(DNA_UI_SKIN_R), dna.GetUIValue(DNA_UI_SKIN_G), dna.GetUIValue(DNA_UI_SKIN_B))
hair_color = rgb(dna.GetUIValue(DNA_UI_HAIR_R),dna.GetUIValue(DNA_UI_HAIR_G),dna.GetUIValue(DNA_UI_HAIR_B))
/obj/item/organ/external/head/sync_colour_to_human(var/mob/living/carbon/human/human)
..()
var/obj/item/organ/internal/eyes/eyes = owner.get_eyes()
if(eyes)
eyes.update_colour()
/obj/item/organ/external/head/get_icon()
..()
ClearOverlays()
if(!owner || !owner.species)
return
var/is_frenzied = FALSE
if(owner.mind)
var/datum/vampire/vampire = owner.mind.antag_datums[MODE_VAMPIRE]
if(vampire && (vampire.status & VAMP_FRENZIED))
is_frenzied = TRUE
if(owner.species.has_organ[owner.species.vision_organ])
var/obj/item/organ/internal/eyes/eyes = owner.get_eyes()
if(eyes && species.eyes && !is_frenzied)
var/eyecolor
if (eyes.eye_colour)
eyecolor = rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3])
var/cache_key = "[species.eyes]_[eyecolor || "nocolor"]"
var/icon/eyes_icon = SSicon_cache.human_eye_cache[cache_key]
if (!eyes_icon)
eyes_icon = new/icon(species.eyes_icons, species.eyes)
if(eyecolor)
eyes_icon.Blend(eyecolor, species.eyes_icon_blend)
else
eyes_icon.Blend(rgb(128,0,0), species.eyes_icon_blend)
SSicon_cache.human_eye_cache[cache_key] = eyes_icon
mob_icon.Blend(eyes_icon, ICON_OVERLAY)
AddOverlays(eyes_icon)
if(owner.lipstick_color && (species && (species.appearance_flags & HAS_LIPS)))
var/icon/lip_icon = SSicon_cache.human_lip_cache["[owner.lipstick_color]"]
if (!lip_icon)
lip_icon = new/icon('icons/mob/human_face/lips.dmi', "lips")
lip_icon.Blend(owner.lipstick_color, species.eyes_icon_blend)
SSicon_cache.human_lip_cache["[owner.lipstick_color]"] = lip_icon
AddOverlays(lip_icon)
mob_icon.Blend(lip_icon, ICON_OVERLAY)
apply_markings()
get_internal_organs_overlay()
AddOverlays(owner.generate_hair_icon())
UpdateOverlays()
return mob_icon
/obj/item/organ/external/head/get_additional_images(var/mob/living/carbon/human/H)
..()
if(!H.mind)
return mob_overlays
var/list/bonus_overlays = list()
var/obj/item/organ/internal/eyes/eyes = H.get_eyes()
if(eyes && BP_IS_ROBOTIC(eyes))
var/datum/robolimb/robolimb_data = GLOB.all_robolimbs[eyes.model]
if(robolimb_data.emissive)
var/mutable_appearance/return_image = emissive_appearance(H.species.eyes_icons, H.species.eyes, MOB_EMISSIVE_LAYER)
bonus_overlays += return_image
var/datum/vampire/vampire = H.mind.antag_datums[MODE_VAMPIRE]
if(vampire && (vampire.status & VAMP_FRENZIED))
var/mutable_appearance/return_image = emissive_appearance(H.species.eyes_icons, "[H.species.eyes]_frenzy")
bonus_overlays += return_image
return mob_overlays + bonus_overlays
/obj/item/organ/external/proc/apply_markings(restrict_to_robotic = FALSE)
if (!cached_markings)
update_marking_cache()
if (LAZYLEN(cached_markings))
for(var/M in cached_markings)
var/datum/sprite_accessory/marking/mark_style = cached_markings[M]["datum"]
if (restrict_to_robotic && !mark_style.is_painted)
continue
var/m_color = cached_markings[M]["color"]
var/cache_key = "[mark_style.icon]-[mark_style.icon_state]-[limb_name]-[m_color]"
var/icon/finished_icon = SSicon_cache.markings_cache[cache_key]
if (!finished_icon)
finished_icon = new/icon("icon" = mark_style.icon, "icon_state" = "[mark_style.icon_state]-[limb_name]")
finished_icon.Blend(m_color, mark_style.icon_blend_mode)
SSicon_cache.markings_cache[cache_key] = finished_icon
AddOverlays(finished_icon) //So when it's not on your body, it has icons
mob_icon.Blend(finished_icon, ICON_OVERLAY) //So when it's on your body, it has icons
/obj/item/organ/external/proc/get_internal_organs_overlay()
for(var/obj/item/organ/internal/O in internal_organs)
if(O.on_mob_icon)
var/internal_organ_icon = O.on_mob_icon
var/cache_key = "[internal_organ_icon]-[O.item_state || O.icon_state]"
if(owner && O.sprite_sheets && O.sprite_sheets[owner.species.get_bodytype()])
cache_key = "[O.sprite_sheets[owner.species.get_bodytype()]]-[O.item_state || O.icon_state]"
internal_organ_icon = O.sprite_sheets[owner.species.get_bodytype()]
var/icon/organ_icon = SSicon_cache.internal_organ_cache[cache_key]
if (!organ_icon)
organ_icon = new /icon(internal_organ_icon, O.item_state || O.icon_state)
SSicon_cache.internal_organ_cache[cache_key] = organ_icon
AddOverlays(organ_icon)
mob_icon.Blend(organ_icon, ICON_OVERLAY)
if(O.blocks_emissive != EMISSIVE_BLOCK_NONE) {
var/mutable_appearance/organ_em_block = emissive_blocker(internal_organ_icon, O.item_state || O.icon_state, MOB_SHADOW_LAYER)
organ_em_block.dir = dir
mob_overlays += list(organ_em_block)
}
if(O.active_overlay && !O.is_broken()) {
var/mutable_appearance/active_overlay = overlay_image(internal_organ_icon, "[O.item_state || O.icon_state]_overlay")
active_overlay.dir = dir
mob_overlays += list(active_overlay)
}
if(O.active_emissive && !O.is_broken()) {
var/mutable_appearance/organ_em = emissive_appearance(internal_organ_icon, "[O.item_state || O.icon_state]_e", MOB_EMISSIVE_LAYER)
organ_em.dir = dir
mob_overlays += list(organ_em)
}
/obj/item/organ/external/var/icon_cache_key
/obj/item/organ/external/proc/get_icon(var/skeletal)
var/gender = "f"
if(owner && owner.gender == MALE)
gender = "m"
var/chosen_icon
var/chosen_icon_state
mob_overlays = list()
if(force_icon)
chosen_icon = force_icon
chosen_icon_state = "[icon_name][gendered_icon ? "_[gender]" : ""]"
mob_icon = new /icon(force_icon, chosen_icon_state)
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
var/mutable_appearance/limb_em_block = emissive_blocker(chosen_icon, chosen_icon_state, MOB_SHADOW_LAYER)
limb_em_block.dir = dir
mob_overlays += list(limb_em_block)
if(is_emissive && !is_broken())
var/mutable_appearance/limb_em = emissive_appearance(chosen_icon, "[chosen_icon_state]_e", MOB_EMISSIVE_LAYER)
limb_em.dir = dir
mob_overlays += list(limb_em)
if(is_overlay && !is_broken())
var/mutable_appearance/limb_overlay = overlay_image(chosen_icon, "[chosen_icon_state]_overlay")
limb_overlay.dir = dir
mob_overlays += list(limb_overlay)
if((painted && skin_color) || robotize_type == PROSTHETIC_SYNTHSKIN)
mob_icon.Blend(skin_color, ICON_ADD)
if(!isnull(s_tone))
if(s_tone >= 0)
mob_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
else
mob_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
apply_markings(restrict_to_robotic = (robotize_type != PROSTHETIC_SYNTHSKIN))
get_internal_organs_overlay()
else
if(!dna)
chosen_icon = 'icons/mob/human_races/human/r_human.dmi'
chosen_icon_state = "[icon_name][gendered_icon ? "_[gender]" : ""]"
mob_icon = new /icon(chosen_icon, chosen_icon_state)
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
var/mutable_appearance/limb_em_block = emissive_blocker(chosen_icon, chosen_icon_state, MOB_SHADOW_LAYER)
limb_em_block.dir = dir
mob_overlays += list(limb_em_block)
if(is_emissive && !is_broken())
var/mutable_appearance/limb_em = emissive_appearance(chosen_icon, "[chosen_icon_state]_e", MOB_EMISSIVE_LAYER)
limb_em.dir = dir
mob_overlays += list(limb_em)
else
chosen_icon_state = "[icon_name][gendered_icon ? "_[gender]" : ""]"
if(!gendered_icon)
gender = null
else
if(dna.GetUIState(DNA_UI_GENDER))
gender = "f"
else
gender = "m"
if(skeletal)
chosen_icon = species.skeleton_icon
mob_icon = new /icon(chosen_icon, chosen_icon_state)
else if (status & ORGAN_ROBOT && !force_skintone)
chosen_icon = 'icons/mob/human_races/ipc/robotic.dmi'
mob_icon = new /icon(chosen_icon, chosen_icon_state)
else
if (status & ORGAN_MUTATED)
chosen_icon = species.deform
else
chosen_icon = species.icobase
mob_icon = new /icon(chosen_icon, chosen_icon_state)
if(status & ORGAN_DEAD)
mob_icon.ColorTone(rgb(10,50,0))
mob_icon.SetIntensity(0.7)
if(status & ORGAN_ZOMBIFIED)
mob_icon.ColorTone(rgb(30, 30, 30))
mob_icon.SetIntensity(0.7)
if(skin_color)
mob_icon.Blend(skin_color, ICON_ADD)
if(!isnull(s_tone))
if(s_tone >= 0)
mob_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD)
else
mob_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT)
apply_markings()
get_internal_organs_overlay()
if(blocks_emissive != EMISSIVE_BLOCK_NONE)
var/mutable_appearance/limb_em_block = emissive_blocker(chosen_icon, chosen_icon_state, MOB_SHADOW_LAYER)
limb_em_block.dir = dir
mob_overlays += list(limb_em_block)
if(is_emissive && !is_broken())
var/mutable_appearance/limb_em = emissive_appearance(chosen_icon, "[chosen_icon_state]_e", MOB_EMISSIVE_LAYER)
limb_em.dir = dir
mob_overlays += list(limb_em)
if(body_hair)
var/list/limb_icon_cache = SSicon_cache.limb_icons_cache
var/cache_key = "[body_hair]-[icon_name]-[hair_color]"
if(!limb_icon_cache[cache_key])
var/icon/I = icon(species.icobase, "[icon_name]_[body_hair]")
I.Blend(hair_color, ICON_ADD)
limb_icon_cache[cache_key] = I
mob_icon.Blend(limb_icon_cache[cache_key], ICON_OVERLAY)
icon_cache_key = cache_key
icon = mob_icon
return mob_icon
/obj/item/organ/external/proc/get_additional_images(var/mob/living/carbon/human/H)
return mob_overlays
/obj/item/organ/external/proc/cut_additional_images(var/mob/living/carbon/human/H)
if(LAZYLEN(additional_images))
H.CutOverlays(additional_images, ATOM_ICON_CACHE_PROTECTED)
LAZYCLEARLIST(additional_images)
// new damage icon system
// adjusted to set damage_state to brute/burn code only (without r_name0 as before)
/obj/item/organ/external/update_icon()
var/n_is = damage_state_text()
if (n_is != damage_state)
damage_state = n_is
return TRUE
return FALSE
// This is NOT safe for caching the organ's own icon, it's only meant to be used for the mob icon cache.
/obj/item/organ/external/proc/get_mob_cache_key()
var/list/keyparts = list()
if (is_stump())
keyparts += "stump"
else if (status & ORGAN_ROBOT)
keyparts += "robot:[model || "nomodel"]"
else if (status & ORGAN_DEAD)
keyparts += "dead"
else
keyparts += "norm"
keyparts += "[species.race_key]"
keyparts += "[dna.GetUIState(DNA_UI_GENDER)]"
keyparts += "[dna.GetUIValue(DNA_UI_SKIN_TONE)]"
if (skin_color)
keyparts += "[skin_color]"
if (body_hair && hair_color)
keyparts += "[hair_color]"
if (!cached_markings)
update_marking_cache()
for (var/marking in cached_markings)
keyparts += "[marking][cached_markings[marking]["color"]]"
for(var/obj/item/organ/internal/O in internal_organs)
if(O.on_mob_icon)
if(owner && O.sprite_sheets && O.sprite_sheets[owner.species.get_bodytype()])
keyparts += "[O.sprite_sheets[owner.species.get_bodytype()]]-[O.item_state || O.icon_state]"
else
keyparts += "[O.on_mob_icon]-[O.item_state || O.icon_state]"
. = keyparts.Join("_")
/obj/item/organ/external/proc/update_marking_cache()
if (LAZYLEN(genetic_markings))
LAZYADD(cached_markings, genetic_markings)
if (LAZYLEN(temporary_markings))
LAZYADD(cached_markings, temporary_markings)
// Global scope, used in code below.
GLOBAL_LIST_INIT(flesh_hud_colours, list("#00ff00","#aaff00","#ffff00","#ffaa00","#ff0000","#aa0000","#660000"))
GLOBAL_LIST_INIT(robot_hud_colours, list("#ffffff","#cccccc","#aaaaaa","#888888","#666666","#444444","#222222","#000000"))
/obj/item/organ/external/proc/get_damage_hud_image(force_update = FALSE)
// Generate the greyscale base icon and cache it for later.
// icon_cache_key is set by any get_icon() calls that are made.
// This looks convoluted, but it's this way to avoid icon proc calls.
var/list/limb_icon_cache = SSicon_cache.limb_icons_cache
var/has_created_image = FALSE
if(!hud_damage_image)
var/cache_key = "dambase-[icon_cache_key]"
if(!icon_cache_key || !limb_icon_cache[cache_key])
limb_icon_cache[cache_key] = icon(get_icon(), null, SOUTH)
var/image/temp = image(limb_icon_cache[cache_key])
if(species)
// Calculate the required colour matrix.
var/r = 0.30 * species.health_hud_intensity
var/g = 0.59 * species.health_hud_intensity
var/b = 0.11 * species.health_hud_intensity
temp.color = list(r, r, r, g, g, g, b, b, b)
hud_damage_image = image(null)
hud_damage_image.overlays += temp
has_created_image = TRUE
if(has_created_image || force_update)
modify_damage_hud_image_color()
return hud_damage_image
/// Modify the damage colour index of the limb image, ONLY if strictly necessary.
/obj/item/organ/external/proc/modify_damage_hud_image_color()
SIGNAL_HANDLER
// Calculate the required color index.
var/dam_state = min(1,((brute_dam+burn_dam)/max(1,max_damage)))
var/min_dam_state = min(1,(get_pain()/max(1,max_damage)))
if(min_dam_state && dam_state < min_dam_state)
dam_state = min_dam_state
// Apply colour and return product.
var/list/hud_colours = !BP_IS_ROBOTIC(src) ? GLOB.flesh_hud_colours : GLOB.robot_hud_colours
hud_damage_image.color = hud_colours[max(1,min(Ceiling(dam_state*hud_colours.len),hud_colours.len))]
/// Returns the possible bandage level the external can have right now, see medical.dm for usage
/obj/item/organ/external/proc/possible_bandage_level()
if(damage_state_text() == "00")
return BANDAGE_LEVEL_NONE
if(!is_bandaged())
return BANDAGE_LEVEL_NONE
if(burn_dam + brute_dam == 0)
. = BANDAGE_LEVEL_NONE
else if (burn_dam + brute_dam < (max_damage * 0.25 / 2))
. = BANDAGE_LEVEL_LIGHT
else if (burn_dam + brute_dam < (max_damage * 0.75 / 2))
. = BANDAGE_LEVEL_MEDIUM
else
. = BANDAGE_LEVEL_HEAVY