[MIRROR] Clothing fallback (#11470)

Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-08-19 18:38:30 -07:00
committed by GitHub
parent 6eb4a15df1
commit 4f205c9197
22 changed files with 119 additions and 181 deletions

View File

@@ -152,9 +152,8 @@
var/render_icon = curicon var/render_icon = curicon
if (render_icon) if (render_icon)
var/curstates = icon_states(curicon) if(!icon_exists(curicon, curstate))
if(!(curstate in curstates)) if(icon_exists(curicon, ""))
if ("" in curstates)
curstate = "" curstate = ""
else else
render_icon = FALSE render_icon = FALSE
@@ -843,21 +842,12 @@ GLOBAL_LIST_EMPTY(cached_examine_icons)
/// If you want a stack trace to be output when the given state/file doesn't exist, use /// If you want a stack trace to be output when the given state/file doesn't exist, use
/// `/proc/icon_exists_or_scream()`. /// `/proc/icon_exists_or_scream()`.
/proc/icon_exists(file, state) /proc/icon_exists(file, state)
var/static/list/icon_states_cache = list()
if(isnull(file) || isnull(state)) if(isnull(file) || isnull(state))
return FALSE //This is common enough that it shouldn't panic, imo. return FALSE //This is common enough that it shouldn't panic, imo.
if(isnull(icon_states_cache[file])) if(isnull(GLOB.icon_states_cache_lookup[file]))
icon_states_cache[file] = list() compile_icon_states_cache(file)
var/file_string = "[file]" return !isnull(GLOB.icon_states_cache_lookup[file][state])
if(isfile(file) && length(file_string)) // ensure that it's actually a file, and not a runtime icon
for(var/istate in json_decode(rustg_dmi_icon_states(file_string)))
icon_states_cache[file][istate] = TRUE
else // Otherwise, we have to use the slower BYOND proc
for(var/istate in icon_states(file))
icon_states_cache[file][istate] = TRUE
return !isnull(icon_states_cache[file][state])
/// Cached, rustg-based alternative to icon_states() /// Cached, rustg-based alternative to icon_states()
/proc/icon_states_fast(file) /proc/icon_states_fast(file)
@@ -880,3 +870,69 @@ GLOBAL_LIST_EMPTY(cached_examine_icons)
for(var/istate in icon_states(file)) for(var/istate in icon_states(file))
GLOB.icon_states_cache[file] += istate GLOB.icon_states_cache[file] += istate
GLOB.icon_states_cache_lookup[file][istate] = TRUE GLOB.icon_states_cache_lookup[file][istate] = TRUE
/// Functions the same as `/proc/icon_exists()`, but with the addition of a stack trace if the
/// specified file or state doesn't exist.
///
/// Stack traces will only be output once for each file.
/proc/icon_exists_or_scream(file, state)
if(icon_exists(file, state))
return TRUE
var/static/list/screams = list()
if(!isnull(screams[file]))
screams[file] = TRUE
stack_trace("State [state] in file [file] does not exist.")
return FALSE
/**
* Returns the size of the sprite in tiles.
* Takes the icon size and divides it by the world icon size (default 32).
* This gives the size of the sprite in tiles.
*
* @return size of the sprite in tiles
*/
/proc/get_size_in_tiles(obj/target)
var/icon/size_check = icon(target.icon, target.icon_state)
var/size = size_check.Width() / ICON_SIZE_X
return size
/// Returns a list containing the width and height of an icon file
/proc/get_icon_dimensions(icon_path)
if(istype(icon_path, /datum/universal_icon))
var/datum/universal_icon/u_icon = icon_path
icon_path = u_icon.icon_file
// Icons can be a real file(), a rsc backed file(), a dynamic rsc (dyn.rsc) reference (known as a cache reference in byond docs), or an /icon which is pointing to one of those.
// Runtime generated dynamic icons are an unbounded concept cache identity wise, the same icon can exist millions of ways and holding them in a list as a key can lead to unbounded memory usage if called often by consumers.
// Check distinctly that this is something that has this unspecified concept, and thus that we should not cache.
if (!istext(icon_path) && (!isfile(icon_path) || !length("[icon_path]")))
var/icon/my_icon = icon(icon_path)
return list("width" = my_icon.Width(), "height" = my_icon.Height())
if (isnull(GLOB.icon_dimensions[icon_path]))
// Used cached icon metadata
var/list/metadata = icon_metadata(icon_path)
var/list/result = null
if(islist(metadata) && isnum(metadata["width"]) && isnum(metadata["height"]))
result = list("width" = metadata["width"], "height" = metadata["height"])
// Otherwise, we have to use the slower BYOND proc
else
var/icon/my_icon = icon(icon_path)
result = list("width" = my_icon.Width(), "height" = my_icon.Height())
GLOB.icon_dimensions[icon_path] = result
return GLOB.icon_dimensions[icon_path]
/// Returns a list containing the width and height of an icon file, without using rustg for pure function calls
/proc/get_icon_dimensions_pure(icon_path)
// Icons can be a real file(), a rsc backed file(), a dynamic rsc (dyn.rsc) reference (known as a cache reference in byond docs), or an /icon which is pointing to one of those.
// Runtime generated dynamic icons are an unbounded concept cache identity wise, the same icon can exist millions of ways and holding them in a list as a key can lead to unbounded memory usage if called often by consumers.
// Check distinctly that this is something that has this unspecified concept, and thus that we should not cache.
if (!isfile(icon_path) || !length("[icon_path]"))
var/icon/my_icon = icon(icon_path)
return list("width" = my_icon.Width(), "height" = my_icon.Height())
if (isnull(GLOB.icon_dimensions[icon_path]))
var/icon/my_icon = icon(icon_path)
GLOB.icon_dimensions[icon_path] = list("width" = my_icon.Width(), "height" = my_icon.Height())
return GLOB.icon_dimensions[icon_path]

View File

@@ -454,7 +454,7 @@ so as to remain in compliance with the most up-to-date laws."
for(var/i in 1 to length(alerts)) for(var/i in 1 to length(alerts))
var/obj/screen/alert/alert = alerts[alerts[i]] var/obj/screen/alert/alert = alerts[alerts[i]]
if(alert.icon_state in cached_icon_states(ui_style)) if(icon_exists(ui_style, alert.icon_state))
alert.icon = ui_style alert.icon = ui_style
else if(!alert.no_underlay) else if(!alert.no_underlay)

View File

@@ -563,19 +563,6 @@ GLOBAL_LIST_EMPTY(icon_dimensions)
"y" = icon_height > world.icon_size /*&& pixel_y != 0*/ ? (icon_height - world.icon_size) * 0.5 : 0, // we don't have pixel_y in use "y" = icon_height > world.icon_size /*&& pixel_y != 0*/ ? (icon_height - world.icon_size) * 0.5 : 0, // we don't have pixel_y in use
) )
/// Returns a list containing the width and height of an icon file
/proc/get_icon_dimensions(icon_path)
// Icons can be a real file(), a rsc backed file(), a dynamic rsc (dyn.rsc) reference (known as a cache reference in byond docs), or an /icon which is pointing to one of those.
// Runtime generated dynamic icons are an unbounded concept cache identity wise, the same icon can exist millions of ways and holding them in a list as a key can lead to unbounded memory usage if called often by consumers.
// Check distinctly that this is something that has this unspecified concept, and thus that we should not cache.
if (!isfile(icon_path) || !length("[icon_path]"))
var/icon/my_icon = icon(icon_path)
return list("width" = my_icon.Width(), "height" = my_icon.Height())
if (isnull(GLOB.icon_dimensions[icon_path]))
var/icon/my_icon = icon(icon_path)
GLOB.icon_dimensions[icon_path] = list("width" = my_icon.Width(), "height" = my_icon.Height())
return GLOB.icon_dimensions[icon_path]
/// Returns the src and all recursive contents as a list. /// Returns the src and all recursive contents as a list.
/atom/proc/get_all_contents(ignore_flag_1) /atom/proc/get_all_contents(ignore_flag_1)
. = list(src) . = list(src)

