From d046c97ff4db281c6fba31f6b44092bbc833af86 Mon Sep 17 00:00:00 2001
From: Lexanx <61974560+Lexanx@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:35:42 +0300
Subject: [PATCH 1/2] Adherent Discharge (#2102)

---
 baystation12.dme                              |   4 +-
 mods/_master_files/code/_onclick/click.dm     |  55 +++++++++++++
 .../code/modules/species/station/adherent.dm  |   4 +
 mods/adherent_discharge/README.md             |  74 ++++++++++++++++++
 .../adherent_discharge/_adherent_discharge.dm |   4 +
 .../_adherent_discharge.dme                   |   6 ++
 mods/adherent_discharge/code/adherent.dm      |  21 +++++
 .../sounds/discharge_on.ogg                   | Bin 0 -> 15051 bytes
 mods/global_modpacks.dm                       |   1 +
 9 files changed, 168 insertions(+), 1 deletion(-)
 create mode 100644 mods/_master_files/code/_onclick/click.dm
 create mode 100644 mods/_master_files/code/modules/species/station/adherent.dm
 create mode 100644 mods/adherent_discharge/README.md
 create mode 100644 mods/adherent_discharge/_adherent_discharge.dm
 create mode 100644 mods/adherent_discharge/_adherent_discharge.dme
 create mode 100644 mods/adherent_discharge/code/adherent.dm
 create mode 100644 mods/adherent_discharge/sounds/discharge_on.ogg

diff --git a/baystation12.dme b/baystation12.dme
index e493fdfdd29ba..f22a037290f3b 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -3416,6 +3416,7 @@
 #include "maps\sierra\loadout\loadout_documents.dm"
 #include "mods\_modpack.dm"
 #include "mods\global_modpacks.dm"
+#include "mods\_master_files\code\_onclick\click.dm"
 #include "mods\_master_files\code\game\world.dm"
 #include "mods\_master_files\code\game\gamemodes\ert.dm"
 #include "mods\_master_files\code\game\objects\effects\decals\contraband.dm"
@@ -3452,9 +3453,10 @@
 #include "mods\_master_files\code\modules\mob\new_player\new_player.dm"
 #include "mods\_master_files\code\modules\power\gravitygenerator.dm"
 #include "mods\_master_files\code\modules\projectiles\projectile\bullets.dm"
-#include "mods\_master_files\code\modules\species\station\machine.dm"
+#include "mods\_master_files\code\modules\species\station\adherent.dm"
 #include "mods\_master_files\code\modules\sounds\connector.dm"
 #include "mods\_master_files\code\modules\sounds\throw.dm"
+#include "mods\_master_files\code\modules\species\station\machine.dm"
 #include "mods\_master_files\maps\sierra\sierra_ranks.dm"
 #include "mods\_master_files\maps\sierra\items\rigs.dm"
 #include "~code\global_init.dm"
diff --git a/mods/_master_files/code/_onclick/click.dm b/mods/_master_files/code/_onclick/click.dm
new file mode 100644
index 0000000000000..3b1bdf224b6bb
--- /dev/null
+++ b/mods/_master_files/code/_onclick/click.dm
@@ -0,0 +1,55 @@
+/mob/living/carbon/human/AltClickOn(atom/A)
+	if(get_dist(src, A) > 1)
+		return ..()
+	if(!stat && mind && ismob(A) && (A != src) && (src.species.name == SPECIES_ADHERENT))
+		var/mob/living/carbon/human/adherent = src
+		var/obj/item/organ/internal/cell/adherent/adherent_core = adherent.internal_organs_by_name[BP_CELL]
+		if(adherent_core.ready_to_charge)
+			var/mob/living/carbon/human/target_human = A
+			var/mob/living/target = A
+			var/obj/item/cell/target_cell
+			var/obj/item/cell/adherent_cell
+			var/obj/item/organ/internal/cell/acell = locate() in adherent.internal_organs
+			if(acell && acell.cell)
+				adherent_cell = acell.cell
+
+			if(adherent_cell && adherent_cell.charge <= 2000)
+				to_chat(src, SPAN_WARNING("Your cell charge is too low for this action."))
+				return
+
+			if(ishuman(target_human))
+				var/obj/item/organ/internal/cell/cell = locate() in target_human.internal_organs
+				if(cell && cell.cell)
+					target_cell = cell.cell
+			else if(isrobot(target))
+				var/mob/living/silicon/robot/robot = target
+				target_cell = robot.get_cell()
+
+			target.visible_message(SPAN_WARNING("There is a loud crack and the smell of ozone as \the [adherent] touches \the [target]."))
+			playsound(loc, 'sound/effects/snap.ogg', 50, 1)
+
+			if(target_cell)
+				if(target_cell.maxcharge > (target_cell.charge + 2000))
+					target_cell.charge += 2000
+				else
+					target_cell.charge = target_cell.maxcharge
+				to_chat(target, SPAN_NOTICE("<b>Your [target_cell] has been charged.</b>"))
+			adherent_cell.charge -= 2000
+			if(istype(target_human) && target_human.species.name == SPECIES_ADHERENT)
+				next_click = world.time + 2 SECONDS
+				return
+			if(isrobot(target))
+				target.apply_damage(100, DAMAGE_BURN, def_zone = src.zone_sel.selecting)
+				visible_message(SPAN_DANGER("[adherent] touches [target] with bright electrical arc connecting them."))
+				to_chat(target, SPAN_DANGER("<b>You detect damage to your components!</b>"))
+			else if(ishuman(target))
+				target.electrocute_act(100, src, def_zone = src.zone_sel.selecting)
+				visible_message(SPAN_DANGER("With bright electrical flash [adherent] touches [target] using it's tentacles."))
+			else
+				target.apply_damage(100, DAMAGE_BURN, def_zone = src.zone_sel.selecting)
+				visible_message(SPAN_DANGER("With bright electrical flash [adherent] touches [target] using it's tentacles."))
+			admin_attack_log(src, target, "Has electrocuted", "Has been electrocuted", "electrocuted")
+			target.throw_at(get_step(target,get_dir(src,target)), 5, 10)
+			next_click = world.time + 2 SECONDS
+			return
+	return ..()
\ No newline at end of file
diff --git a/mods/_master_files/code/modules/species/station/adherent.dm b/mods/_master_files/code/modules/species/station/adherent.dm
new file mode 100644
index 0000000000000..8884960d049c8
--- /dev/null
+++ b/mods/_master_files/code/modules/species/station/adherent.dm
@@ -0,0 +1,4 @@
+/datum/species/adherent/New()
+	LAZYINITLIST(inherent_verbs)
+	inherent_verbs += /mob/living/carbon/human/proc/toggle_emergency_discharge
+	..()
\ No newline at end of file
diff --git a/mods/adherent_discharge/README.md b/mods/adherent_discharge/README.md
new file mode 100644
index 0000000000000..7aa1bf23c2ee0
--- /dev/null
+++ b/mods/adherent_discharge/README.md
@@ -0,0 +1,74 @@
+
+#### Список PRов:
+
+- https://github.com/SierraBay/SierraBay12/pull/1653
+<!--
+  Ссылки на PRы, связанные с модом:
+  - Создание
+  - Большие изменения
+-->
+
+<!-- Название мода. Не важно на русском или на английском. -->
+## Adherent Discharge
+
+ID мода: ADHERENT_DISCHARGE
+<!--
+  Название модпака прописными буквами, СОЕДИНЁННЫМИ_ПОДЧЁРКИВАНИЕМ,
+  которое ты будешь использовать для обозначения файлов.
+-->
+
+### Описание мода
+
+Этот мод служит примером для разработчиков и существует лишь для того,
+чтобы его можно было легко скопировать и вставить в другое место.
+<!--
+  Что он делает, что добавляет: что, куда, зачем и почему - всё здесь.
+  А также любая полезная информация.
+-->
+
+### Изменения *кор кода*
+
+- Отсутствуют
+<!--
+  Если вы редактировали какие-либо процедуры или переменные в кор коде,
+  они должны быть указаны здесь.
+  Нужно указать и файл, и процедуры/переменные.
+
+  Изменений нет - напиши "Отсутствуют"
+-->
+
+### Оверрайды
+
+- `mods/_master_files/code/_onclick/click.dm`: `/mob/living/carbon/human/AltClickOn()`
+- `mods/_master_files/code/modules/species/station/adherent.dm`: `/datum/species/adherent/New()`
+<!--
+  Если ты добавлял новый модульный оверрайд, его нужно указать здесь.
+  Здесь указываются оверрайды в твоём моде и папке `_master_files`
+
+  Изменений нет - напиши "Отсутствуют"
+-->
+
+### Дефайны
+
+- Отсутствуют
+<!--
+  Если требовалось добавить какие-либо дефайны, укажи файлы,
+  в которые ты их добавил, а также перечисли имена.
+  И то же самое, если ты используешь дефайны, определённые другим модом.
+
+  Не используешь - напиши "Отсутствуют"
+-->
+
+### Используемые файлы, не содержащиеся в модпаке
+
+- Отсутствуют
+<!--
+  Будь то немодульный файл или модульный файл, который не содержится в папке,
+  принадлежащей этому конкретному моду, он должен быть упомянут здесь.
+  Хорошими примерами являются иконки или звуки, которые используются одновременно
+  несколькими модулями, или что-либо подобное.
+-->
+
+### Авторы:
+
+Lexanx
diff --git a/mods/adherent_discharge/_adherent_discharge.dm b/mods/adherent_discharge/_adherent_discharge.dm
new file mode 100644
index 0000000000000..ee2718ce2524d
--- /dev/null
+++ b/mods/adherent_discharge/_adherent_discharge.dm
@@ -0,0 +1,4 @@
+/singleton/modpack/adherent_discharge
+	name = "Adherent Discharge"
+	desc = "Добавляет Адхерентам кнопку удара электричеством."
+	author = "Lexanx"
diff --git a/mods/adherent_discharge/_adherent_discharge.dme b/mods/adherent_discharge/_adherent_discharge.dme
new file mode 100644
index 0000000000000..c8a66146a6812
--- /dev/null
+++ b/mods/adherent_discharge/_adherent_discharge.dme
@@ -0,0 +1,6 @@
+#ifndef MODPACK_ADHERENT_DISCHARGE
+#define MODPACK_ADHERENT_DISCHARGE
+
+#include "_adherent_discharge.dm"
+#include "code/adherent.dm"
+#endif
diff --git a/mods/adherent_discharge/code/adherent.dm b/mods/adherent_discharge/code/adherent.dm
new file mode 100644
index 0000000000000..681dec209ae83
--- /dev/null
+++ b/mods/adherent_discharge/code/adherent.dm
@@ -0,0 +1,21 @@
+/obj/item/organ/internal/cell/adherent
+	var/ready_to_charge
+
+
+/mob/living/carbon/human/proc/toggle_emergency_discharge()
+	set category = "Abilities"
+	set name = "Toggle emergency discharge"
+	set desc = "Allows you to overload your piezo capacitors."
+
+	var/mob/living/carbon/human/adherent = src
+	var/obj/item/organ/internal/cell/adherent/adherent_core = adherent.internal_organs_by_name[BP_CELL]
+	if(!adherent_core.ready_to_charge)
+		adherent_core.ready_to_charge = TRUE
+		to_chat(src, SPAN_WARNING("The emergency discharge is ready for use."))
+		to_chat(src, SPAN_GOOD("You are ready to discharge, use alt+click on target to electrocute them."))
+		adherent.visible_message(SPAN_WARNING("You hear silent crackle sounds from [adherent] tentacles"))
+		playsound(loc, 'mods/adherent_discharge/sounds/discharge_on.ogg', 40, 1)
+		return
+
+	adherent_core.ready_to_charge = FALSE
+	to_chat(src, SPAN_WARNING("You have relieved the tension of your tentacles."))
diff --git a/mods/adherent_discharge/sounds/discharge_on.ogg b/mods/adherent_discharge/sounds/discharge_on.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..dcb9e407eb65cbde8fb87b4495e3225ecf816c72
GIT binary patch
literal 15051
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
P=1)5_Riv8`2*LjXo8FD!

literal 0
HcmV?d00001

diff --git a/mods/global_modpacks.dm b/mods/global_modpacks.dm
index 7ae1b7c1fa410..f69275e197813 100644
--- a/mods/global_modpacks.dm
+++ b/mods/global_modpacks.dm
@@ -1,5 +1,6 @@
 // SIERRA TODO: GET RID OF IT!!!
 #include "ai/_ai.dme"
+#include "adherent_discharge/_adherent_discharge.dme"
 #include "body_markings/_body_markings.dme"
 #include "client_verbs/_client_verbs.dme"
 #include "don_loadout/_don_loadout.dme"

From 5761ecd3dad408f8b06d106d7bf6f99f091be2d3 Mon Sep 17 00:00:00 2001
From: UEDCommander <52104104+UEDCommander@users.noreply.github.com>
Date: Thu, 11 Apr 2024 17:36:06 +0300
Subject: [PATCH 2/2] Downstream refactors (#2104)

---
 baystation12.dme                              |   1 +
 code/__defines/dcs/signals/signals_area.dm    |  10 ++
 code/controllers/subsystems/atoms.dm          |  45 +++--
 code/controllers/subsystems/garbage.dm        |   4 +
 code/controllers/subsystems/overlays.dm       | 163 ++++++++++--------
 .../subsystems/processing/icon_updates.dm     |  69 ++++----
 code/game/area/area_power.dm                  |  22 +++
 .../objects/items/devices/radio/intercom.dm   |  68 ++++----
 code/modules/power/apc.dm                     |   6 +-
 9 files changed, 230 insertions(+), 158 deletions(-)
 create mode 100644 code/__defines/dcs/signals/signals_area.dm

diff --git a/baystation12.dme b/baystation12.dme
index f22a037290f3b..f8da9d1219587 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -98,6 +98,7 @@
 #include "code\__defines\zmimic.dm"
 #include "code\__defines\dcs\flags.dm"
 #include "code\__defines\dcs\helpers.dm"
+#include "code\__defines\dcs\signals\signals_area.dm"
 #include "code\__defines\dcs\signals\signals_atom.dm"
 #include "code\__defines\dcs\signals\signals_atom_movable.dm"
 #include "code\__defines\dcs\signals\signals_datum.dm"
diff --git a/code/__defines/dcs/signals/signals_area.dm b/code/__defines/dcs/signals/signals_area.dm
new file mode 100644
index 0000000000000..7e05ef6a0479f
--- /dev/null
+++ b/code/__defines/dcs/signals/signals_area.dm
@@ -0,0 +1,10 @@
+// Main area signals. Format:
+// When the signal is called: (signal arguments)
+// All signals send the source datum of the signal as the first argument
+
+///from base of /area/proc/power_change(): (area/apc_area)
+#define COMSIG_AREA_POWER_CHANGE "area_apc_power_change"
+///from base of /area/proc/set_apc(): (area/apc_area)
+#define COMSIG_AREA_APC_ADDED "area_apc_added"
+///from base of /area/proc/remove_apc(): (area/apc_area)
+#define COMSIG_AREA_APC_REMOVED "area_apc_removed"
diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm
index d7236a00638c9..cc550d2ede5e8 100644
--- a/code/controllers/subsystems/atoms.dm
+++ b/code/controllers/subsystems/atoms.dm
@@ -44,33 +44,32 @@ SUBSYSTEM_DEF(atoms)
 		return
 	atom_init_stage = INITIALIZATION_INNEW_MAPLOAD
 	var/list/mapload_arg = list(TRUE)
-	var/atom/atom
-	var/list/params
 	var/count = 0
 	var/time = Uptime()
-	if (!initialized)
-		for (atom in world)
-			if (!atom || atom.atom_flags & ATOM_FLAG_INITIALIZED)
-				continue
-			InitAtom(atom, mapload_arg)
-			if (++count % 1000)
+	if(!initialized)
+		for(var/atom/atom_to_initialize as anything in world)
+			if(!atom_to_initialize || atom_to_initialize.atom_flags & ATOM_FLAG_INITIALIZED)
 				continue
+			InitAtom(atom_to_initialize, mapload_arg)
+			count++
 			CHECK_TICK
+
 	var/init_queue_length = length(init_queue)
-	if (init_queue_length)
-		for (var/i = 1 to init_queue_length)
-			atom = init_queue[i]
-			if (!atom || atom.atom_flags & ATOM_FLAG_INITIALIZED)
+	if(init_queue_length)
+		for(var/i = 1 to init_queue_length)
+			var/atom/atom_to_initialize = init_queue[i]
+			if (!atom_to_initialize || atom_to_initialize.atom_flags & ATOM_FLAG_INITIALIZED)
 				continue
-			params = init_queue[atom]
+
+			var/list/params = init_queue[atom_to_initialize]
 			if (params)
-				InitAtom(atom, mapload_arg + params)
+				InitAtom(atom_to_initialize, mapload_arg + params)
 			else
-				InitAtom(atom, mapload_arg)
-			if (++count % 500)
-				continue
+				InitAtom(atom_to_initialize, mapload_arg)
+			count++
 			CHECK_TICK
 		init_queue.Cut(1, init_queue_length + 1)
+
 	time = max((Uptime() - time) * 0.1, 0.1)
 	report_progress("Initialized [count] atom\s in [time]s ([floor(count/time)]/s)")
 	atom_init_stage = INITIALIZATION_INNEW_REGULAR
@@ -78,13 +77,13 @@ SUBSYSTEM_DEF(atoms)
 	if (late_queue_length)
 		count = 0
 		time = Uptime()
-		for (var/i = 1 to late_queue_length)
-			atom = late_init_queue[i]
-			if (!atom)
-				continue
-			atom.LateInitialize(arglist(late_init_queue[atom]))
-			if (++count % 250)
+		for(var/i = 1 to late_queue_length)
+			var/atom/atom_to_late_init = late_init_queue[i]
+			if (!atom_to_late_init)
 				continue
+
+			atom_to_late_init.LateInitialize(arglist(late_init_queue[atom_to_late_init]))
+			count++
 			CHECK_TICK
 		late_init_queue.Cut(1, late_queue_length + 1)
 		time = max((Uptime() - time) * 0.1, 0.1)
diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index d8cfe79fe21ce..a0a1bbf954cb0 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -219,9 +219,13 @@ SUBSYSTEM_DEF(garbage)
 	++details.qdels
 	switch (datum.gc_destroyed)
 		if (null)
+			if(SEND_SIGNAL(datum, COMSIG_PREQDELETED)) // Gives any signal listener a chance to prevent atom qdel
+				return
+
 			datum.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
 			var/start_time = world.time
 			var/start_tick = world.tick_usage
+			SEND_SIGNAL(datum, COMSIG_QDELETING) // Leting signal listeners know, that datum is being qdeleted
 			var/hint = datum.Destroy()
 			if (world.time != start_time)
 				++details.slept_destroy
diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm
index 6090afe02c78e..baf3141f9a0b2 100644
--- a/code/controllers/subsystems/overlays.dm
+++ b/code/controllers/subsystems/overlays.dm
@@ -11,21 +11,17 @@ var/global/const/ATOM_ICON_CACHE_ALL = (ATOM_ICON_CACHE_NORMAL | ATOM_ICON_CACHE
 SUBSYSTEM_DEF(overlays)
 	name = "Overlays"
 	flags = SS_TICKER
-	wait = 1 // ticks
+	wait = 1
 	priority = FIRE_PRIORITY_OVERLAYS
 	init_order = SS_INIT_OVERLAYS
-
 	/// The queue of atoms that need under/overlay updates.
-	var/static/list/atom/queue = list()
-
+	VAR_PRIVATE/static/list/atom/queue = list()
 	/// A list([icon] = list([state] = [appearance], ...), ...) cache of appearances.
-	var/static/list/state_cache = list()
-
+	VAR_PRIVATE/static/list/state_cache = list()
 	/// A list([icon] = [appearance], ...) cache of appearances.
-	var/static/list/icon_cache = list()
-
+	VAR_PRIVATE/static/list/icon_cache = list()
 	/// The number of appearances currently cached.
-	var/static/cache_size = 0
+	VAR_PRIVATE/static/cache_size = 0
 
 
 /datum/controller/subsystem/overlays/Recover()
@@ -33,16 +29,15 @@ SUBSYSTEM_DEF(overlays)
 	LIST_RESIZE(state_cache, 0)
 	LIST_RESIZE(icon_cache, 0)
 	cache_size = 0
-	var/count = 0
-	for (var/atom/atom)
-		atom.atom_flags &= ~ATOM_AWAITING_OVERLAY_UPDATE
-		if (++count % 500)
-			continue
+	for(var/atom/atom as anything in world)
+		if(atom.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
+			SSoverlays.queue += atom
+
 		CHECK_TICK
 
 
 /datum/controller/subsystem/overlays/Initialize(start_uptime)
-	fire(FALSE, TRUE)
+	flush_queue()
 
 
 /datum/controller/subsystem/overlays/UpdateStat(time)
@@ -51,73 +46,100 @@ SUBSYSTEM_DEF(overlays)
 	..({"Queued Atoms: [length(queue)], Cache Size: [cache_size]"})
 
 
-/datum/controller/subsystem/overlays/fire(resumed, no_mc_tick)
-	var/queue_length = length(queue)
-	if (queue_length)
-		var/atom/atom
-		for (var/i = 1 to queue_length)
-			atom = queue[i]
-			if (QDELETED(atom))
-				continue
-			if (atom.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
-				atom.UpdateOverlays()
-			if (no_mc_tick)
-				if (i % 1000)
-					continue
-				CHECK_TICK
-			else if (MC_TICK_CHECK)
-				queue.Cut(1, i + 1)
-				return
-		queue.Cut(1, queue_length + 1)
+/datum/controller/subsystem/overlays/fire(resumed)
+	var/queue_position = 1
+	while(length(queue) >= queue_position)
+		var/atom/atom_to_update = queue[queue_position]
+		if(!QDELETED(atom_to_update) && atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
+			atom_to_update.UpdateOverlays()
+
+		queue_position++
+		if(MC_TICK_CHECK)
+			break
+
+	queue.Cut(1, queue_position)
+
+/datum/controller/subsystem/overlays/proc/flush_queue()
+	var/queue_position = 1
+	while(length(queue) >= queue_position)
+		process_atom_overlays_update(queue[queue_position])
+		queue_position++
+		CHECK_TICK
+
+	LIST_RESIZE(queue, 0)
+
+/datum/controller/subsystem/overlays/proc/process_atom_overlays_update(atom/atom_to_update)
+	if(!QDELETED(atom_to_update) && atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
+		atom_to_update.UpdateOverlays()
 
 
 /datum/controller/subsystem/overlays/proc/GetStateAppearance(icon, state)
-	var/list/subcache = state_cache[icon]
-	if (!subcache)
-		subcache = list()
-		state_cache[icon] = subcache
-	if (!subcache[state])
-		var/image/image = image(icon, null, state)
-		subcache[state] = image.appearance
-		++cache_size
-	return subcache[state]
+	var/list/state_to_appearance = state_cache[icon]
+	if(!state_to_appearance)
+		state_to_appearance = list()
+		state_cache[icon] = state_to_appearance
+
+	var/state_appearance = state_to_appearance[state]
+	if(!state_appearance)
+		var/image/state_image = image(icon, null, state)
+		state_appearance = state_image.appearance
+		state_to_appearance[state] = state_appearance
+		cache_size++
+
+	return state_appearance
 
 
 /datum/controller/subsystem/overlays/proc/GetIconAppearance(icon)
-	if (!icon_cache[icon])
-		var/image/image = image(icon)
-		icon_cache[icon] = image.appearance
-		++cache_size
-	return icon_cache[icon]
+	var/icon_appearance = icon_cache[icon]
+	if (!icon_appearance)
+		var/image/icon_image = image(icon)
+		icon_appearance = icon_image.appearance
+		icon_cache[icon] = icon_appearance
+		cache_size++
+
+	return icon_appearance
 
 
-/datum/controller/subsystem/overlays/proc/GetAppearanceList(atom/subject, list/sources)
+/datum/controller/subsystem/overlays/proc/getAppearanceList(atom/subject, list/sources)
 	if (!sources)
 		return list()
+
 	if (!islist(sources))
 		sources = list(sources)
+
 	var/list/result = list()
-	var/icon/icon = subject.icon
-	var/atom/entry
-	for (var/i = 1 to length(sources))
-		entry = sources[i]
-		if (!entry)
+	for (var/atom/source as anything in sources)
+		if(!source)
 			continue
-		else if (istext(entry))
-			result += GetStateAppearance(icon, entry)
-		else if (isicon(entry))
-			result += GetIconAppearance(entry)
+
+		if(istext(source))
+			result += GetStateAppearance(subject.icon, source)
+
+		else if(isicon(source))
+			result += GetIconAppearance(source)
+
 		else
-			if (isloc(entry))
-				if (entry.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
-					entry.UpdateOverlays()
-			if (!ispath(entry))
-				result += entry.appearance
+			if(isatom(source) && source.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
+				source.UpdateOverlays()
+
+			if(!ispath(source))
+				result += source.appearance
 			else
-				var/image/image = entry
+				var/image/image = source
 				result += image.appearance
+
 	return result
 
+/datum/controller/subsystem/overlays/proc/enque_atom_overlay_update(atom/atom_to_update)
+	if(!atom_to_update)
+		return
+
+	if(atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
+		return
+
+	atom_to_update.atom_flags |= ATOM_AWAITING_OVERLAY_UPDATE
+	SSoverlays.queue += atom_to_update
+
 
 /// Immediately runs an overlay update.
 /atom/proc/ImmediateOverlayUpdate()
@@ -147,11 +169,7 @@ SUBSYSTEM_DEF(overlays)
 /// Enqueues the atom for an overlay update if not already queued
 /atom/proc/QueueOverlayUpdate()
 	SHOULD_NOT_OVERRIDE(TRUE)
-	if (atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
-		return
-	atom_flags |= ATOM_AWAITING_OVERLAY_UPDATE
-	SSoverlays.queue += src
-
+	SSoverlays.enque_atom_overlay_update(src)
 
 /// Builds the atom's overlay state from caches
 /atom/proc/UpdateOverlays()
@@ -160,6 +178,7 @@ SUBSYSTEM_DEF(overlays)
 	if (QDELING(src))
 		LIST_RESIZE(overlays, 0)
 		return
+
 	if (length(atom_protected_overlay_cache))
 		if (length(atom_overlay_cache))
 			overlays = atom_protected_overlay_cache + atom_overlay_cache
@@ -203,7 +222,7 @@ SUBSYSTEM_DEF(overlays)
 	SHOULD_NOT_OVERRIDE(TRUE)
 	if (!sources)
 		return
-	sources = SSoverlays.GetAppearanceList(src, sources)
+	sources = SSoverlays.getAppearanceList(src, sources)
 	if (!length(sources))
 		return
 	if (cache_target & ATOM_ICON_CACHE_PROTECTED)
@@ -228,9 +247,11 @@ SUBSYSTEM_DEF(overlays)
 	SHOULD_NOT_OVERRIDE(TRUE)
 	if (!sources)
 		return
-	sources = SSoverlays.GetAppearanceList(src, sources)
+
+	sources = SSoverlays.getAppearanceList(src, sources)
 	if (!length(sources))
 		return
+
 	var/update
 	if (cache_target & ATOM_ICON_CACHE_PROTECTED)
 		var/outcome = CutCacheBehavior(sources, atom_protected_overlay_cache)
@@ -238,12 +259,14 @@ SUBSYSTEM_DEF(overlays)
 			update = TRUE
 			if (outcome == TRUE)
 				atom_protected_overlay_cache = null
+
 	if (cache_target & ATOM_ICON_CACHE_NORMAL)
 		var/outcome = CutCacheBehavior(sources, atom_overlay_cache)
 		if (!isnull(outcome))
 			update = TRUE
 			if (outcome == TRUE)
 				atom_overlay_cache = null
+
 	if (update)
 		QueueOverlayUpdate()
 
diff --git a/code/controllers/subsystems/processing/icon_updates.dm b/code/controllers/subsystems/processing/icon_updates.dm
index 1d2c918118104..5ce611a23d7f2 100644
--- a/code/controllers/subsystems/processing/icon_updates.dm
+++ b/code/controllers/subsystems/processing/icon_updates.dm
@@ -4,7 +4,7 @@ SUBSYSTEM_DEF(icon_update)
 	flags = SS_TICKER
 	priority = FIRE_PRIORITY_ICON_UPDATE
 	init_order = SS_INIT_ICON_UPDATE
-	var/static/list/queue = list()
+	VAR_PRIVATE/static/list/queue = list()
 
 
 /datum/controller/subsystem/icon_update/Recover()
@@ -19,44 +19,47 @@ SUBSYSTEM_DEF(icon_update)
 
 
 /datum/controller/subsystem/icon_update/Initialize(start_uptime)
-	fire(FALSE, TRUE)
-
-
-/datum/controller/subsystem/icon_update/fire(resumed, no_mc_tick)
-	var/atom/atom
-	var/list/params
-	var/queue_length = length(queue)
-	for (var/i = 1 to queue_length)
-		atom = queue[i]
-		if (QDELETED(atom))
-			continue
-		params = queue[atom]
-		if (islist(params))
-			atom.update_icon(arglist(params))
-		else
-			atom.update_icon()
-		if (no_mc_tick)
-			if (i % 100)
-				continue
-			CHECK_TICK
-		else if (MC_TICK_CHECK)
-			queue.Cut(1, i + 1)
-			return
-	if (queue_length)
-		queue.Cut(1, queue_length + 1)
-	suspend()
+	flush_queue()
 
+/datum/controller/subsystem/icon_update/fire(resumed)
+	var/queue_position = 1
+	while(length(queue) >= queue_position)
+		process_atom_icon_update(queue[queue_position])
+		queue_position++
+		if(MC_TICK_CHECK)
+			break
+
+	queue.Cut(1, queue_position)
+
+/datum/controller/subsystem/icon_update/proc/flush_queue()
+	var/queue_position = 1
+	while(length(queue) >= queue_position)
+		process_atom_icon_update(queue[queue_position])
+		queue_position++
+		CHECK_TICK
+
+	LIST_RESIZE(queue, 0)
+
+/datum/controller/subsystem/icon_update/proc/process_atom_icon_update(atom/atom_to_update)
+	if(QDELETED(atom_to_update))
+		return
+
+	var/list/params = queue[atom_to_update]
+	if (islist(params))
+		atom_to_update.update_icon(arglist(params))
+	else
+		atom_to_update.update_icon()
+
+/datum/controller/subsystem/icon_update/proc/enque_atom_icon_update(atom/atom_to_update, arguments)
+	SSicon_update.queue[atom_to_update] = arguments
 
 /**
  * Adds the atom to the icon_update subsystem to be queued for icon updates. Use this if you're going to be pushing a
  * lot of icon updates at once.
  */
 /atom/proc/queue_icon_update(...)
-	SSicon_update.queue[src] = length(args) ? args : TRUE
-	if (SSicon_update.suspended)
-		SSicon_update.wake()
-
+	SSicon_update.enque_atom_icon_update(src, length(args) ? args : TRUE)
 
-/hook/game_ready/proc/FlushIconUpdateQueue()
-	SSicon_update.fire(FALSE, TRUE)
+/hook/game_ready/proc/flush_icon_update_queue()
+	SSicon_update.flush_queue()
 	return TRUE
diff --git a/code/game/area/area_power.dm b/code/game/area/area_power.dm
index 963a86903be97..f67f32b2b282e 100644
--- a/code/game/area/area_power.dm
+++ b/code/game/area/area_power.dm
@@ -28,9 +28,31 @@
 /area/proc/power_change()
 	for(var/obj/machinery/M as anything in machinery_list)	// for each machine in the area
 		M.power_change()			// reverify power status (to update icons etc.)
+	SEND_SIGNAL(src, COMSIG_AREA_POWER_CHANGE)
 	if (fire || eject || party)
 		update_icon()
 
+/// Sets the apc in area. Sends COMSIG_AREA_APC_ADDED signal
+/area/proc/set_apc(obj/machinery/power/apc/new_apc)
+	if(!istype(new_apc))
+		CRASH("Invalid apc passed [log_info_line(new_apc)]")
+
+	if(apc)
+		stack_trace("Apc set in area when old one is still present")
+		remove_apc()
+
+	apc = new_apc
+	SEND_SIGNAL(src, COMSIG_AREA_APC_ADDED, new_apc)
+
+/// Removes current apc from area, if present. Sends COMSIG_AREA_APC_REMOVED signal
+/area/proc/remove_apc()
+	if(!apc)
+		return
+
+	SEND_SIGNAL(src, COMSIG_AREA_APC_REMOVED, apc)
+	apc = null
+
+
 /// Returns Integer. The total amount of power usage queued for the area from both `used_*` and `oneoff_*` for the given power channel, or all channels if `TOTAL` is passed instead.
 /area/proc/usage(chan)
 	switch(chan)
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index d2e549fb6405e..ccbb2f4ac2d85 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -15,7 +15,7 @@
 	///2 = wired/built, 1 = circuit installed, 0 = frame
 	var/buildstage = 2
 	var/number = 0
-	var/last_tick //used to delay the powercheck
+	var/area/linked_area
 	intercom_handling = TRUE
 
 /obj/item/device/radio/intercom/get_storage_cost()
@@ -93,7 +93,7 @@
 
 /obj/item/device/radio/intercom/Initialize(loc, dir, atom/frame)
 	. = ..()
-	START_PROCESSING(SSobj, src)
+	find_and_set_linked_area()
 
 	if (dir)
 		set_dir(dir)
@@ -148,10 +148,6 @@
 	. = ..()
 	internal_channels[num2text(RAID_FREQ)] = list(access_syndicate)
 
-/obj/item/device/radio/intercom/Destroy()
-	STOP_PROCESSING(SSobj, src)
-	return ..()
-
 /obj/item/device/radio/intercom/attack_ai(mob/user)
 	add_fingerprint(user)
 	if (buildstage == 2)
@@ -322,26 +318,6 @@
 	.["Wirecutters"] += "<p>Used for deconstruction. See deconstruction steps.</p>"
 	.["Wrench"] += "<p>Used for deconstruction. See deconstruction steps.</p>"
 
-/obj/item/device/radio/intercom/Process()
-	if (wiresexposed)
-		on = FALSE
-		return
-	if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0))
-		last_tick = world.timeofday
-		var/old_on = on
-
-		if(!src.loc)
-			on = FALSE
-		else
-			var/area/A = get_area(src)
-			if(!A)
-				on = FALSE
-			else
-				on = A.powered(EQUIP) // set "on" to the power status
-
-		if (on != old_on)
-			update_icon()
-
 /obj/item/device/radio/intercom/on_update_icon()
 	if (buildstage == 2 && wiresexposed)
 		icon_state = "intercom-b2"
@@ -349,10 +325,11 @@
 		icon_state = "intercom-b1"
 	else if (buildstage == 0)
 		icon_state = "intercom-f"
-	else if (!on)
-		icon_state = "intercom-p"
 	else
-		icon_state = "intercom_[broadcasting][listening]"
+		if(on)
+			icon_state = "intercom_[broadcasting][listening]"
+		else
+			icon_state = "intercom-p"
 
 /obj/item/device/radio/intercom/ToggleBroadcast()
 	..()
@@ -362,6 +339,39 @@
 	..()
 	update_icon()
 
+/obj/item/device/radio/intercom/proc/find_and_set_linked_area()
+	var/area/target_area = get_area(src)
+	if(!target_area.apc)
+		RegisterSignal(target_area, COMSIG_AREA_APC_ADDED, PROC_REF(on_apc_add))
+		return
+
+	on_apc_add(target_area)
+
+/obj/item/device/radio/intercom/proc/on_apc_add(area/apc_area)
+	SIGNAL_HANDLER
+
+	UnregisterSignal(apc_area, COMSIG_AREA_APC_ADDED)
+	linked_area = apc_area
+	RegisterSignal(apc_area, COMSIG_AREA_APC_REMOVED, PROC_REF(on_apc_removal))
+	RegisterSignal(apc_area, COMSIG_AREA_POWER_CHANGE, PROC_REF(change_status))
+
+/obj/item/device/radio/intercom/proc/on_apc_removal(area/apc_area)
+	SIGNAL_HANDLER
+
+	UnregisterSignal(apc_area, COMSIG_AREA_APC_REMOVED)
+	UnregisterSignal(apc_area, COMSIG_AREA_POWER_CHANGE)
+	linked_area = null
+	on = FALSE
+	update_icon()
+
+	RegisterSignal(apc_area, COMSIG_AREA_APC_ADDED, PROC_REF(on_apc_add))
+
+/obj/item/device/radio/intercom/proc/change_status()
+	SIGNAL_HANDLER
+
+	on = linked_area.powered(EQUIP)
+	update_icon()
+
 /obj/item/device/radio/intercom/broadcasting
 	broadcasting = 1
 
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 649e52794e871..01c6ea536ad95 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -176,7 +176,7 @@
 		area = A
 	if(autoname)
 		SetName("\improper [area.name] APC")
-	area.apc = src
+	area.set_apc(src)
 
 	. = ..()
 
@@ -193,8 +193,8 @@
 	power_change()
 
 /obj/machinery/power/apc/Destroy()
-	src.update()
-	area.apc = null
+	update()
+	area.remove_apc()
 	area.power_light = 0
 	area.power_equip = 0
 	area.power_environ = 0