diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index 6559f28f26..6bd32c762c 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -48,6 +48,9 @@ Pipelines + Other Objects -> Pipe network pipe_color = null init_dir() +/obj/machinery/atmospherics/examine_icon() + return icon(icon=initial(icon),icon_state=initial(icon_state)) + // This is used to set up what directions pipes will connect to. Should be called inside New() and whenever a dir changes. /obj/machinery/atmospherics/proc/init_dir() return diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index 5abedfe9ac..a199c88622 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -107,7 +107,7 @@ AngleToHue(hue) Converts an angle to a hue in the valid range. RotateHue(hsv, angle) Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360. - (Rotating red by 60° produces yellow.) The result is another HSV or HSVA color with the same saturation and value + (Rotating red by 60deg produces yellow.) The result is another HSV or HSVA color with the same saturation and value as the original, but a different hue. GrayScale(rgb) Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string. @@ -679,7 +679,7 @@ proc/ColorTone(rgb, tone) var/curstate = A.icon_state || defstate if(!((noIcon = (!curicon)))) - var/curstates = icon_states(curicon) + var/curstates = cached_icon_states(curicon) if(!(curstate in curstates)) if("" in curstates) curstate = "" @@ -689,19 +689,16 @@ proc/ColorTone(rgb, tone) 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 + // Use the requested dir or the atom's current dir + curdir = defdir || A.dir - //Try to remove/optimize this section ASAP, CPU hog. + //Try to remove/optimize this section ASAP, CPU hog. //Slightly mitigated by implementing caching using cached_icon_states //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)))) + if(length(cached_icon_states(icon(curicon, curstate, i)))) exist = TRUE break if(!exist) @@ -739,8 +736,8 @@ proc/ColorTone(rgb, tone) continue var/current_layer = current.layer if(current_layer < 0) - if(current_layer <= -1000) - return flat + //if(current_layer <= -1000) + //return flat current_layer = process_set + A.layer + current_layer / 1000 for(var/p in 1 to layers.len) @@ -768,7 +765,7 @@ proc/ColorTone(rgb, tone) curblend = BLEND_OVERLAY add = icon(I.icon, I.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(I), I.dir||curdir, curicon, curstate, curblend, FALSE, no_anim) if(!add) continue // Find the new dimensions of the flat icon to fit the added overlay @@ -899,6 +896,37 @@ proc/ColorTone(rgb, tone) composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY) return composite +GLOBAL_LIST_EMPTY(icon_state_lists) +/proc/cached_icon_states(var/icon/I) + if(!I) + return list() + var/key = I + var/returnlist = GLOB.icon_state_lists[key] + if(!returnlist) + returnlist = icon_states(I) + if(isfile(I)) // It's something that will stick around + GLOB.icon_state_lists[key] = returnlist + return returnlist + +/proc/expire_states_cache(var/key) + if(GLOB.icon_state_lists[key]) + GLOB.icon_state_lists -= key + return TRUE + return FALSE + +GLOBAL_LIST_EMPTY(cached_examine_icons) +/proc/set_cached_examine_icon(var/atom/A, var/icon/I, var/expiry = 12000) + GLOB.cached_examine_icons[weakref(A)] = I + if(expiry) + addtimer(CALLBACK(GLOBAL_PROC, .proc/uncache_examine_icon, weakref(A)), expiry, TIMER_UNIQUE) + +/proc/get_cached_examine_icon(var/atom/A) + var/weakref/WR = weakref(A) + return GLOB.cached_examine_icons[WR] + +/proc/uncache_examine_icon(var/weakref/WR) + GLOB.cached_examine_icons -= WR + proc/adjust_brightness(var/color, var/value) if (!color) return "#FFFFFF" if (!value) return color diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 73ae811193..d4400da8df 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -94,7 +94,7 @@ proc/age2agedescription(age) else return "unknown" /proc/RoundHealth(health) - var/list/icon_states = icon_states(ingame_hud_med) + var/list/icon_states = cached_icon_states(ingame_hud_med) for(var/icon_state in icon_states) if(health >= text2num(icon_state)) return icon_state diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5f8ccb3391..7d39676d51 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -192,6 +192,10 @@ return output +// Don't make these call bicon or anything, these are what bicon uses. They need to return an icon. +/atom/proc/examine_icon() + return icon(icon=src.icon, icon_state=src.icon_state, dir=SOUTH, frame=1, moving=0) + // called by mobs when e.g. having the atom as their machine, pulledby, loc (AKA mob being inside the atom) or buckled var set. // see code/modules/mob/mob_movement.dm for more. /atom/proc/relaymove() diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 95db86460e..a668075068 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -63,7 +63,7 @@ overlays.Cut() if(front_id) var/tiny_state = "id-generic" - if("id-"+front_id.icon_state in icon_states(icon)) + if("id-"+front_id.icon_state in cached_icon_states(icon)) tiny_state = "id-"+front_id.icon_state var/image/tiny_image = new/image(icon, icon_state = tiny_state) tiny_image.appearance_flags = RESET_COLOR diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm index cd1c448b2f..e54c75eebb 100644 --- a/code/game/objects/structures/barsign.dm +++ b/code/game/objects/structures/barsign.dm @@ -6,7 +6,7 @@ var/cult = 0 /obj/structure/sign/double/barsign/proc/get_valid_states(initial=1) - . = icon_states(icon) + . = cached_icon_states(icon) . -= "on" . -= "narsiebistro" . -= "empty" diff --git a/code/game/objects/structures/cliff.dm b/code/game/objects/structures/cliff.dm index c4caf4b7ab..66fb945988 100644 --- a/code/game/objects/structures/cliff.dm +++ b/code/game/objects/structures/cliff.dm @@ -114,7 +114,7 @@ two tiles on initialization, and which way a cliff is facing may change during m var/subtraction_icon_state = "[icon_state]-subtract" var/cache_string = "[icon_state]_[T.icon]_[T.icon_state]" - if(T && subtraction_icon_state in icon_states(icon)) + if(T && subtraction_icon_state in cached_icon_states(icon)) cut_overlays() // If we've made the same icon before, just recycle it. if(cache_string in GLOB.cliff_icon_cache) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 3df62610c9..2434d33e89 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -47,6 +47,9 @@ else . += "There is a thick layer of silicate covering it." +/obj/structure/window/examine_icon() + return icon(icon=initial(icon),icon_state=initial(icon_state)) + /obj/structure/window/take_damage(var/damage = 0, var/sound_effect = 1) var/initialhealth = health diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm index 5bf41c4a5f..dd49744a8f 100644 --- a/code/game/turfs/simulated/wall_icon.dm +++ b/code/game/turfs/simulated/wall_icon.dm @@ -67,7 +67,7 @@ I.color = reinf_material.icon_colour add_overlay(I) else - if("[reinf_material.icon_reinf]0" in icon_states('icons/turf/wall_masks.dmi')) + if("[reinf_material.icon_reinf]0" in cached_icon_states('icons/turf/wall_masks.dmi')) // Directional icon for(var/i = 1 to 4) I = image('icons/turf/wall_masks.dmi', "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1)) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index add0b3b11d..1fc49d58a9 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -46,6 +46,9 @@ dismantle_wall(null,null,1) ..() +/turf/simulated/wall/examine_icon() + return icon(icon=initial(icon), icon_state=initial(icon_state)) + /turf/simulated/wall/process() // Calling parent will kill processing if(!radiate()) diff --git a/code/modules/client/asset_cache.dm b/code/modules/client/asset_cache.dm index 5580c7fd98..ed6439d3cd 100644 --- a/code/modules/client/asset_cache.dm +++ b/code/modules/client/asset_cache.dm @@ -204,12 +204,12 @@ You can set verify to TRUE if you want send() to sleep until the client has the directions = list(SOUTH) var/sprites = list() - for (var/icon_state_name in icon_states(I)) + for (var/icon_state_name in cached_icon_states(I)) for (var/direction in directions) var/suffix = (directions.len > 1) ? "-[dir2text(direction)]" : "" var/sprite_name = "[prefix][icon_state_name][suffix]" var/icon/sprite = icon(I, icon_state=icon_state_name, dir=direction, frame=1, moving=FALSE) - if (!sprite || !length(icon_states(sprite))) // that direction or state doesn't exist + if (!sprite || !length(cached_icon_states(sprite))) // that direction or state doesn't exist continue sprites[sprite_name] = sprite return sprites diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index adb52397ff..3208179b91 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -841,7 +841,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O dat += "[current_species.blurb]" //vorestation edit end dat += "" - if("preview" in icon_states(current_species.icobase)) + if("preview" in cached_icon_states(current_species.icobase)) usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") dat += "