View File

@@ -314,7 +314,7 @@ GLOBAL_LIST_EMPTY(suit_cycler_emagged)
/datum/suit_cycler_choice/species/proc/can_refit_to(...) /datum/suit_cycler_choice/species/proc/can_refit_to(...)
for(var/obj/item/clothing/C in args) for(var/obj/item/clothing/C in args)
if(LAZYACCESS(C.sprite_sheets_obj, name)) if(LAZYACCESS(C.sprite_sheets_obj, name))
if(!(C.icon_state in cached_icon_states(C.sprite_sheets_obj[name]))) if(!icon_exists(C.sprite_sheets_obj[name], C.icon_state))
return FALSE // Species was in sprite_sheets_obj, but had no sprite for this object in particular return FALSE // Species was in sprite_sheets_obj, but had no sprite for this object in particular
return TRUE return TRUE

View File

@@ -40,7 +40,7 @@
var/icon/Cutter var/icon/Cutter
if("[initial_icon]_cutter" in cached_icon_states(icon)) if(icon_exists(icon, "[initial_icon]_cutter"))
Cutter = new(src.icon, "[initial_icon]_cutter") Cutter = new(src.icon, "[initial_icon]_cutter")
if(Cutter) if(Cutter)

View File

@@ -947,13 +947,17 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
//2: species-specific sprite sheets (skipped for inhands) //2: species-specific sprite sheets (skipped for inhands)
if(LAZYLEN(sprite_sheets) && !inhands) if(LAZYLEN(sprite_sheets) && !inhands)
var/sheet = sprite_sheets[body_type] var/sheet = sprite_sheets[body_type]
if(sheet) if(sheet && icon_exists(sheet, icon_state)) //Checks to make sure our custom sheet actually HAS the icon_state
return sheet return sheet
//3: slot-specific sprite sheets //3: slot-specific sprite sheets
if(LAZYLEN(item_icons)) if(LAZYLEN(item_icons))
var/sheet = item_icons[slot_name] var/sheet = item_icons[slot_name]
if(sheet) if(sheet)
/* //Alerts that we are equipping an item that has no item_state for the slot-specific icon sheet. Commented out because it's not really too important.
if(!icon_exists(sheet, icon_state))
log_debug("Item [src] is equippable on the [slot_name] but has no sprite for it!")
*/
return sheet return sheet
//4: item's default icon //4: item's default icon

