diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 585f6c5365f..f10dc5d3334 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -1058,3 +1058,6 @@
// Sent when a mob spawner is attacked directly or via projectile.
#define COMSIG_SPAWNER_SET_TARGET "spawner_set_target"
+
+/// Used by admin-tooling to remove radiation
+#define COMSIG_ADMIN_DECONTAMINATE "admin_decontaminate"
diff --git a/code/controllers/subsystem/SSradiation.dm b/code/controllers/subsystem/SSradiation.dm
index 540e56ce19a..c30f40a1363 100644
--- a/code/controllers/subsystem/SSradiation.dm
+++ b/code/controllers/subsystem/SSradiation.dm
@@ -13,6 +13,8 @@ PROCESSING_SUBSYSTEM_DEF(radiation)
var/rad_cache_update_interval = 5 SECONDS
var/list/turf_rad_cache = list()
var/list/prev_rad_cache = list()
+ /// Lazy list of all radioactive components
+ var/list/all_radiations
/datum/controller/subsystem/processing/radiation/proc/warn(datum/component/radioactive/contamination)
diff --git a/code/datums/components/radioactive.dm b/code/datums/components/radioactive.dm
index 97d0591c4eb..ba240898e34 100644
--- a/code/datums/components/radioactive.dm
+++ b/code/datums/components/radioactive.dm
@@ -13,17 +13,17 @@
var/can_contaminate
/datum/component/radioactive/Initialize(_strength = 0, _source, _half_life = RAD_HALF_LIFE, _can_contaminate = TRUE)
+ if(!istype(parent, /atom))
+ return COMPONENT_INCOMPATIBLE
strength = _strength
source = _source
hl3_release_date = _half_life
can_contaminate = _can_contaminate
- if(istype(parent, /atom))
- RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(rad_examine))
- if(isitem(parent))
- RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(rad_attack))
- RegisterSignal(parent, COMSIG_ITEM_ATTACK_OBJ, PROC_REF(rad_attack))
- else
- return COMPONENT_INCOMPATIBLE
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(rad_examine))
+ RegisterSignal(parent, COMSIG_ADMIN_DECONTAMINATE, PROC_REF(admin_decontaminate))
+ if(isitem(parent))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(rad_attack))
+ RegisterSignal(parent, COMSIG_ITEM_ATTACK_OBJ, PROC_REF(rad_attack))
if(strength > RAD_MINIMUM_CONTAMINATION)
SSradiation.warn(src)
//Let's make er glow
@@ -31,10 +31,12 @@
var/atom/movable/master = parent
master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
addtimer(CALLBACK(src, PROC_REF(glow_loop), master), rand(1, 19)) //Things should look uneven
+ LAZYADD(SSradiation.all_radiations, src)
START_PROCESSING(SSradiation, src)
/datum/component/radioactive/Destroy()
STOP_PROCESSING(SSradiation, src)
+ LAZYREMOVE(SSradiation.all_radiations, src)
var/atom/movable/master = parent
master.remove_filter("rad_glow")
return ..()
@@ -99,6 +101,17 @@
return
strength -= strength / hl3_release_date
+/datum/component/radioactive/proc/admin_decontaminate()
+ SIGNAL_HANDLER
+ . = TRUE
+ if(ismob(parent))
+ var/mob/M = parent
+ M.radiation = 0
+ if(ismob(source))
+ var/mob/M = source
+ M.radiation = 0
+ qdel(src)
+
#undef RAD_AMOUNT_LOW
#undef RAD_AMOUNT_MEDIUM
#undef RAD_AMOUNT_HIGH
diff --git a/code/defines/procs/admin_keyname_procs.dm b/code/defines/procs/admin_keyname_procs.dm
index 255b89dd7f8..166540f7b13 100644
--- a/code/defines/procs/admin_keyname_procs.dm
+++ b/code/defines/procs/admin_keyname_procs.dm
@@ -90,3 +90,7 @@
/proc/log_and_message_admins(message)
log_admin("[key_name(usr)] " + message)
message_admins("[key_name_admin(usr)] " + message)
+
+/proc/log_and_message_admins_no_usr(message)
+ log_admin(message)
+ message_admins(message)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 6e3753a705c..47529556d96 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -989,3 +989,24 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
vis.set_content(ui_dat.Join(""))
vis.open(FALSE)
+
+/client/proc/cmd_clean_radiation()
+ set name = "Remove All Radiation"
+ set desc = "Remove all radiation in the world."
+ set category = "Debug"
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ if(alert(src, "Are you sure you want to remove all radiation in the world? This may lag the server. Alternatively, use the radiation cleaning buildmode.", "Lag warning", "Yes, I'm sure", "No, I want to live") != "Yes, I'm sure")
+ return
+
+ log_and_message_admins("is decontaminating the world of all radiation. (This may be laggy!)")
+
+ var/counter = 0
+ for(var/datum/component/radioactive/rad as anything in SSradiation.all_radiations)
+ rad.admin_decontaminate()
+ counter++
+ CHECK_TICK
+
+ log_and_message_admins_no_usr("The world has been decontaminated of [counter] radiation components.")
diff --git a/code/modules/admin/verbs/toggledebugverbs.dm b/code/modules/admin/verbs/toggledebugverbs.dm
index 74d8358640c..120a69b924b 100644
--- a/code/modules/admin/verbs/toggledebugverbs.dm
+++ b/code/modules/admin/verbs/toggledebugverbs.dm
@@ -16,6 +16,7 @@ GLOBAL_LIST_INIT(admin_verbs_show_debug_verbs, list(
/client/proc/forceEvent,
/client/proc/admin_redo_space_transitions,
/client/proc/make_turf_space_map,
+ /client/proc/cmd_clean_radiation,
))
// Would be nice to make this a permanent admin pref so we don't need to click it each time
diff --git a/code/modules/buildmode/submodes/antirad_mode.dm b/code/modules/buildmode/submodes/antirad_mode.dm
new file mode 100644
index 00000000000..1ddd9964bb0
--- /dev/null
+++ b/code/modules/buildmode/submodes/antirad_mode.dm
@@ -0,0 +1,55 @@
+/datum/buildmode_mode/clean_radiation
+ key = "rad"
+
+/datum/buildmode_mode/clean_radiation/show_help(mob/user)
+ var/list/messages = list(
+ "***********************************************************",
+ "Left Mouse Button on obj/turf/mob = Remove radiation of selected target.",
+ "Ctrl-Left Mouse Button on screen = Remove all radiation in your sight.",
+ "Right Mouse Button on obj/turf/mob = Deep clean: Remove radiation of all recursive contents of turf.",
+ "Ctrl-Right Mouse Button on screen = Deep clean: Remove radiation of all recursive contents in your sight.",
+ "***********************************************************"
+ )
+ to_chat(user, messages.Join("
"))
+
+/datum/buildmode_mode/clean_radiation/handle_click(mob/user, params, atom/target)
+ var/list/pa = params2list(params)
+ var/deep_clean = pa.Find("right")
+ var/clean_screen = pa.Find("ctrl")
+
+ if(!clean_screen)
+ if(!deep_clean)
+ if(SEND_SIGNAL(target, COMSIG_ADMIN_DECONTAMINATE))
+ to_chat(user, "Decontaminated [target].")
+ log_admin("Build Mode: [key_name(user)] decontaminated radiation at ([target.x],[target.y],[target.z])")
+ return
+
+ var/counter = 0
+ var/turf/T = get_turf(target)
+ counter += SEND_SIGNAL(T, COMSIG_ADMIN_DECONTAMINATE)
+ for(var/atom/movable/cleanable in T)
+ counter += SEND_SIGNAL(cleanable, COMSIG_ADMIN_DECONTAMINATE)
+ CHECK_TICK
+
+ if(isliving(cleanable))
+ var/mob/living/L = cleanable
+ for(var/atom/movable/cleanable2 in L.get_contents())
+ counter += SEND_SIGNAL(cleanable2, COMSIG_ADMIN_DECONTAMINATE)
+ CHECK_TICK
+ to_chat(user, "Decontaminated [counter] atom\s.")
+ log_admin("Build Mode: [key_name(user)] deep-clean decontaminated radiation at ([target.x],[target.y],[target.z])")
+ return
+
+ var/counter = 0
+ for(var/turf/T in range(user.client.view, user))
+ counter += SEND_SIGNAL(T, COMSIG_ADMIN_DECONTAMINATE)
+ for(var/atom/movable/cleanable in T)
+ counter += SEND_SIGNAL(cleanable, COMSIG_ADMIN_DECONTAMINATE)
+ CHECK_TICK
+ if(deep_clean && isliving(cleanable))
+ var/mob/living/L = cleanable
+ for(var/atom/movable/cleanable2 in L.get_contents())
+ counter += SEND_SIGNAL(cleanable2, COMSIG_ADMIN_DECONTAMINATE)
+ CHECK_TICK
+ to_chat(user, "Decontaminated [counter] atom\s.")
+ log_admin("Build Mode: [key_name(user)] [deep_clean ? "deep-clean " : ""]decontaminated their screen of radiation at ([target.x],[target.y],[target.z])")
diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi
index 0520a9ef005..663d4546caf 100644
Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 912489efe04..bdac76b5105 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1598,6 +1598,7 @@
#include "code\modules\buildmode\buildmode_hud.dm"
#include "code\modules\buildmode\effects\line.dm"
#include "code\modules\buildmode\submodes\advanced.dm"
+#include "code\modules\buildmode\submodes\antirad_mode.dm"
#include "code\modules\buildmode\submodes\area_edit.dm"
#include "code\modules\buildmode\submodes\atmos.dm"
#include "code\modules\buildmode\submodes\basic.dm"