" dat += "Language: [current_species.species_language]
" diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 283406d6ba..eff875ee8d 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -805,7 +805,7 @@ //autodetect rollability if(rolled_down < 0) - if(("[worn_state]_d_s" in icon_states(icon)) || ("[worn_state]_s" in icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in icon_states(icon_override))) + if(("[worn_state]_d_s" in cached_icon_states(icon)) || ("[worn_state]_s" in cached_icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in cached_icon_states(icon_override))) rolled_down = 0 if(rolled_down == -1) @@ -842,11 +842,11 @@ under_icon = sprite_sheets[H.species.get_bodytype(H)] else if(item_icons && item_icons[slot_w_uniform_str]) under_icon = item_icons[slot_w_uniform_str] - else if ("[worn_state]_s" in icon_states(rolled_down_icon)) + else if ("[worn_state]_s" in cached_icon_states(rolled_down_icon)) under_icon = rolled_down_icon // The _s is because the icon update procs append it. - if((under_icon == rolled_down_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_d_s" in icon_states(under_icon))) + if((under_icon == rolled_down_icon && "[worn_state]_s" in cached_icon_states(under_icon)) || ("[worn_state]_d_s" in cached_icon_states(under_icon))) if(rolled_down != 1) rolled_down = 0 else @@ -865,13 +865,13 @@ under_icon = sprite_sheets[H.species.get_bodytype(H)] else if(item_icons && item_icons[slot_w_uniform_str]) under_icon = item_icons[slot_w_uniform_str] - else if ("[worn_state]_s" in icon_states(rolled_down_sleeves_icon)) + else if ("[worn_state]_s" in cached_icon_states(rolled_down_sleeves_icon)) under_icon = rolled_down_sleeves_icon else if(index) under_icon = new /icon("[INV_W_UNIFORM_DEF_ICON]_[index].dmi") // The _s is because the icon update procs append it. - if((under_icon == rolled_down_sleeves_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_r_s" in icon_states(under_icon))) + if((under_icon == rolled_down_sleeves_icon && "[worn_state]_s" in cached_icon_states(under_icon)) || ("[worn_state]_r_s" in cached_icon_states(under_icon))) if(rolled_sleeves != 1) rolled_sleeves = 0 else @@ -955,7 +955,7 @@ if(rolled_down) body_parts_covered = initial(body_parts_covered) body_parts_covered &= ~(UPPER_TORSO|ARMS) - if("[worn_state]_s" in icon_states(rolled_down_icon)) + if("[worn_state]_s" in cached_icon_states(rolled_down_icon)) icon_override = rolled_down_icon item_state_slots[slot_w_uniform_str] = "[worn_state]" else @@ -988,7 +988,7 @@ rolled_sleeves = !rolled_sleeves if(rolled_sleeves) body_parts_covered &= ~(ARMS) - if("[worn_state]_s" in icon_states(rolled_down_sleeves_icon)) + if("[worn_state]_s" in cached_icon_states(rolled_down_sleeves_icon)) icon_override = rolled_down_sleeves_icon item_state_slots[slot_w_uniform_str] = "[worn_state]" else diff --git a/code/modules/clothing/clothing_vr.dm b/code/modules/clothing/clothing_vr.dm index 1fb7d26548..470cb94c06 100644 --- a/code/modules/clothing/clothing_vr.dm +++ b/code/modules/clothing/clothing_vr.dm @@ -134,7 +134,7 @@ var/mob/living/carbon/human/H = user if(isTaurTail(H.tail_style)) var/datum/sprite_accessory/tail/taur/taurtail = H.tail_style - if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in icon_states(taurtail.suit_sprites))) + if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in cached_icon_states(taurtail.suit_sprites))) icon_override = taurtail.suit_sprites normalize = FALSE taurized = TRUE diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 57fe80cd76..6aed5daf39 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -24,7 +24,7 @@ if(!inv_overlay) var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]" if(icon_override) - if("[tmp_icon_state]_tie" in icon_states(icon_override)) + if("[tmp_icon_state]_tie" in cached_icon_states(icon_override)) tmp_icon_state = "[tmp_icon_state]_tie" inv_overlay = image(icon = icon_override, icon_state = tmp_icon_state, dir = SOUTH) else @@ -48,7 +48,7 @@ tmp_icon_state = on_rolled["rolled"] if(icon_override) - if("[tmp_icon_state]_mob" in icon_states(icon_override)) + if("[tmp_icon_state]_mob" in cached_icon_states(icon_override)) tmp_icon_state = "[tmp_icon_state]_mob" mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]") else if(wearer && sprite_sheets[wearer.species.get_bodytype(wearer)]) //Teshari can finally into webbing, too! diff --git a/code/modules/clothing/under/accessories/lockets.dm b/code/modules/clothing/under/accessories/lockets.dm index ca859addb5..153df0d584 100644 --- a/code/modules/clothing/under/accessories/lockets.dm +++ b/code/modules/clothing/under/accessories/lockets.dm @@ -13,7 +13,7 @@ if(!base_icon) base_icon = icon_state - if(!("[base_icon]_open" in icon_states(icon))) + if(!("[base_icon]_open" in cached_icon_states(icon))) to_chat(user, "\The [src] doesn't seem to open.") return diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm index b87183c385..5e85c0123c 100644 --- a/code/modules/customitems/item_spawning.dm +++ b/code/modules/customitems/item_spawning.dm @@ -78,7 +78,7 @@ var/list/new_item_icons = list() var/list/new_item_state_slots = list() - var/list/available_states = icon_states(CUSTOM_ITEM_MOB) + var/list/available_states = cached_icon_states(CUSTOM_ITEM_MOB) //If l_hand or r_hand are not present, preserve them using item_icons/item_state_slots //Then use icon_override to make every other slot use the custom sprites by default. diff --git a/code/modules/examine/examine.dm b/code/modules/examine/examine.dm index 6e2df0b1fa..f49c672bca 100644 --- a/code/modules/examine/examine.dm +++ b/code/modules/examine/examine.dm @@ -5,7 +5,7 @@ This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort. */ -#define EXAMINE_PANEL_PADDING " " +#define EXAMINE_PANEL_PADDING " " /atom/ var/description_info = null //Helpful blue text. @@ -56,7 +56,7 @@ description_holders["interactions"] = A.get_description_interaction() description_holders["name"] = "[A.name]" - description_holders["icon"] = "\icon[A]" + description_holders["icon"] = "\icon[A.examine_icon()]" description_holders["desc"] = A.desc /mob/Stat() diff --git a/code/modules/food/drinkingglass/drinkingglass.dm b/code/modules/food/drinkingglass/drinkingglass.dm index 928c24954b..c2c5dc4219 100644 --- a/code/modules/food/drinkingglass/drinkingglass.dm +++ b/code/modules/food/drinkingglass/drinkingglass.dm @@ -74,9 +74,9 @@ update_icon() /obj/item/weapon/reagent_containers/food/drinks/glass2/proc/can_add_extra(obj/item/weapon/glass_extra/GE) - if(!("[base_icon]_[GE.glass_addition]left" in icon_states(icon))) //VOREStation Edit + if(!("[base_icon]_[GE.glass_addition]left" in cached_icon_states(icon))) //VOREStation Edit return 0 - if(!("[base_icon]_[GE.glass_addition]right" in icon_states(icon))) //VOREStation Edit + if(!("[base_icon]_[GE.glass_addition]right" in cached_icon_states(icon))) //VOREStation Edit return 0 return 1 @@ -106,9 +106,9 @@ over_liquid |= "[base_icon][amnt]_fizz" for(var/S in R.glass_special) - if("[base_icon]_[S]" in icon_states(icon)) //VOREStation Edit + if("[base_icon]_[S]" in cached_icon_states(icon)) //VOREStation Edit under_liquid |= "[base_icon]_[S]" - else if("[base_icon][amnt]_[S]" in icon_states(icon)) //VOREStation Edit + else if("[base_icon][amnt]_[S]" in cached_icon_states(icon)) //VOREStation Edit over_liquid |= "[base_icon][amnt]_[S]" for(var/k in under_liquid) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 982f44e794..90afa7f416 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -141,7 +141,7 @@ var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product") fruit_base.color = "[seed.get_trait(TRAIT_PRODUCT_COLOUR)]" plant_icon.overlays |= fruit_base - if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in icon_states('icons/obj/hydroponics_products.dmi')) + if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in cached_icon_states('icons/obj/hydroponics_products.dmi')) var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf") fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]" plant_icon.overlays |= fruit_leaves diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm index 1ca42f4c60..28315b361a 100644 --- a/code/modules/hydroponics/seed_controller.dm +++ b/code/modules/hydroponics/seed_controller.dm @@ -53,7 +53,7 @@ var/global/datum/controller/plants/plant_controller // Set in New(). /datum/controller/plants/proc/setup() // Build the icon lists. - for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi')) + for(var/icostate in cached_icon_states('icons/obj/hydroponics_growing.dmi')) var/split = findtext(icostate,"-") if(!split) // invalid icon_state @@ -71,7 +71,7 @@ var/global/datum/controller/plants/plant_controller // Set in New(). if(!(base in GLOB.forbidden_plant_growth_sprites)) accessible_plant_sprites[base] = ikey - for(var/icostate in icon_states('icons/obj/hydroponics_products.dmi')) + for(var/icostate in cached_icon_states('icons/obj/hydroponics_products.dmi')) var/split = findtext(icostate,"-") var/base = copytext(icostate,1,split) if(split) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index e20d3740c9..349859029f 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -152,6 +152,13 @@ if(new_stat != DEAD) CRASH("It is best if observers stay dead, thank you.") +/mob/observer/dead/examine_icon() + var/icon/I = get_cached_examine_icon(src) + if(!I) + I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE) + set_cached_examine_icon(src, I, 200 SECONDS) + return I + /* Transfer_mind is there to check if mob is being deleted/not going to have a body. Works together with spawning an observer, noted above. diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f7ee2d9520..9687bde18f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1596,6 +1596,13 @@ else layer = HIDING_LAYER +/mob/living/carbon/human/examine_icon() + var/icon/I = get_cached_examine_icon(src) + if(!I) + I = getFlatIcon(src, defdir = SOUTH, no_anim = TRUE) + set_cached_examine_icon(src, I, 50 SECONDS) + return I + /mob/living/carbon/human/proc/get_display_species() //Shows species in tooltip if(src.custom_species) //VOREStation Add diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 963ad4cd38..2903bf604f 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -321,7 +321,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3])) //Handle husk overlay. - if(husk && ("overlay_husk" in icon_states(species.icobase))) + if(husk && ("overlay_husk" in cached_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) diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index 57a9574f11..fb7f28d112 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -11,7 +11,7 @@ var/obj/effect/lobby_image = new /obj/effect/lobby_image /obj/effect/lobby_image/Initialize() icon = using_map.lobby_icon - var/known_icon_states = icon_states(icon) + var/known_icon_states = cached_icon_states(icon) for(var/lobby_screen in using_map.lobby_screens) if(!(lobby_screen in known_icon_states)) error("Lobby screen '[lobby_screen]' did not exist in the icon set [icon].") diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index b07cacd92b..01f4e6003a 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -201,7 +201,7 @@ /proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M) var/list/icon_keys = list() var/list/ammo_states = list() - var/list/states = icon_states(M.icon) + var/list/states = cached_icon_states(M.icon) for(var/i = 0, i <= M.max_ammo, i++) var/ammo_state = "[M.icon_state]-[i]" if(ammo_state in states) diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm index f853e224fc..249c84be73 100644 --- a/code/modules/tables/tables.dm +++ b/code/modules/tables/tables.dm @@ -30,6 +30,9 @@ var/list/table_icon_cache = list() var/item_place = 1 //allows items to be placed on the table, but not on benches. +/obj/structure/table/examine_icon() + return icon(icon=initial(icon), icon_state=initial(icon_state)) //Basically the map preview version + /obj/structure/table/proc/update_material() var/old_maxhealth = maxhealth if(!material) diff --git a/code/modules/vchat/vchat_client.dm b/code/modules/vchat/vchat_client.dm index 6e0ac509b0..8456c5225f 100644 --- a/code/modules/vchat/vchat_client.dm +++ b/code/modules/vchat/vchat_client.dm @@ -266,31 +266,45 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic var/list/partial = splittext(iconData, "{") return replacetext(copytext(partial[2], 3, -5), "\n", "") +/proc/expire_bicon_cache(key) + if(GLOB.bicon_cache[key]) + GLOB.bicon_cache -= key + return TRUE + return FALSE + +GLOBAL_LIST_EMPTY(bicon_cache) // Cache of the tag results, not the icons /proc/bicon(var/obj, var/use_class = 1, var/custom_classes = "") var/class = use_class ? "class='icon misc [custom_classes]'" : null - if (!obj) + if(!obj) return - var/static/list/bicon_cache = list() - if (isicon(obj)) - //Icon refs get reused all the time especially on temporarily made ones like chat tags, too difficult to cache. - //if (!bicon_cache["\ref[obj]"]) // Doesn't exist yet, make it. - //bicon_cache["\ref[obj]"] = icon2base64(obj) - + // Try to avoid passing bicon an /icon directly. It is better to pass it an atom so it can cache. + if(isicon(obj)) // Passed an icon directly, nothing to cache-key on, as icon refs get reused *often* return "" // Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with. var/atom/A = obj - var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" - if (!bicon_cache[key]) // Doesn't exist, make it. - var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1) - if (ishuman(obj)) - I = getFlatIcon(obj) //Ugly - bicon_cache[key] = icon2base64(I, key) + var/key + var/changes_often = ishuman(A) || isobserver(A) // If this ends up with more, move it into a proc or var on atom. + + if(changes_often) + key = "\ref[A]" + else + key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]" + + var/base64 = GLOB.bicon_cache[key] + // Non-human atom, no cache + if(!base64) // Doesn't exist, make it. + base64 = icon2base64(A.examine_icon(), key) + GLOB.bicon_cache[key] = base64 + if(changes_often) + addtimer(CALLBACK(GLOBAL_PROC, .proc/expire_bicon_cache, key), 50 SECONDS, TIMER_UNIQUE) + + // May add a class to the img tag created by bicon if(use_class) class = "class='icon [A.icon_state] [custom_classes]'" - return "" + return "" //Checks if the message content is a valid to_chat message /proc/is_valid_tochat_message(message)