View File

@@ -71,7 +71,7 @@
cut_overlays() cut_overlays()
if(front_id) if(front_id)
var/tiny_state = "id-generic" var/tiny_state = "id-generic"
if("id-[front_id.icon_state]" in cached_icon_states(icon)) if(icon_exists(icon, "id-[front_id.icon_state]"))
tiny_state = "id-"+front_id.icon_state tiny_state = "id-"+front_id.icon_state
var/image/tiny_image = new/image(icon, icon_state = tiny_state) var/image/tiny_image = new/image(icon, icon_state = tiny_state)
tiny_image.appearance_flags = RESET_COLOR tiny_image.appearance_flags = RESET_COLOR

View File

@@ -129,7 +129,7 @@ two tiles on initialization, and which way a cliff is facing may change during m
var/subtraction_icon_state = "[icon_state]-subtract" var/subtraction_icon_state = "[icon_state]-subtract"
var/cache_string = "[icon_state]_[T.icon]_[T.icon_state]" var/cache_string = "[icon_state]_[T.icon]_[T.icon_state]"
if(T && (subtraction_icon_state in cached_icon_states(icon))) if(T && icon_exists(icon, subtraction_icon_state))
cut_overlays() cut_overlays()
// If we've made the same icon before, just recycle it. // If we've made the same icon before, just recycle it.
if(cache_string in GLOB.cliff_icon_cache) if(cache_string in GLOB.cliff_icon_cache)

View File

@@ -67,13 +67,13 @@
I.color = reinf_material.icon_colour I.color = reinf_material.icon_colour
add_overlay(I) add_overlay(I)
else else
if("[reinf_material.icon_reinf]0" in cached_icon_states(wall_masks)) if(icon_exists(wall_masks, "[reinf_material.icon_reinf]0"))
// Directional icon // Directional icon
for(var/i = 1 to 4) for(var/i = 1 to 4)
I = image(wall_masks, "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1)) I = image(wall_masks, "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
I.color = reinf_material.icon_colour I.color = reinf_material.icon_colour
add_overlay(I) add_overlay(I)
else if("[reinf_material.icon_reinf]" in cached_icon_states(wall_masks)) else if(icon_exists(wall_masks, "[reinf_material.icon_reinf]"))
I = image(wall_masks, reinf_material.icon_reinf) I = image(wall_masks, reinf_material.icon_reinf)
I.color = reinf_material.icon_colour I.color = reinf_material.icon_colour
add_overlay(I) add_overlay(I)

View File

@@ -30,7 +30,7 @@
if(!inv_overlay) if(!inv_overlay)
var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]" var/tmp_icon_state = "[overlay_state? "[overlay_state]" : "[icon_state]"]"
if(icon_override) if(icon_override)
if("[tmp_icon_state]_tie" in cached_icon_states(icon_override)) if(icon_exists(icon_override, "[tmp_icon_state]_tie"))
tmp_icon_state = "[tmp_icon_state]_tie" tmp_icon_state = "[tmp_icon_state]_tie"
inv_overlay = image(icon = icon_override, icon_state = tmp_icon_state, dir = SOUTH) inv_overlay = image(icon = icon_override, icon_state = tmp_icon_state, dir = SOUTH)
else else
@@ -61,7 +61,7 @@
tmp_icon_state = on_rolled["rolled"] tmp_icon_state = on_rolled["rolled"]
if(icon_override) if(icon_override)
if("[tmp_icon_state]_mob" in cached_icon_states(icon_override)) if(icon_exists(icon_override, "[tmp_icon_state]_mob"))
tmp_icon_state = "[tmp_icon_state]_mob" tmp_icon_state = "[tmp_icon_state]_mob"
mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]") mob_overlay = image("icon" = icon_override, "icon_state" = "[tmp_icon_state]")
else if(H && LAZYACCESS(sprite_sheets, H.species.get_bodytype(H))) //Teshari can finally into webbing, too! else if(H && LAZYACCESS(sprite_sheets, H.species.get_bodytype(H))) //Teshari can finally into webbing, too!

