diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index d2c712d32ea..03fb57dea26 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -40,6 +40,7 @@
var/lights = FALSE
var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference
var/completely_disabled = FALSE //stops the mech from doing anything
+ var/frozen = FALSE // admin frozen
var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it.
//inner atmos
@@ -565,7 +566,7 @@
/obj/mecha/relaymove(mob/living/user, direction)
if(completely_disabled)
return
- if(!direction)
+ if(!direction || frozen)
return
if(user != occupant) //While not "realistic", this piece is player friendly.
user.forceMove(get_turf(src))
@@ -884,6 +885,9 @@
. = t_air.return_temperature()
/obj/mecha/MouseDrop_T(mob/M, mob/user)
+ if(frozen)
+ to_chat(user, "Do not enter Admin-Frozen mechs.")
+ return TRUE
if((user != M) || user.incapacitated() || !Adjacent(user))
return
if(!ishuman(user)) // no silicons or drones in mechas.
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index f5f28c60c80..6182101d9b4 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -46,6 +46,12 @@
icon_state = "shieldsparkles"
anchored = TRUE
+/obj/effect/overlay/adminoverlay
+ name = "adminoverlay"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "admin"
+ layer = 4.1
+
/obj/effect/overlay/vis
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 929cf33f331..4df079e3749 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -79,6 +79,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/overmap_datum_token_manager,
/datum/admins/proc/open_borgopanel,
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
+ /client/proc/freeze,
)
GLOBAL_LIST_INIT(admin_verbs_ban, list(
diff --git a/code/modules/admin/verbs/freeze.dm b/code/modules/admin/verbs/freeze.dm
new file mode 100644
index 00000000000..494d0f575e8
--- /dev/null
+++ b/code/modules/admin/verbs/freeze.dm
@@ -0,0 +1,94 @@
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//////Freeze Mob/Mech Verb -- Ported from NSS Pheonix (Unbound Travels)/////////
+////////////////////////////////////////////////////////////////////////////////
+//////Allows admin's to right click on any mob/mech and freeze them in place.///
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+GLOBAL_LIST_EMPTY(frozen_atom_list) // A list of admin-frozen atoms.
+
+/client/proc/freeze(atom/movable/M)
+ set name = "\[Admin\] Freeze"
+ set category = null
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ M.admin_Freeze(src)
+
+/// Created here as a base proc. Override as needed for any type of object or mob you want able to be frozen.
+/atom/movable/proc/admin_Freeze(client/admin)
+ to_chat(admin, "Freeze is not able to be called on this type of object.You have been [frozen ? "frozen" : "unfrozen"] by [admin]")
+ message_admins("[key_name_admin(admin)] [frozen ? "froze" : "unfroze"] [key_name_admin(src)] [mech ? "in a [mech]" : ""]")
+ log_admin("[key_name(admin)] [frozen ? "froze" : "unfroze"] [key_name(src)] [mech ? "in a [mech]" : ""]")
+ update_icons()
+
+ return frozen
+
+
+/mob/living/simple_animal/slime/admin_Freeze(admin)
+ if(..()) // The result of the parent call here will be the value of the mob's `frozen` variable after they get (un)frozen.
+ adjustHealth(1000) //arbitrary large value
+ else
+ revive()
+
+/mob/living/simple_animal/var/admin_prev_health = null
+
+/mob/living/simple_animal/admin_Freeze(admin)
+ if(..()) // The result of the parent call here will be the value of the mob's `frozen` variable after they get (un)frozen.
+ admin_prev_health = health
+ health = 0
+ else
+ revive()
+ overlays.Cut()
+
+//////////////////////////Freeze Mech
+
+/obj/mecha/admin_Freeze(client/admin)
+ var/obj/effect/overlay/adminoverlay/freeze_overlay = new
+ if(!frozen)
+ GLOB.frozen_atom_list += src
+ frozen = TRUE
+ overlays += freeze_overlay
+ else
+ GLOB.frozen_atom_list -= src
+ frozen = FALSE
+ overlays -= freeze_overlay
+
+ if(occupant)
+ occupant.admin_Freeze(admin, mech = name) // We also want to freeze the driver of the mech.
+ else
+ message_admins("[key_name_admin(admin)] [frozen ? "froze" : "unfroze"] an empty [name]")
+ log_admin("[key_name(admin)] [frozen ? "froze" : "unfroze"] an empty [name]")
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 734ffac0859..d86ff2adb5a 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -43,6 +43,11 @@
/// Flags that determine the potential of a mob to perform certain actions. Do not change this directly.
var/mobility_flags = MOBILITY_FLAGS_DEFAULT
+ /// Used for preventing attacks on admin-frozen mobs.
+ var/frozen = null
+ /// Used for keeping track of previous sleeping value with admin freeze.
+ var/admin_prev_sleeping = 0
+
var/resting = FALSE
/// Variable to track the body position of a mob, regardgless of the actual angle of rotation (usually matching it, but not necessarily).
diff --git a/shiptest.dme b/shiptest.dme
index e933dfe020c..661720a7dfd 100644
--- a/shiptest.dme
+++ b/shiptest.dme
@@ -1513,6 +1513,7 @@
#include "code\modules\admin\verbs\fax_manager.dm"
#include "code\modules\admin\verbs\fix_air.dm"
#include "code\modules\admin\verbs\fps.dm"
+#include "code\modules\admin\verbs\freeze.dm"
#include "code\modules\admin\verbs\getlogs.dm"
#include "code\modules\admin\verbs\individual_logging.dm"
#include "code\modules\admin\verbs\machine_upgrade.dm"