diff --git a/code/__defines/items_clothing.dm b/code/__defines/items_clothing.dm
index c33d92609c..8cb0d04bab 100644
--- a/code/__defines/items_clothing.dm
+++ b/code/__defines/items_clothing.dm
@@ -36,7 +36,7 @@
#define ACCESSORY_SLOT_ARMOR_M "Misc armor"
#define ACCESSORY_SLOT_HELM_C "Helmet cover"
-// Flags bitmasks.
+// Flags bitmasks. - Used in /atom/var/flags
#define NOBLUDGEON 0x1 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
#define CONDUCT 0x2 // Conducts electricity. (metal etc.)
#define ON_BORDER 0x4 // Item has priority to check when entering or leaving.
@@ -45,8 +45,9 @@
#define PHORONGUARD 0x20 // Does not get contaminated by phoron.
#define NOREACT 0x40 // Reagents don't react inside this container.
#define PROXMOVE 0x80 // Does this object require proximity checking in Enter()?
+#define OVERLAY_QUEUED 0x100 // Atom queued to SSoverlay for COMPILE_OVERLAYS
-//Flags for items (equipment)
+//Flags for items (equipment) - Used in /obj/item/var/item_flags
#define THICKMATERIAL 0x1 // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
#define STOPPRESSUREDAMAGE 0x2 // Counts towards pressure protection. Note that like temperature protection, body_parts_covered is considered here as well.
#define AIRTIGHT 0x4 // Functions with internals.
@@ -54,13 +55,13 @@
#define BLOCK_GAS_SMOKE_EFFECT 0x10 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
#define FLEXIBLEMATERIAL 0x20 // At the moment, masks with this flag will not prevent eating even if they are covering your face.
-// Flags for pass_flags.
+// Flags for pass_flags. - Used in /atom/var/pass_flags
#define PASSTABLE 0x1
#define PASSGLASS 0x2
#define PASSGRILLE 0x4
#define PASSBLOB 0x8
-// Bitmasks for the flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
+// Bitmasks for the /obj/item/var/flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
// WARNING: The following flags apply only to the external suit!
#define HIDEGLOVES 0x1
#define HIDESUITSTORAGE 0x2
diff --git a/code/__defines/math.dm b/code/__defines/math.dm
index 79dc1b4d24..4245b5b564 100644
--- a/code/__defines/math.dm
+++ b/code/__defines/math.dm
@@ -9,6 +9,8 @@
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
+#define SHORT_REAL_LIMIT 16777216 // 2^24 - Maximum integer that can be exactly represented in a float (BYOND num var)
+
#define CEILING(x, y) ( -round(-(x) / (y)) * (y) )
// round() acts like floor(x, 1) by default but can't handle other values
#define FLOOR(x, y) ( round((x) / (y)) * (y) )
diff --git a/code/__defines/stat_tracking.dm b/code/__defines/stat_tracking.dm
new file mode 100644
index 0000000000..79337bda5c
--- /dev/null
+++ b/code/__defines/stat_tracking.dm
@@ -0,0 +1,17 @@
+//
+// Defines used for advanced performance profiling of subsystems.
+// Currently used only by SSoverlays (2018-02-24 ~Leshana)
+//
+#define STAT_ENTRY_TIME 1
+#define STAT_ENTRY_COUNT 2
+#define STAT_ENTRY_LENGTH 2
+
+#define STAT_START_STOPWATCH var/STAT_STOP_WATCH = TICK_USAGE
+#define STAT_STOP_STOPWATCH var/STAT_TIME = TICK_USAGE_TO_MS(STAT_STOP_WATCH)
+#define STAT_LOG_ENTRY(entrylist, entryname) \
+ var/list/STAT_ENTRY = entrylist[entryname] || (entrylist[entryname] = new /list(STAT_ENTRY_LENGTH));\
+ STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\
+ var/STAT_INCR_AMOUNT = min(1, 2**round((STAT_ENTRY[STAT_ENTRY_COUNT] || 0)/SHORT_REAL_LIMIT));\
+ if (STAT_INCR_AMOUNT == 1 || prob(100/STAT_INCR_AMOUNT)) {\
+ STAT_ENTRY[STAT_ENTRY_COUNT] += STAT_INCR_AMOUNT;\
+ };\
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index ccbb9306ed..5b459f73ff 100644
--- a/code/__defines/subsystems.dm
+++ b/code/__defines/subsystems.dm
@@ -29,5 +29,35 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
#define INIT_ORDER_MACHINES 10
#define INIT_ORDER_SHUTTLES 3
#define INIT_ORDER_LIGHTING 0
-#define INIT_ORDER_AIR -1
+#define INIT_ORDER_AIR -1
+#define INIT_ORDER_OVERLAY -6
#define INIT_ORDER_XENOARCH -20
+
+
+// Subsystem fire priority, from lowest to highest priority
+// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
+
+ #define FIRE_PRIORITY_OVERLAYS 500
+
+// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)
+// TODO - I don't really like the location of this macro define. Consider it. ~Leshana
+#define COMPILE_OVERLAYS(A)\
+ if (TRUE) {\
+ var/list/oo = A.our_overlays;\
+ var/list/po = A.priority_overlays;\
+ if(LAZYLEN(po)){\
+ if(LAZYLEN(oo)){\
+ A.overlays = oo + po;\
+ }\
+ else{\
+ A.overlays = po;\
+ }\
+ }\
+ else if(LAZYLEN(oo)){\
+ A.overlays = oo;\
+ }\
+ else{\
+ A.overlays.Cut();\
+ }\
+ A.flags &= ~OVERLAY_QUEUED;\
+ }
diff --git a/code/_helpers/sorts/comparators.dm b/code/_helpers/sorts/comparators.dm
index 1b4b834692..7fd07ec711 100644
--- a/code/_helpers/sorts/comparators.dm
+++ b/code/_helpers/sorts/comparators.dm
@@ -36,3 +36,9 @@
. = b.head_position - a.head_position
if (. == 0) //Already in head/nothead spot, sort by name
. = sorttext(b.title, a.title)
+
+// Sorts entries in a performance stats list.
+/proc/cmp_generic_stat_item_time(list/A, list/B)
+ . = B[STAT_ENTRY_TIME] - A[STAT_ENTRY_TIME]
+ if (!.)
+ . = B[STAT_ENTRY_COUNT] - A[STAT_ENTRY_COUNT]
diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm
new file mode 100644
index 0000000000..6d7581e126
--- /dev/null
+++ b/code/controllers/subsystems/overlays.dm
@@ -0,0 +1,253 @@
+SUBSYSTEM_DEF(overlays)
+ name = "Overlay"
+ flags = SS_TICKER
+ wait = 1
+ priority = FIRE_PRIORITY_OVERLAYS
+ init_order = INIT_ORDER_OVERLAY
+
+ var/initialized = FALSE
+ var/list/queue // Queue of atoms needing overlay compiling (TODO-VERIFY!)
+ var/list/stats
+ var/list/overlay_icon_state_caches // Cache thing
+ var/list/overlay_icon_cache // Cache thing
+
+/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)
+ ..()
+
+/datum/controller/subsystem/overlays/stat_entry()
+ ..("Ov:[length(queue)]")
+
+
+/datum/controller/subsystem/overlays/Shutdown()
+ //text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log")
+ var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day")
+ text2file(render_stats(stats), "data/logs/[date_string]-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
+
+
+/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)
+ STAT_START_STOPWATCH
+ var/atom/A = thing
+ COMPILE_OVERLAYS(A)
+ 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
+
+/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
+
+/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] = .
+
+/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)
+ if(!overlay)
+ continue
+ if (istext(overlay))
+ new_overlays += iconstate2appearance(icon, overlay)
+ else if(isicon(overlay))
+ new_overlays += icon2appearance(overlay)
+ else
+ if(isloc(overlay))
+ var/atom/A = overlay
+ if (A.flags & OVERLAY_QUEUED)
+ 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
+
+#define NOT_QUEUED_ALREADY (!(flags & OVERLAY_QUEUED))
+#define QUEUE_FOR_COMPILE flags |= OVERLAY_QUEUED; SSoverlays.queue += src;
+
+/**
+ * Cut all of atom's normal overlays. Usually leaves "priority" overlays untouched.
+ *
+ * @param priority If true, also will cut priority overlays.
+ */
+/atom/proc/cut_overlays(priority = FALSE)
+ var/list/cached_overlays = our_overlays
+ var/list/cached_priority = priority_overlays
+
+ var/need_compile = FALSE
+
+ if(LAZYLEN(cached_overlays)) //don't queue empty lists, don't cut priority overlays
+ cached_overlays.Cut() //clear regular overlays
+ need_compile = TRUE
+
+ if(priority && LAZYLEN(cached_priority))
+ cached_priority.Cut()
+ need_compile = TRUE
+
+ if(NOT_QUEUED_ALREADY && need_compile)
+ QUEUE_FOR_COMPILE
+
+/**
+ * Removes specific overlay(s) from the atom. Usually does not remove them from "priority" overlays.
+ *
+ * @param overlays The overlays to removed, type can be anything that is allowed for add_overlay().
+ * @param priority If true, also will remove them from the "priority" overlays.
+ */
+/atom/proc/cut_overlay(list/overlays, priority)
+ if(!overlays)
+ return
+
+ overlays = build_appearance_list(overlays)
+
+ var/list/cached_overlays = our_overlays //sanic
+ var/list/cached_priority = priority_overlays
+ var/init_o_len = LAZYLEN(cached_overlays)
+ var/init_p_len = LAZYLEN(cached_priority) //starter pokemon
+
+ LAZYREMOVE(cached_overlays, overlays)
+ if(priority)
+ LAZYREMOVE(cached_priority, overlays)
+
+ if(NOT_QUEUED_ALREADY && ((init_o_len != LAZYLEN(cached_overlays)) || (init_p_len != LAZYLEN(cached_priority))))
+ QUEUE_FOR_COMPILE
+
+/**
+ * Adds specific overlay(s) to the atom.
+ * It is designed so any of the types allowed to be added to /atom/overlays can be added here too. More details below.
+ *
+ * @param overlays The overlay(s) to add. These may be
+ * - A string: In which case it is treated as an icon_state of the atom's icon.
+ * - An icon: It is treated as an icon.
+ * - An atom: Its own overlays are compiled and then it's appearance is added. (Meaning its current apperance is frozen).
+ * - An image: Image's apperance is added (i.e. subsequently editing the image will not edit the overlay)
+ * - A type path: Added to overlays as is. Does whatever it is BYOND does when you add paths to overlays.
+ * - Or a list containing any of the above.
+ * @param priority The overlays are added to the "priority" list istead of the normal one.
+ */
+/atom/proc/add_overlay(list/overlays, priority = FALSE)
+ if(!overlays)
+ return
+
+ overlays = build_appearance_list(overlays)
+
+ LAZYINITLIST(our_overlays) //always initialized after this point
+ LAZYINITLIST(priority_overlays)
+
+ var/list/cached_overlays = our_overlays //sanic
+ var/list/cached_priority = priority_overlays
+ var/init_o_len = cached_overlays.len
+ var/init_p_len = cached_priority.len //starter pokemon
+ var/need_compile
+
+ if(priority)
+ cached_priority += overlays //or in the image. Can we use [image] = image?
+ need_compile = init_p_len != cached_priority.len
+ else
+ cached_overlays += overlays
+ need_compile = init_o_len != cached_overlays.len
+
+ if(NOT_QUEUED_ALREADY && need_compile) //have we caught more pokemon?
+ QUEUE_FOR_COMPILE
+
+/**
+ * Copy the overlays from another atom, either replacing all of ours or appending to our existing overlays.
+ * Note: This copies only the normal overlays, not the "priority" overlays.
+ *
+ * @param other The atom to copy overlays from.
+ * @param cut_old If true, all of our overlays will be *replaced* by the other's. If other is null, that means cutting all ours.
+ */
+/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
+ if(!other)
+ if(cut_old)
+ cut_overlays()
+ return
+
+ var/list/cached_other = other.our_overlays
+ if(cached_other)
+ if(cut_old || !LAZYLEN(our_overlays))
+ our_overlays = cached_other.Copy()
+ else
+ our_overlays |= cached_other
+ if(NOT_QUEUED_ALREADY)
+ QUEUE_FOR_COMPILE
+ else if(cut_old)
+ cut_overlays()
+
+#undef NOT_QUEUED_ALREADY
+#undef QUEUE_FOR_COMPILE
+
+//TODO: Better solution for these?
+/image/proc/add_overlay(x)
+ overlays += x
+
+/image/proc/cut_overlay(x)
+ overlays -= x
+
+/image/proc/cut_overlays(x)
+ overlays.Cut()
+
+/image/proc/copy_overlays(atom/other, cut_old)
+ if(!other)
+ if(cut_old)
+ cut_overlays()
+ return
+
+ var/list/cached_other = other.our_overlays
+ if(cached_other)
+ if(cut_old || !overlays.len)
+ overlays = cached_other.Copy()
+ else
+ overlays |= cached_other
+ else if(cut_old)
+ cut_overlays()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index d23f53c23a..dba0ec67ab 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -22,6 +22,10 @@
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
///Chemistry.
+ // Overlays
+ var/list/our_overlays //our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate
+ var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
+
//Detective Work, used for the duplicate data points kept in the scanners
var/list/original_atom
// Track if we are already had initialize() called to prevent double-initialization.
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 9fcac1a398..bbd10a20dc 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -195,6 +195,7 @@ var/list/admin_verbs_debug = list(
/client/proc/cmd_debug_tog_aliens,
/client/proc/cmd_display_del_log,
/client/proc/cmd_display_init_log,
+ /client/proc/cmd_display_overlay_log,
/client/proc/air_report,
/client/proc/reload_admins,
/client/proc/reload_eventMs,
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 291b1aee0c..a7b966447d 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -335,6 +335,28 @@
if(!check_rights(R_DEBUG)) return
src << browse(replacetext(SSatoms.InitLog(), "\n", "
"), "window=initlog")
+/client/proc/cmd_display_overlay_log()
+ set category = "Debug"
+ set name = "Display overlay Log"
+ set desc = "Display SSoverlays log of everything that's passed through it."
+
+ if(!check_rights(R_DEBUG)) return
+ render_stats(SSoverlays.stats, src)
+
+// Render stats list for round-end statistics.
+/proc/render_stats(list/stats, user, sort = /proc/cmp_generic_stat_item_time)
+ sortTim(stats, sort, TRUE)
+
+ var/list/lines = list()
+ for (var/entry in stats)
+ var/list/data = stats[entry]
+ lines += "[entry] => [num2text(data[STAT_ENTRY_TIME], 10)]ms ([data[STAT_ENTRY_COUNT]]) (avg:[num2text(data[STAT_ENTRY_TIME]/(data[STAT_ENTRY_COUNT] || 1), 99)])"
+
+ if (user)
+ user << browse("