View File

@@ -15,7 +15,7 @@
if(!base_icon) if(!base_icon)
base_icon = icon_state base_icon = icon_state
if(!("[base_icon]_open" in cached_icon_states(icon))) if(!icon_exists(icon, "[base_icon]_open"))
to_chat(user, "\The [src] doesn't seem to open.") to_chat(user, "\The [src] doesn't seem to open.")
return return

View File

@@ -1045,7 +1045,7 @@
/obj/item/clothing/suit/proc/taurize(var/mob/living/carbon/human/taur, has_taur_tail = FALSE) /obj/item/clothing/suit/proc/taurize(var/mob/living/carbon/human/taur, has_taur_tail = FALSE)
if(has_taur_tail) if(has_taur_tail)
var/datum/sprite_accessory/tail/taur/taurtail = taur.tail_style var/datum/sprite_accessory/tail/taur/taurtail = taur.tail_style
if(taurtail.suit_sprites && (get_worn_icon_state(slot_wear_suit_str) in cached_icon_states(taurtail.suit_sprites))) if(taurtail.suit_sprites && (icon_exists(taurtail.suit_sprites, get_worn_icon_state(slot_wear_suit_str))))
icon_override = taurtail.suit_sprites icon_override = taurtail.suit_sprites
taurized = TRUE taurized = TRUE
// means that if a taur puts on an already taurized suit without a taur sprite // means that if a taur puts on an already taurized suit without a taur sprite
@@ -1159,7 +1159,7 @@
//autodetect rollability //autodetect rollability
if(rolled_down < 0) if(rolled_down < 0)
if(("[worn_state]_d" in cached_icon_states(icon)) || (worn_state in cached_icon_states(rolled_down_icon)) || ("[worn_state]_d" in cached_icon_states(icon_override))) if((icon_exists(icon, "[worn_state]_d") || icon_exists(rolled_down_icon, worn_state) || icon_exists(icon_override, "[worn_state]_d")))
rolled_down = 0 rolled_down = 0
if(rolled_down == -1) if(rolled_down == -1)
@@ -1179,11 +1179,11 @@
under_icon = sprite_sheets[H.species.get_bodytype(H)] under_icon = sprite_sheets[H.species.get_bodytype(H)]
else if(LAZYACCESS(item_icons, slot_w_uniform_str)) else if(LAZYACCESS(item_icons, slot_w_uniform_str))
under_icon = item_icons[slot_w_uniform_str] under_icon = item_icons[slot_w_uniform_str]
else if (worn_state in cached_icon_states(rolled_down_icon)) else if (icon_exists(rolled_down_icon, worn_state))
under_icon = rolled_down_icon under_icon = rolled_down_icon
// The _s is because the icon update procs append it. // The _s is because the icon update procs append it.
if((under_icon == rolled_down_icon && ("[worn_state]" in cached_icon_states(under_icon))) || ("[worn_state]_d" in cached_icon_states(under_icon))) if((under_icon == rolled_down_icon && (icon_exists(under_icon, worn_state))) || (icon_exists(under_icon, "[worn_state]_d")))
if(rolled_down != 1) if(rolled_down != 1)
rolled_down = 0 rolled_down = 0
else else
@@ -1202,13 +1202,13 @@
under_icon = sprite_sheets[H.species.get_bodytype(H)] under_icon = sprite_sheets[H.species.get_bodytype(H)]
else if(LAZYACCESS(item_icons, slot_w_uniform_str)) else if(LAZYACCESS(item_icons, slot_w_uniform_str))
under_icon = item_icons[slot_w_uniform_str] under_icon = item_icons[slot_w_uniform_str]
else if (worn_state in cached_icon_states(rolled_down_sleeves_icon)) else if (icon_exists(rolled_down_sleeves_icon, worn_state))
under_icon = rolled_down_sleeves_icon under_icon = rolled_down_sleeves_icon
else else
under_icon = new /icon(INV_W_UNIFORM_DEF_ICON) under_icon = new /icon(INV_W_UNIFORM_DEF_ICON)
// The _s is because the icon update procs append it. // The _s is because the icon update procs append it.
if((under_icon == rolled_down_sleeves_icon && ("[worn_state]" in cached_icon_states(under_icon))) || ("[worn_state]_r" in cached_icon_states(under_icon))) if((under_icon == rolled_down_sleeves_icon && (icon_exists(under_icon, worn_state))) || (icon_exists(under_icon, "[worn_state]_r")))
if(rolled_sleeves != 1) if(rolled_sleeves != 1)
rolled_sleeves = 0 rolled_sleeves = 0
else else
@@ -1292,7 +1292,7 @@
body_parts_covered &= ~(UPPER_TORSO|ARMS) body_parts_covered &= ~(UPPER_TORSO|ARMS)
heat_protection &= ~(UPPER_TORSO|ARMS) heat_protection &= ~(UPPER_TORSO|ARMS)
cold_protection &= ~(UPPER_TORSO|ARMS) cold_protection &= ~(UPPER_TORSO|ARMS)
if(worn_state in cached_icon_states(rolled_down_icon)) if(icon_exists(rolled_down_icon, worn_state))
icon_override = rolled_down_icon icon_override = rolled_down_icon
LAZYSET(item_state_slots, slot_w_uniform_str, worn_state) LAZYSET(item_state_slots, slot_w_uniform_str, worn_state)
else else
@@ -1329,7 +1329,7 @@
body_parts_covered &= ~(ARMS) body_parts_covered &= ~(ARMS)
heat_protection &= ~(ARMS) heat_protection &= ~(ARMS)
cold_protection &= ~(ARMS) cold_protection &= ~(ARMS)
if(worn_state in cached_icon_states(rolled_down_sleeves_icon)) if(icon_exists(rolled_down_sleeves_icon, worn_state))
icon_override = rolled_down_sleeves_icon icon_override = rolled_down_sleeves_icon
LAZYSET(item_state_slots, slot_w_uniform_str, worn_state) LAZYSET(item_state_slots, slot_w_uniform_str, worn_state)
else else
@@ -1377,7 +1377,7 @@
// only override icon if a corresponding digitigrade replacement icon_state exists // only override icon if a corresponding digitigrade replacement icon_state exists
// otherwise, keep the old non-digi icon_define (or nothing) // otherwise, keep the old non-digi icon_define (or nothing)
if(icon_state && cached_icon_states(update_icon_define_digi):Find(icon_state)) if(icon_state && cached_icon_states(update_icon_define_digi):Find(icon_state)) //Unsure what to do to this seeing as it does :Find()
update_icon_define = update_icon_define_digi update_icon_define = update_icon_define_digi

