diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index cd38c9ad5b..265f4e14db 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -33,8 +33,6 @@ GLOBAL_LIST_INIT(bitflags, list( #define CONDUCT_1 (1<<5) ///For machines and structures that should not break into parts, eg, holodeck stuff. #define NODECONSTRUCT_1 (1<<7) -///Atom queued to SSoverlay. -#define OVERLAY_QUEUED_1 (1<<8) ///Item has priority to check when entering or leaving. #define ON_BORDER_1 (1<<9) ///Whether or not this atom shows screentips when hovered over diff --git a/code/__DEFINES/overlays.dm b/code/__DEFINES/overlays.dm new file mode 100644 index 0000000000..3e5959a680 --- /dev/null +++ b/code/__DEFINES/overlays.dm @@ -0,0 +1,24 @@ +// A reasonable number of maximum overlays an object needs +// If you think you need more, rethink it +#define MAX_ATOM_OVERLAYS 100 + +/// Checks if an atom has reached the overlay limit, and make a loud error if it does. +#define VALIDATE_OVERLAY_LIMIT(changed_on) \ + if(length(changed_on.overlays) >= MAX_ATOM_OVERLAYS) { \ + var/text_lays = overlays2text(changed_on.overlays); \ + stack_trace("Too many overlays on [changed_on.type] - [length(changed_on.overlays)], refusing to update and cutting.\ + \n What follows is a printout of all existing overlays at the time of the overflow \n[text_lays]"); \ + changed_on.overlays.Cut(); \ + changed_on.add_overlay(mutable_appearance('icons/testing/greyscale_error.dmi')); \ + } \ + +/// Performs any operations that ought to run after an appearance change +/* #define POST_OVERLAY_CHANGE(changed_on) \ + if(alternate_appearances) { \ + for(var/I in changed_on.alternate_appearances){\ + var/datum/atom_hud/alternate_appearance/AA = changed_on.alternate_appearances[I];\ + if(AA.transfer_overlays){\ + AA.copy_overlays(changed_on, TRUE);\ + }\ + } \ + } */ diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 49bad31a60..a66ec3ca61 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -228,25 +228,6 @@ #define SSMOBS_DT (SSmobs.wait/10) #define SSOBJ_DT (SSobj.wait/10) -//! ## Overlays subsystem - -///Compile all the overlays for an atom from the cache lists -// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway. -#define COMPILE_OVERLAYS(A)\ - do {\ - var/list/ad = A.add_overlays;\ - var/list/rm = A.remove_overlays;\ - if(LAZYLEN(rm)){\ - A.overlays -= rm;\ - rm.Cut();\ - }\ - if(LAZYLEN(ad)){\ - A.overlays |= ad;\ - ad.Cut();\ - }\ - A.flags_1 &= ~OVERLAY_QUEUED_1;\ - } while(FALSE) - /** Create a new timer and add it to the queue. * Arguments: diff --git a/code/__HELPERS/custom_holoforms.dm b/code/__HELPERS/custom_holoforms.dm index 87f3bfbe8b..4761c1f160 100644 --- a/code/__HELPERS/custom_holoforms.dm +++ b/code/__HELPERS/custom_holoforms.dm @@ -25,7 +25,6 @@ var/icon/combined = new for(var/d in GLOB.cardinals) mannequin.setDir(d) - COMPILE_OVERLAYS(mannequin) CHECK_TICK var/icon/capture = getFlatIcon(mannequin) CHECK_TICK diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index eb0aa448d3..e5aff01eef 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1065,7 +1065,6 @@ GLOBAL_LIST_EMPTY(friendly_animal_types) var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing") - COMPILE_OVERLAYS(body) for(var/D in showDirs) var/icon/partial = getFlatIcon(body, defdir = D, no_anim = no_anim) out_icon.Insert(partial,dir=D) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index aef0022c4f..1ed2075537 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -79,10 +79,6 @@ #define CBT #endif -// A reasonable number of maximum overlays an object needs -// If you think you need more, rethink it -#define MAX_ATOM_OVERLAYS 100 - #if !defined(CBT) && !defined(SPACEMAN_DMM) #warn Building with Dream Maker is no longer supported and will result in errors. #warn In order to build, run BUILD.bat in the root directory. diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index d16c24be44..e4ac2fe140 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -164,7 +164,6 @@ DEFINE_BITFIELD(flags_1, list( "NO_LAVA_GEN_1" = NO_LAVA_GEN_1, "NO_RUINS_1" = NO_RUINS_1, "NO_SCREENTIPS_1" = NO_SCREENTIPS_1, - "OVERLAY_QUEUED_1" = OVERLAY_QUEUED_1, "ON_BORDER_1" = ON_BORDER_1, "PREVENT_CLICK_UNDER_1" = PREVENT_CLICK_UNDER_1, "PREVENT_CONTENTS_EXPLOSION_1" = PREVENT_CONTENTS_EXPLOSION_1, diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index 74b60783c3..1284664ce5 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -1,187 +1,114 @@ SUBSYSTEM_DEF(overlays) name = "Overlay" - flags = SS_TICKER - wait = 1 - priority = FIRE_PRIORITY_OVERLAYS - init_order = INIT_ORDER_OVERLAY - - var/list/queue + flags = SS_NO_FIRE|SS_NO_INIT var/list/stats - var/list/overlay_icon_state_caches - var/list/overlay_icon_cache /datum/controller/subsystem/overlays/PreInit() - overlay_icon_state_caches = list() - overlay_icon_cache = list() - queue = list() stats = list() -/datum/controller/subsystem/overlays/Initialize() - initialized = TRUE - fire(mc_check = FALSE) - return ..() - - -/datum/controller/subsystem/overlays/stat_entry(msg) - msg = "Ov:[length(queue)]" - return ..() - - /datum/controller/subsystem/overlays/Shutdown() text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log") - /datum/controller/subsystem/overlays/Recover() - overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches - overlay_icon_cache = SSoverlays.overlay_icon_cache - queue = SSoverlays.queue + stats = SSoverlays.stats - -/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE) - var/list/queue = src.queue - var/static/count = 0 - if (count) - var/c = count - count = 0 //so if we runtime on the Cut, we don't try again. - queue.Cut(1,c+1) - - for (var/thing in queue) - count++ - if(thing) - var/atom/A = thing - if(A.overlays.len >= MAX_ATOM_OVERLAYS) - //Break it real GOOD - stack_trace("Too many overlays on [A.type] - [A.overlays.len], refusing to update and cutting") - A.overlays.Cut() - continue - STAT_START_STOPWATCH - COMPILE_OVERLAYS(A) - UNSETEMPTY(A.add_overlays) - UNSETEMPTY(A.remove_overlays) - STAT_STOP_STOPWATCH - STAT_LOG_ENTRY(stats, A.type) - if(mc_check) - if(MC_TICK_CHECK) - break - else - CHECK_TICK - - if (count) - queue.Cut(1,count+1) - count = 0 +/// Converts an overlay list into text for debug printing +/// Of note: overlays aren't actually mutable appearances, they're just appearances +/// Don't have access to that type tho, so this is the best you're gonna get +/proc/overlays2text(list/overlays) + var/list/unique_overlays = list() + // As anything because we're basically doing type coerrsion, rather then actually filtering for mutable apperances + for(var/mutable_appearance/overlay as anything in overlays) + var/key = "[overlay.icon]-[overlay.icon_state]-[overlay.dir]" + unique_overlays[key] += 1 + var/list/output_text = list() + for(var/key in unique_overlays) + output_text += "([key]) = [unique_overlays[key]]" + return output_text.Join("\n") /proc/iconstate2appearance(icon, iconstate) var/static/image/stringbro = new() - var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches - var/list/cached_icon = icon_states_cache[icon] - if (cached_icon) - var/cached_appearance = cached_icon["[iconstate]"] - if (cached_appearance) - return cached_appearance stringbro.icon = icon stringbro.icon_state = iconstate - if (!cached_icon) //not using the macro to save an associated lookup - cached_icon = list() - icon_states_cache[icon] = cached_icon - var/cached_appearance = stringbro.appearance - cached_icon["[iconstate]"] = cached_appearance - return cached_appearance + return stringbro.appearance /proc/icon2appearance(icon) var/static/image/iconbro = new() - var/list/icon_cache = SSoverlays.overlay_icon_cache - . = icon_cache[icon] - if (!.) - iconbro.icon = icon - . = iconbro.appearance - icon_cache[icon] = . + iconbro.icon = icon + return iconbro.appearance -/atom/proc/build_appearance_list(old_overlays) - var/static/image/appearance_bro = new() - var/list/new_overlays = list() - if (!islist(old_overlays)) - old_overlays = list(old_overlays) - for (var/overlay in old_overlays) +/atom/proc/build_appearance_list(list/build_overlays) + if (!islist(build_overlays)) + build_overlays = list(build_overlays) + for (var/overlay in build_overlays) if(!overlay) + build_overlays -= overlay continue if (istext(overlay)) - new_overlays += iconstate2appearance(icon, overlay) +#ifdef UNIT_TESTS + // This is too expensive to run normally but running it during CI is a good test + var/list/icon_states_available = icon_states(icon) + if(!(overlay in icon_states_available)) + var/icon_file = "[icon]" || "Unknown Generated Icon" + stack_trace("Invalid overlay: Icon object '[icon_file]' [REF(icon)] used in '[src]' [type] is missing icon state [overlay].") + continue +#endif + var/index = build_overlays.Find(overlay) + build_overlays[index] = iconstate2appearance(icon, overlay) else if(isicon(overlay)) - new_overlays += icon2appearance(overlay) - else - if(isloc(overlay)) - var/atom/A = overlay - if (A.flags_1 & OVERLAY_QUEUED_1) - COMPILE_OVERLAYS(A) - appearance_bro.appearance = overlay //this works for images and atoms too! - if(!ispath(overlay)) - var/image/I = overlay - appearance_bro.dir = I.dir - new_overlays += appearance_bro.appearance - return new_overlays + var/index = build_overlays.Find(overlay) + build_overlays[index] = icon2appearance(overlay) + return build_overlays -#define NOT_QUEUED_ALREADY (!(flags_1 & OVERLAY_QUEUED_1)) -#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src; /atom/proc/cut_overlays() - LAZYINITLIST(remove_overlays) - remove_overlays = overlays.Copy() - add_overlays = null + STAT_START_STOPWATCH + overlays = null +// POST_OVERLAY_CHANGE(src) + STAT_STOP_STOPWATCH + STAT_LOG_ENTRY(SSoverlays.stats, type) - //If not already queued for work and there are overlays to remove - if(NOT_QUEUED_ALREADY && remove_overlays.len) - QUEUE_FOR_COMPILE - -/atom/proc/cut_overlay(list/overlays) +/atom/proc/cut_overlay(list/remove_overlays) if(!overlays) return - overlays = build_appearance_list(overlays) - LAZYINITLIST(add_overlays) - LAZYINITLIST(remove_overlays) - var/a_len = add_overlays.len - var/r_len = remove_overlays.len - remove_overlays += overlays - add_overlays -= overlays + STAT_START_STOPWATCH + overlays -= build_appearance_list(remove_overlays) +// POST_OVERLAY_CHANGE(src) + STAT_STOP_STOPWATCH + STAT_LOG_ENTRY(SSoverlays.stats, type) - var/fa_len = add_overlays.len - var/fr_len = remove_overlays.len - - //If not already queued and there is work to be done - if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len )) - QUEUE_FOR_COMPILE - UNSETEMPTY(add_overlays) - -/atom/proc/add_overlay(list/overlays) +/atom/proc/add_overlay(list/add_overlays) if(!overlays) return + STAT_START_STOPWATCH + overlays += build_appearance_list(add_overlays) + VALIDATE_OVERLAY_LIMIT(src) +// POST_OVERLAY_CHANGE(src) + STAT_STOP_STOPWATCH + STAT_LOG_ENTRY(SSoverlays.stats, type) - overlays = build_appearance_list(overlays) - - LAZYINITLIST(add_overlays) //always initialized after this point - var/a_len = add_overlays.len - - add_overlays += overlays - var/fa_len = add_overlays.len - if(NOT_QUEUED_ALREADY && fa_len != a_len) - QUEUE_FOR_COMPILE - -/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom +/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom if(!other) if(cut_old) cut_overlays() return + STAT_START_STOPWATCH var/list/cached_other = other.overlays.Copy() - if(cached_other) - if(cut_old || !LAZYLEN(overlays)) - remove_overlays = overlays - add_overlays = cached_other - if(NOT_QUEUED_ALREADY) - QUEUE_FOR_COMPILE - else if(cut_old) - cut_overlays() - -#undef NOT_QUEUED_ALREADY -#undef QUEUE_FOR_COMPILE + if(cut_old) + if(cached_other) + overlays = cached_other + else + overlays = null + VALIDATE_OVERLAY_LIMIT(src) +// POST_OVERLAY_CHANGE(src) + STAT_STOP_STOPWATCH + STAT_LOG_ENTRY(SSoverlays.stats, type) + else if(cached_other) + overlays += cached_other + VALIDATE_OVERLAY_LIMIT(src) +// POST_OVERLAY_CHANGE(src) + STAT_STOP_STOPWATCH + STAT_LOG_ENTRY(SSoverlays.stats, type) //TODO: Better solution for these? /image/proc/add_overlay(x) @@ -207,3 +134,100 @@ SUBSYSTEM_DEF(overlays) overlays |= cached_other else if(cut_old) cut_overlays() + +// Debug procs + +/atom + /// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances + /// Drawn from the overlays list + var/list/realized_overlays + /// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances + /// Drawn from the underlays list + var/list/realized_underlays + +/image + /// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances + /// Drawn from the overlays list + var/list/realized_overlays + /// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances + /// Drawn from the underlays list + var/list/realized_underlays + +/// Takes the atoms's existing overlays and underlays, and makes them mutable so they can be properly vv'd in the realized_overlays/underlays list +/atom/proc/realize_overlays() + realized_overlays = realize_appearance_queue(overlays) + realized_underlays = realize_appearance_queue(underlays) + +/// Takes the image's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list +/image/proc/realize_overlays() + realized_overlays = realize_appearance_queue(overlays) + realized_underlays = realize_appearance_queue(underlays) + +/// Takes a list of appearnces, makes them mutable so they can be properly vv'd and inspected +/proc/realize_appearance_queue(list/appearances) + var/list/real_appearances = list() + var/list/queue = appearances.Copy() + var/queue_index = 0 + while(queue_index < length(queue)) + queue_index++ + // If it's not a command, we assert that it's an appearance + var/mutable_appearance/appearance = queue[queue_index] + if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst + continue + + var/mutable_appearance/new_appearance = new /mutable_appearance() + new_appearance.appearance = appearance + var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]" + var/tmp_key = key + var/appearance_indx = 1 + while(real_appearances[tmp_key]) + tmp_key = "[key]-[appearance_indx]" + appearance_indx++ + + real_appearances[tmp_key] = new_appearance + var/add_index = queue_index + // Now check its children + for(var/mutable_appearance/child_appearance as anything in appearance.overlays) + add_index++ + queue.Insert(add_index, child_appearance) + for(var/mutable_appearance/child_appearance as anything in appearance.underlays) + add_index++ + queue.Insert(add_index, child_appearance) + return real_appearances + +/// Takes two appearances as args, prints out, logs, and returns a text representation of their differences +/// Including suboverlays +/proc/diff_appearances(mutable_appearance/first, mutable_appearance/second, iter = 0) + var/list/diffs = list() + var/list/firstdeet = first.vars + var/list/seconddeet = second.vars + var/diff_found = FALSE + for(var/name in first.vars) + var/firstv = firstdeet[name] + var/secondv = seconddeet[name] + if(firstv ~= secondv) + continue + if((islist(firstv) || islist(secondv)) && length(firstv) == 0 && length(secondv) == 0) + continue + if(name == "vars") // Go away + continue + if(name == "_listen_lookup") // This is just gonna happen with marked datums, don't care + continue + if(name == "overlays") + first.realize_overlays() + second.realize_overlays() + var/overlays_differ = FALSE + for(var/i in 1 to length(first.realized_overlays)) + if(diff_appearances(first.realized_overlays[i], second.realized_overlays[i], iter + 1)) + overlays_differ = TRUE + + if(!overlays_differ) + continue + + diff_found = TRUE + diffs += "Diffs detected at [name]: First ([firstv]), Second ([secondv])" + + var/text = "Depth of: [iter]\n\t[diffs.Join("\n\t")]" + message_admins(text) + log_world(text) + return diff_found diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index aeb810cfdd..bb033c10c9 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -317,7 +317,6 @@ if(outfit_type) mannequin.equipOutfit(outfit_type,TRUE) mannequin.setDir(SOUTH) - COMPILE_OVERLAYS(mannequin) . = image(mannequin) unset_busy_human_dummy("HOLODISK_PRESET") diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 6b1d28fcba..19d6688ee8 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -43,18 +43,23 @@ /obj/machinery/computer/update_overlays() . = ..() SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays) - if(stat & NOPOWER) - . += "[icon_keyboard]_off" - return - . += icon_keyboard + if(icon_keyboard) + if(stat & NOPOWER) + . += "[icon_keyboard]_off" + else + . += icon_keyboard - // This whole block lets screens ignore lighting and be visible even in the darkest room - // We can't do this for many things that emit light unfortunately because it layers over things that would be on top of it - var/overlay_state = icon_screen if(stat & BROKEN) - overlay_state = "[icon_state]_broken" - . += mutable_appearance(icon, overlay_state) - . += emissive_appearance(icon, overlay_state) + . += mutable_appearance(icon, "[icon_state]_broken") + return // If we don't do this broken computers glow in the dark. + + if(stat & NOPOWER) // Your screen can't be on if you've got no damn charge + return + + // This lets screens ignore lighting and be visible even in the darkest room + if(icon_screen) + . += mutable_appearance(icon, icon_screen) + . += emissive_appearance(icon, icon_screen) /obj/machinery/computer/power_change() ..() diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 276c1796b3..625886611a 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( name = "random arcade" desc = "random arcade machine" icon_state = "arcade" - icon_keyboard = "no_keyboard" + icon_keyboard = null icon_screen = "invaders" light_color = LIGHT_COLOR_GREEN var/list/prize_override diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 056a0dafda..97d2f3bab4 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -209,7 +209,7 @@ name = "security camera monitor" desc = "An old TV hooked into the station's camera network." icon_state = "television" - icon_keyboard = "no_keyboard" + icon_keyboard = null icon_screen = "detective_tv" pass_flags = PASSTABLE @@ -252,6 +252,7 @@ desc = "Used for watching an empty arena." icon = 'icons/obj/stationobjs.dmi' icon_state = "telescreen" + icon_keyboard = null layer = SIGN_LAYER network = list("thunder") density = FALSE diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm index a7071ac72e..54b515f74c 100644 --- a/code/game/machinery/computer/pod.dm +++ b/code/game/machinery/computer/pod.dm @@ -138,13 +138,13 @@ name = "\improper DoorMex control console" icon_state = "oldcomp" icon_screen = "library" - icon_keyboard = "no_keyboard" + icon_keyboard = null // /obj/machinery/computer/pod/old/mass_driver_controller // name = "\improper Mass Driver Controller" // icon = 'icons/obj/airlock_machines.dmi' // icon_state = "airlock_control_standby" -// icon_keyboard = "no_keyboard" +// icon_keyboard = null // density = FALSE // /obj/machinery/computer/pod/old/mass_driver_controller/toxinsdriver diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm index f7a6b6db2a..1c78345338 100644 --- a/code/game/machinery/slotmachine.dm +++ b/code/game/machinery/slotmachine.dm @@ -19,6 +19,7 @@ desc = "Gambling for the antisocial." icon = 'icons/obj/economy.dmi' icon_state = "slots1" + icon_keyboard = null density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 50 diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 6d5ab1cdce..61641e1d49 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -558,8 +558,9 @@ RLD . = ..() if(has_ammobar) var/ratio = CEILING((matter / max_matter) * ammo_sections, 1) - cut_overlays() //To prevent infinite stacking of overlays - add_overlay("[icon_state]_charge[ratio]") + if(ratio) + cut_overlays() //To prevent infinite stacking of overlays + add_overlay("[icon_state]_charge[ratio]") /obj/item/construction/rcd/Initialize(mapload) . = ..() diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 4df3accb67..a154b8a638 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -19,6 +19,8 @@ var/on = FALSE //if the paddles are equipped (1) or on the defib (0) var/safety = TRUE //if you can zap people with the defibs on harm mode var/powered = FALSE //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise + /// If the cell can be removed via screwdriver + var/cell_removable = TRUE var/obj/item/shockpaddles/paddles var/obj/item/stock_parts/cell/cell var/combat = FALSE //if true, revive through hardsuits, allow for combat shocking, and tint paddles syndicate colors @@ -29,6 +31,16 @@ var/timedeath = 10 var/disarm_shock_time = 10 var/always_emagged = FALSE + /// The icon state for the paddle overlay, not applied if null + var/paddle_state = "defibunit-paddles" + /// The icon state for the powered on overlay, not applied if null + var/powered_state = "defibunit-powered" + /// The icon state for the charge bar overlay, not applied if null + var/charge_state = "defibunit-charge" + /// The icon state for the missing cell overlay, not applied if null + var/nocell_state = "defibunit-nocell" + /// The icon state for the emagged overlay, not applied if null + var/emagged_state = "defibunit-emagged" /obj/item/defibrillator/get_cell() return cell @@ -56,18 +68,19 @@ /obj/item/defibrillator/update_overlays() . = ..() - if(!on) - . += "[initial(icon_state)]-paddles" - if(powered) - . += "[initial(icon_state)]-powered" - if(!QDELETED(cell)) + + if(!on && paddle_state) + . += paddle_state + if(powered && powered_state) + . += powered_state + if(!QDELETED(cell) && charge_state) var/ratio = cell.charge / cell.maxcharge ratio = CEILING(ratio*4, 1) * 25 - add_overlay("[initial(icon_state)]-charge[ratio]") - if(!cell) - . += "[initial(icon_state)]-nocell" - if(!safety) - . += "[initial(icon_state)]-emagged" + . += "[charge_state][ratio]" + if(!cell && nocell_state) + . += "[nocell_state]" + if(!safety && emagged_state) + . += emagged_state /obj/item/defibrillator/CheckParts(list/parts_list) ..() @@ -103,6 +116,18 @@ var/atom/movable/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(src, H.held_index) +/obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/tool) + if(!cell || !cell_removable) + return FALSE + + cell.update_appearance() + cell.forceMove(get_turf(src)) + balloon_alert(user, "removed [cell]") + cell = null + tool.play_tool_sound(src, 50) + update_power() + return TRUE + /obj/item/defibrillator/attackby(obj/item/W, mob/user, params) if(W == paddles) toggle_paddles() @@ -120,13 +145,6 @@ to_chat(user, "You install a cell in [src].") update_power() - else if(W.tool_behaviour == TOOL_SCREWDRIVER) - if(cell) - cell.update_icon() - cell.forceMove(get_turf(src)) - cell = null - to_chat(user, "You remove the cell from [src].") - update_power() else return ..() @@ -236,6 +254,11 @@ item_state = "defibcompact" w_class = WEIGHT_CLASS_NORMAL slot_flags = ITEM_SLOT_BELT + paddle_state = "defibcompact-paddles" + powered_state = "defibcompact-powered" + charge_state = "defibcompact-charge" + nocell_state = "defibcompact-nocell" + emagged_state = "defibcompact-emagged" /obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user, datum/action/A) if(slot == user.getBeltSlot()) @@ -254,6 +277,13 @@ always_emagged = TRUE disarm_shock_time = 0 cell = /obj/item/stock_parts/cell/infinite + paddles = /obj/item/shockpaddles/syndicate + paddle_state = "defibcombat-paddles" + powered_state = null + emagged_state = null + +/obj/item/defibrillator/compact/combat/loaded + cell_removable = FALSE // Don't let people just have an infinite power cell /obj/item/defibrillator/compact/combat/loaded/attackby(obj/item/W, mob/user, params) if(W == paddles) diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 667e8f9db9..9aa29a4d75 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -639,6 +639,7 @@ icon = 'icons/obj/cigarettes.dmi' icon_state = "matchbox" item_state = "zippo" + illustration = null w_class = WEIGHT_CLASS_TINY slot_flags = ITEM_SLOT_BELT custom_price = PRICE_REALLY_CHEAP diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 0176abd505..a713ddfbf4 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -76,7 +76,8 @@ . += "[icon_door_override ? icon_door : icon_state]_open" return - . += "[icon_door || icon_state]_door" + if(icon_door) + . += "[icon_door || icon_state]_door" if(welded) . += icon_welded diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index 14d28b17d3..fc0b7c96c8 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -3,6 +3,7 @@ name = "large cardboard box" desc = "Just a box..." icon_state = "cardboard" + icon_door = null mob_storage_capacity = 1 resistance_flags = FLAMMABLE max_integrity = 70 diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 89c0e0210e..9e570608f2 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -307,7 +307,6 @@ GLOBAL_VAR_INIT(say_disabled, FALSE) qdel(I) randomize_human(D) JB.equip(D, TRUE, FALSE) - COMPILE_OVERLAYS(D) var/icon/I = icon(getFlatIcon(D), frame = 1) final.Insert(I, JB.title) qdel(D) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index e7fc2c3f94..292c0564b0 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -314,7 +314,6 @@ equipAntagOnDummy(mannequin, ert) - COMPILE_OVERLAYS(mannequin) CHECK_TICK var/icon/preview_icon = icon('icons/effects/effects.dmi', "nothing") preview_icon.Scale(48+32, 16+32) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 136a4c6e69..9f3556dbb6 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -391,7 +391,6 @@ GLOBAL_LIST_EMPTY(antagonists) /datum/antagonist/proc/render_preview_outfit(datum/outfit/outfit, mob/living/carbon/human/dummy) dummy = dummy || new /mob/living/carbon/human/dummy/consistent dummy.equipOutfit(outfit, visualsOnly = TRUE) - COMPILE_OVERLAYS(dummy) var/icon = getFlatIcon(dummy) // We don't want to qdel the dummy right away, since its items haven't initialized yet. diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 9e0a2b46b1..29404eb24e 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -13,6 +13,7 @@ icon = 'icons/obj/abductor.dmi' icon_state = "camera" + icon_keyboard = null resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF /obj/machinery/computer/camera_advanced/abductor/CreateEye() diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 479a80b0f6..d7d53ba691 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -1342,7 +1342,6 @@ GLOBAL_LIST_INIT(hallucination_list, list( var/datum/preferences/prefs = C.client.prefs var/mob/living/carbon/human/dummy/M = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_HALLUCINATION) prefs.copy_to(M) - COMPILE_OVERLAYS(M) CHECK_TICK image = image(M,C) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_HALLUCINATION) diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm index 14545f9570..78314ee6b6 100644 --- a/code/modules/mining/aux_base.dm +++ b/code/modules/mining/aux_base.dm @@ -15,6 +15,7 @@ name = "auxillary base management console" icon = 'icons/obj/terminals.dmi' icon_state = "dorm_available" + icon_keyboard = null var/shuttleId = "colony_drop" desc = "Allows a deployable expedition base to be dropped from the station to a designated mining location. It can also \ interface with the mining shuttle at the landing site if a mobile beacon is also deployed." diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index a978e541bf..aaa5e04c0e 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -70,7 +70,6 @@ mannequin.regenerate_icons() - COMPILE_OVERLAYS(mannequin) parent.show_character_previews(new /mutable_appearance(mannequin)) unset_busy_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 51710affc0..bf8899e5d5 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -20,7 +20,8 @@ var/chargerate = 100 //how much power is given every tick in a recharger var/self_recharge = 0 //does it self recharge, over time, or not? var/ratingdesc = TRUE - var/grown_battery = FALSE // If it's a grown that acts as a battery, add a wire overlay to it. + ///If it's a grown that acts as a battery, add a wire overlay to it. + var/grown_battery = FALSE rad_flags = RAD_NO_CONTAMINATE // Prevent the same cheese as with the stock parts /obj/item/stock_parts/cell/get_cell() @@ -61,7 +62,8 @@ /obj/item/stock_parts/cell/update_overlays() . = ..() if(grown_battery) - . += image('icons/obj/power.dmi',"grown_wires") + . += image('icons/obj/power.dmi', "grown_wires") + return if(charge < 0.01) return else if(charge/maxcharge >=0.995) diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 0bb1c3cada..f0285a5ad9 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -220,6 +220,7 @@ can_suppress = FALSE burst_size = 3 burst_shot_delay = 1 + automatic_burst_overlay = FALSE // Bulldog shotgun // diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index a34e0f6f12..4fd0220ee3 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -45,6 +45,8 @@ desc = "A modified version of the basic phaser gun, this one fires less concentrated energy bolts designed for target practice." ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/practice) icon_state = "decloner" + //You have no icons for energy types, you're a decloner + modifystate = FALSE /obj/item/gun/energy/e_gun/hos name = "\improper X-01 MultiPhase Energy Gun" @@ -78,6 +80,7 @@ lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap) + modifystate = FALSE can_flashlight = 0 ammo_x_offset = 1 diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 6991aeef43..7ae4aae5fc 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -7,6 +7,7 @@ density = TRUE icon = 'icons/obj/chemical.dmi' icon_state = "mixer0" + icon_keyboard = null use_power = TRUE idle_power_usage = 20 resistance_flags = ACID_PROOF diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index 794f2bcd44..d6d934530c 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -45,6 +45,7 @@ desc = "Controls the drop pod's launch system." icon = 'icons/obj/terminals.dmi' icon_state = "dorm_available" + icon_keyboard = null light_color = LIGHT_COLOR_BLUE req_access = list(ACCESS_SYNDICATE) shuttleId = "steel_rain" diff --git a/icons/Testing/greyscale_error.dmi b/icons/Testing/greyscale_error.dmi new file mode 100644 index 0000000000..6c781a70ad Binary files /dev/null and b/icons/Testing/greyscale_error.dmi differ diff --git a/icons/obj/dice.dmi b/icons/obj/dice.dmi index 1d6601aa31..aecdbde71c 100644 Binary files a/icons/obj/dice.dmi and b/icons/obj/dice.dmi differ diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi index 580d78900d..fdffb346ea 100644 Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index 3204b36cc5..d4f1eb71ee 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 9d25bf3a57..4d5b5f23de 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -90,6 +90,7 @@ #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\nanites.dm" #include "code\__DEFINES\networks.dm" +#include "code\__DEFINES\overlays.dm" #include "code\__DEFINES\pinpointers.dm" #include "code\__DEFINES\pipe_construction.dm" #include "code\__DEFINES\plumbing.dm"