View File

@@ -49,9 +49,9 @@
var/datum/reagent/R = reagents.get_master_reagent() var/datum/reagent/R = reagents.get_master_reagent()
if(!((R.id == REAGENT_ID_ICE) || (REAGENT_ID_ICE in R.glass_special))) // if it's not a cup of ice, and it's not already supposed to have ice in, see if the bartender's put ice in it if(!((R.id == REAGENT_ID_ICE) || (REAGENT_ID_ICE in R.glass_special))) // if it's not a cup of ice, and it's not already supposed to have ice in, see if the bartender's put ice in it
if(reagents.has_reagent(REAGENT_ID_ICE, reagents.total_volume / 10)) // 10% ice by volume if(reagents.has_reagent(REAGENT_ID_ICE, reagents.total_volume / 10)) // 10% ice by volume
return 1 return TRUE
return 0 return FALSE
/obj/item/reagent_containers/food/drinks/glass2/proc/has_fizz() /obj/item/reagent_containers/food/drinks/glass2/proc/has_fizz()
if(reagents.reagent_list.len > 0) if(reagents.reagent_list.len > 0)
@@ -62,8 +62,8 @@
if("fizz" in re.glass_special) if("fizz" in re.glass_special)
totalfizzy += re.volume totalfizzy += re.volume
if(totalfizzy >= reagents.total_volume / 5) // 20% fizzy by volume if(totalfizzy >= reagents.total_volume / 5) // 20% fizzy by volume
return 1 return TRUE
return 0 return FALSE
/obj/item/reagent_containers/food/drinks/glass2/Initialize(mapload) /obj/item/reagent_containers/food/drinks/glass2/Initialize(mapload)
. = ..() . = ..()
@@ -74,12 +74,10 @@
update_icon() update_icon()
/obj/item/reagent_containers/food/drinks/glass2/proc/can_add_extra(obj/item/glass_extra/GE) /obj/item/reagent_containers/food/drinks/glass2/proc/can_add_extra(obj/item/glass_extra/GE)
if(!("[base_icon]_[GE.glass_addition]left" in cached_icon_states(icon))) //VOREStation Edit if(!icon_exists(icon, "[base_icon]_[GE.glass_addition]left") || !icon_exists(icon, "[base_icon]_[GE.glass_addition]right"))
return 0 return FALSE
if(!("[base_icon]_[GE.glass_addition]right" in cached_icon_states(icon))) //VOREStation Edit
return 0
return 1 return TRUE
/obj/item/reagent_containers/food/drinks/glass2/update_icon() /obj/item/reagent_containers/food/drinks/glass2/update_icon()
underlays.Cut() underlays.Cut()
@@ -106,9 +104,9 @@
over_liquid |= "[base_icon][amnt]_fizz" over_liquid |= "[base_icon][amnt]_fizz"
for(var/S in R.glass_special) for(var/S in R.glass_special)
if("[base_icon]_[S]" in cached_icon_states(icon)) //VOREStation Edit if(icon_exists(icon, "[base_icon]_[S]"))
under_liquid |= "[base_icon]_[S]" under_liquid |= "[base_icon]_[S]"
else if("[base_icon][amnt]_[S]" in cached_icon_states(icon)) //VOREStation Edit else if(icon_exists(icon, "[base_icon][amnt]_[S]"))
over_liquid |= "[base_icon][amnt]_[S]" over_liquid |= "[base_icon][amnt]_[S]"
for(var/k in under_liquid) for(var/k in under_liquid)
@@ -150,13 +148,13 @@
/obj/item/reagent_containers/food/drinks/glass2/afterattack(var/obj/target, var/mob/user, var/proximity) /obj/item/reagent_containers/food/drinks/glass2/afterattack(var/obj/target, var/mob/user, var/proximity)
if(user.a_intent == I_HURT) //We only want splashing to be done if they are on harm intent. if(user.a_intent == I_HURT) //We only want splashing to be done if they are on harm intent.
if(!is_open_container() || !proximity) if(!is_open_container() || !proximity)
return 1 return TRUE
if(standard_splash_mob(user, target)) if(standard_splash_mob(user, target))
return 1 return TRUE
if(reagents && reagents.total_volume) //They are on harm intent, aka wanting to spill it. if(reagents && reagents.total_volume) //They are on harm intent, aka wanting to spill it.
to_chat(user, span_notice("You splash the solution onto [target].")) to_chat(user, span_notice("You splash the solution onto [target]."))
reagents.splash(target, reagents.total_volume) reagents.splash(target, reagents.total_volume)
return 1 return TRUE
..() ..()
/obj/item/reagent_containers/food/drinks/glass2/standard_feed_mob(var/mob/user, var/mob/target) /obj/item/reagent_containers/food/drinks/glass2/standard_feed_mob(var/mob/user, var/mob/target)

View File

@@ -135,7 +135,7 @@
var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product") 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)]" fruit_base.color = "[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"
plant_icon.add_overlay(fruit_base) plant_icon.add_overlay(fruit_base)
if("[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf" in cached_icon_states('icons/obj/hydroponics_products.dmi')) if(icon_exists('icons/obj/hydroponics_products.dmi', "[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf"))
var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf") 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)]" fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]"
plant_icon.add_overlay(fruit_leaves) plant_icon.add_overlay(fruit_leaves)

View File

@@ -351,7 +351,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) //see UpdateDamageIcon()
base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3])) base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3]))
//Handle husk overlay. //Handle husk overlay.
if(husk && ("overlay_husk" in cached_icon_states(species.icobase))) if(husk && icon_exists(species.icobase, "overlay_husk"))
var/icon/mask = new(base_icon) var/icon/mask = new(base_icon)
var/icon/husk_over = new(species.icobase,"overlay_husk") 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) mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0)

View File

@@ -83,12 +83,12 @@
// Unfortunately not all these states exist, ugh. // Unfortunately not all these states exist, ugh.
else if(vore_fullness && !resting) else if(vore_fullness && !resting)
if("[chassis]_full[fullness_extension]" in cached_icon_states(icon)) if(icon_exists(icon, "[chassis]_full[fullness_extension]"))
icon_state = "[chassis]_full[fullness_extension]" icon_state = "[chassis]_full[fullness_extension]"
else else
icon_state = "[chassis]" icon_state = "[chassis]"
else if(vore_fullness && resting) else if(vore_fullness && resting)
if("[chassis]_rest_full[fullness_extension]" in cached_icon_states(icon)) if(icon_exists(icon, "[chassis]_rest_full[fullness_extension]"))
icon_state = "[chassis]_rest_full[fullness_extension]" icon_state = "[chassis]_rest_full[fullness_extension]"
else else
icon_state = "[chassis]_rest" icon_state = "[chassis]_rest"

View File

@@ -54,7 +54,7 @@
TEST_ASSERT(C.name != "", "[C.type]: Clothing - Empty name.") TEST_ASSERT(C.name != "", "[C.type]: Clothing - Empty name.")
// Icons // Icons
if(!("[C.icon_state]" in cached_icon_states(C.icon))) if(!icon_exists(C.icon, C.icon_state))
if(C.icon == initial(C.icon) && C.icon_state == initial(C.icon_state)) if(C.icon == initial(C.icon) && C.icon_state == initial(C.icon_state))
TEST_NOTICE("[C.type]: Clothing - Icon_state \"[C.icon_state]\" is not present in [C.icon].") TEST_NOTICE("[C.type]: Clothing - Icon_state \"[C.icon_state]\" is not present in [C.icon].")
else else
@@ -165,7 +165,7 @@
return return
// All that matters // All that matters
if(!("[set_state]" in cached_icon_states(set_icon))) if(!icon_exists(set_icon, set_state))
TEST_NOTICE("[item_path]: Clothing - Testing \"[species]\" state \"[set_state]\" for slot \"[slot_name]\", but it was not in dmi \"[set_icon]\"") TEST_NOTICE("[item_path]: Clothing - Testing \"[species]\" state \"[set_state]\" for slot \"[slot_name]\", but it was not in dmi \"[set_icon]\"")
signal_failed = TRUE signal_failed = TRUE
return return

View File

@@ -38,12 +38,12 @@
if(istype(accessory, /datum/sprite_accessory/hair)) if(istype(accessory, /datum/sprite_accessory/hair))
actual_icon_state += "_s" actual_icon_state += "_s"
TEST_ASSERT(actual_icon_state in cached_icon_states(accessory::icon), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].") TEST_ASSERT(icon_exists(accessory::icon, actual_icon_state), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].")
return return
if(istype(accessory, /datum/sprite_accessory/facial_hair)) if(istype(accessory, /datum/sprite_accessory/facial_hair))
actual_icon_state += "_s" actual_icon_state += "_s"
TEST_ASSERT(actual_icon_state in cached_icon_states(accessory::icon), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].") TEST_ASSERT(icon_exists(accessory::icon, actual_icon_state), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].")
return return
if(istype(accessory, /datum/sprite_accessory/marking)) if(istype(accessory, /datum/sprite_accessory/marking))
@@ -52,5 +52,5 @@
TEST_ASSERT(body_part in BP_ALL, "[accessory::name] - [accessory::type]: Cosmetic - Has an illegal bodypart \"[body_part]\". ONLY use parts listed in BP_ALL.") TEST_ASSERT(body_part in BP_ALL, "[accessory::name] - [accessory::type]: Cosmetic - Has an illegal bodypart \"[body_part]\". ONLY use parts listed in BP_ALL.")
actual_icon_state = "[accessory::icon_state]-[body_part]" actual_icon_state = "[accessory::icon_state]-[body_part]"
TEST_ASSERT(actual_icon_state in cached_icon_states(accessory::icon), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].") TEST_ASSERT(icon_exists(accessory::icon, actual_icon_state), "[accessory::name] - [accessory::type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [accessory::icon].")
return return

View File

@@ -10,4 +10,4 @@
var/icon/I = initial(P.icon) var/icon/I = initial(P.icon)
if(D.icon_override) if(D.icon_override)
I = D.icon_override I = D.icon_override
TEST_ASSERT(D.icon_state in cached_icon_states(I), "[D.type]: Poster - missing icon_state \"[D.icon_state]\" in \"[I]\", as [D.icon_override ? "override" : "base"] dmi.") TEST_ASSERT(icon_exists(I, D.icon_state), "[D.type]: Poster - missing icon_state \"[D.icon_state]\" in \"[I]\", as [D.icon_override ? "override" : "base"] dmi.")

View File

@@ -152,7 +152,7 @@
if(robot.has_dead_sprite) if(robot.has_dead_sprite)
check_state(robot,"-wreck") check_state(robot,"-wreck")
if(robot.has_dead_sprite_overlay) // Only one per dmi if(robot.has_dead_sprite_overlay) // Only one per dmi
TEST_ASSERT("wreck-overlay" in cached_icon_states(robot.sprite_icon), "[robot.type]: Robots - Robot sprite \"[robot.name]\", missing icon_state wreck-overlay, in dmi \"[robot.sprite_icon]\".") TEST_ASSERT(icon_exists(robot.sprite_icon, "wreck-overlay"), "[robot.type]: Robots - Robot sprite \"[robot.name]\", missing icon_state wreck-overlay, in dmi \"[robot.sprite_icon]\".")
// offset // offset
var/icon/I = new(robot.sprite_icon) var/icon/I = new(robot.sprite_icon)
TEST_ASSERT_EQUAL(robot.icon_x, I.Width(), "[robot.type]: Robots - Robot sprite \"[robot.name]\", icon_x \"[robot.icon_x]\" did not match dmi configured width \"[I.Width()]\"") TEST_ASSERT_EQUAL(robot.icon_x, I.Width(), "[robot.type]: Robots - Robot sprite \"[robot.name]\", icon_x \"[robot.icon_x]\" did not match dmi configured width \"[I.Width()]\"")
@@ -167,4 +167,4 @@
/datum/unit_test/all_robot_sprites_must_be_valid/proc/check_state(datum/robot_sprite/robot, append) /datum/unit_test/all_robot_sprites_must_be_valid/proc/check_state(datum/robot_sprite/robot, append)
var/check_state = "[robot.sprite_icon_state][append]" var/check_state = "[robot.sprite_icon_state][append]"
TEST_ASSERT(check_state in cached_icon_states(robot.sprite_icon), "[robot.type]: Robots - Robot sprite \"[robot.name]\", enabled but missing icon_state \"[check_state]\", in dmi \"[robot.sprite_icon]\".") TEST_ASSERT(icon_exists(robot.sprite_icon, check_state), "[robot.type]: Robots - Robot sprite \"[robot.name]\", enabled but missing icon_state \"[check_state]\", in dmi \"[robot.sprite_icon]\".")

View File

@@ -40,59 +40,6 @@
girder_material = newgmaterial girder_material = newgmaterial
update_material() update_material()
/turf/simulated/wall/update_icon()
if(!material)
return
if(!damage_overlays[1]) //list hasn't been populated
generate_overlays()
cut_overlays()
var/image/I
if(!density)
I = image(wall_masks, "[material.icon_base]fwall_open")
I.color = material.icon_colour
add_overlay(I)
return
for(var/i = 1 to 4)
I = image(wall_masks, "[material.icon_base][wall_connections[i]]", dir = 1<<(i-1))
I.color = material.icon_colour
add_overlay(I)
if(reinf_material)
if(construction_stage != null && construction_stage < 6)
I = image(wall_masks, "reinf_construct-[construction_stage]")
I.color = reinf_material.icon_colour
add_overlay(I)
else
if("[reinf_material.icon_reinf]0" in cached_icon_states(wall_masks))
// Directional icon
for(var/i = 1 to 4)
I = image(wall_masks, "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
I.color = reinf_material.icon_colour
add_overlay(I)
else if("[reinf_material.icon_reinf]" in cached_icon_states(wall_masks))
I = image(wall_masks, reinf_material.icon_reinf)
I.color = reinf_material.icon_colour
add_overlay(I)
var/image/texture = material.get_wall_texture()
if(texture)
add_overlay(texture)
if(damage != 0)
var/integrity = material.integrity
if(reinf_material)
integrity += reinf_material.integrity
var/overlay = round(damage / integrity * damage_overlays.len) + 1
if(overlay > damage_overlays.len)
overlay = damage_overlays.len
add_overlay(damage_overlays[overlay])
return
/turf/simulated/shuttlewalls/proc/generate_overlays() /turf/simulated/shuttlewalls/proc/generate_overlays()
var/alpha_inc = 256 / damage_overlays.len var/alpha_inc = 256 / damage_overlays.len

View File

@@ -1,54 +0,0 @@
//THIS FILE HAS BEEN UNTICKED, We already got energy_ch.dm, we dont need to override twice
/obj/item/projectile/energy/excavate
//damage = 20
armor_penetration = 60
/obj/item/projectile/energy/excavate/weak
//damage = 10
excavation_amount = 100
/obj/item/projectile/energy/acid
//damage = 15
/obj/item/projectile/energy/neurotoxin/toxic
damage = 10
//
/obj/item/projectile/energy/phase/bolt
range = 4
mob_bonus_damage = 15 // 30 total on animals
icon_state = "cbbolt"
hud_state = "taser"
/obj/item/projectile/energy/phase/bolt/heavy
range = 4
mob_bonus_damage = 25 // 20 total on animals
hud_state = "taser"
/obj/item/projectile/energy/plasma/vepr
//damage = 30
armor_penetration = 15
/obj/item/projectile/energy/phase
//damage = 5
mob_bonus_damage = 15
armor_penetration = 0
SA_vulnerability = list(SA_ANIMAL, MOB_CLASS_SYNTHETIC, MOB_CLASS_ABERRATION)
/obj/item/projectile/energy/phase/light
mob_bonus_damage = 5
armor_penetration = 0
/obj/item/projectile/energy/phase/heavy
//damage = 5
mob_bonus_damage = 20
armor_penetration = 0
/obj/item/projectile/energy/phase/heavy/cannon
//damage = 5
mob_bonus_damage = 35
armor_penetration = 0
/obj/item/gun/energy/Initialize(mapload)
if(icon == 'icons/obj/gun_ch.dmi' && !(icon_state in cached_icon_states('icons/obj/gun_ch.dmi')))
icon = 'icons/obj/gun.dmi'
return ..()