diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index f619e9aa9bd..3e3e1696e61 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -57,6 +57,9 @@
W.plane = initial(W.plane)
W.loc = affected_mob.loc
W.dropped(affected_mob)
+ if(isobj(affected_mob.loc))
+ var/obj/O = affected_mob.loc
+ O.force_eject_occupant()
var/mob/living/new_mob = new new_form(affected_mob.loc)
if(istype(new_mob))
new_mob.a_intent = "harm"
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index fb0ccff32cb..d887153c6d5 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -282,6 +282,9 @@
occupant = null
icon_state = "scanner_open"
+/obj/machinery/dna_scannernew/force_eject_occupant()
+ go_out(null, TRUE)
+
/obj/machinery/dna_scannernew/ex_act(severity)
if(occupant)
occupant.ex_act(severity)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index e4d0befa61e..7c5a03e29e6 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -411,6 +411,9 @@
for(var/atom/movable/A in contents - component_parts - list(beaker))
A.forceMove(loc)
+/obj/machinery/sleeper/force_eject_occupant()
+ go_out()
+
/obj/machinery/sleeper/proc/inject_chemical(mob/living/user as mob, chemical, amount)
if(!(chemical in possible_chems))
to_chat(user, "The sleeper does not offer that chemical!")
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 1ee30b6e9d0..3fa78dd02e6 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -172,6 +172,9 @@
for(var/atom/movable/A in contents - component_parts)
A.forceMove(loc)
+/obj/machinery/bodyscanner/force_eject_occupant()
+ go_out()
+
/obj/machinery/bodyscanner/ex_act(severity)
if(occupant)
occupant.ex_act(severity)
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 4213ff517bf..8be09ef30b7 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -443,6 +443,9 @@
for(var/atom/movable/A in contents - component_parts - list(beaker))
A.forceMove(get_step(loc, SOUTH))
+/obj/machinery/atmospherics/unary/cryo_cell/force_eject_occupant()
+ go_out()
+
/// Called when either the occupant is dead and the AUTO_EJECT_DEAD flag is present, OR the occupant is alive, has no external damage, and the AUTO_EJECT_HEALTHY flag is present.
/obj/machinery/atmospherics/unary/cryo_cell/proc/auto_eject(eject_flag)
on = FALSE
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 2e0c4c54375..fecd006886e 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -769,9 +769,13 @@
return ..()
+
/proc/cryo_ssd(var/mob/living/carbon/person_to_cryo)
if(istype(person_to_cryo.loc, /obj/machinery/cryopod))
return 0
+ if(isobj(person_to_cryo.loc))
+ var/obj/O = person_to_cryo.loc
+ O.force_eject_occupant()
var/list/free_cryopods = list()
for(var/obj/machinery/cryopod/P in GLOB.machines)
if(!P.occupant && istype(get_area(P), /area/crew_quarters/sleep))
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index da4df4f8382..cd6b33d0a95 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -740,10 +740,11 @@
if(!occupant)
return
- if(user != occupant)
- to_chat(occupant, "The machine kicks you out!")
- if(user.loc != loc)
- to_chat(occupant, "You leave the not-so-cozy confines of the SSU.")
+ if(user)
+ if(user != occupant)
+ to_chat(occupant, "The machine kicks you out!")
+ if(user.loc != loc)
+ to_chat(occupant, "You leave the not-so-cozy confines of [src].")
occupant.forceMove(loc)
occupant = null
if(!state_open)
@@ -751,6 +752,8 @@
update_icon()
return
+/obj/machinery/suit_storage_unit/force_eject_occupant()
+ eject_occupant()
/obj/machinery/suit_storage_unit/verb/get_out()
set name = "Eject Suit Storage Unit"
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 540e1074844..69f70207452 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -1273,6 +1273,9 @@
L.client.RemoveViewMod("mecha")
zoom_mode = FALSE
+/obj/mecha/force_eject_occupant()
+ go_out()
+
/////////////////////////
////// Access stuff /////
/////////////////////////
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index d40c628ed90..7a56c53f73a 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -351,3 +351,9 @@ a {
/obj/proc/check_uplink_validity()
return TRUE
+
+/obj/proc/force_eject_occupant()
+ // This proc handles safely removing occupant mobs from the object if they must be teleported out (due to being SSD/AFK, by admin teleport, etc) or transformed.
+ // In the event that the object doesn't have an overriden version of this proc to do it, log a runtime so one can be added.
+ CRASH("Proc force_eject_occupant() is not overriden on a machine containing a mob.")
+
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 04373502832..6db1846e872 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -354,6 +354,11 @@
/obj/structure/closet/AllowDrop()
return TRUE
+/obj/structure/closet/force_eject_occupant()
+ // Its okay to silently teleport mobs out of lockers, since the only thing affected is their contents list.
+ return
+
+
/obj/structure/closet/bluespace
name = "bluespace closet"
desc = "A storage unit that moves and stores through the fourth dimension."
diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm
index 0c1a8c5f14f..ca83b5bad08 100644
--- a/code/modules/admin/verbs/adminjump.dm
+++ b/code/modules/admin/verbs/adminjump.dm
@@ -22,6 +22,10 @@
to_chat(src, "Nowhere to jump to!")
return
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
+
admin_forcemove(usr, T)
log_admin("[key_name(usr)] jumped to [A]")
if(!isobserver(usr))
@@ -35,6 +39,9 @@
if(!check_rights(R_ADMIN))
return
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
log_admin("[key_name(usr)] jumped to [T.x], [T.y], [T.z] in [T.loc]")
if(!isobserver(usr))
message_admins("[key_name_admin(usr)] jumped to [T.x], [T.y], [T.z] in [T.loc]", 1)
@@ -52,6 +59,9 @@
log_admin("[key_name(usr)] jumped to [key_name(M)]")
if(!isobserver(usr))
message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]", 1)
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
if(src.mob)
var/mob/A = src.mob
var/turf/T = get_turf(M)
@@ -70,6 +80,9 @@
var/turf/T = locate(tx, ty, tz)
if(T)
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
admin_forcemove(usr, T)
if(isobserver(usr))
var/mob/dead/observer/O = usr
@@ -96,7 +109,9 @@
log_admin("[key_name(usr)] jumped to [key_name(M)]")
if(!isobserver(usr))
message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]", 1)
-
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
admin_forcemove(usr, M.loc)
feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -111,6 +126,10 @@
log_admin("[key_name(usr)] teleported [key_name(M)]")
message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)]", 1)
+
+ if(isobj(M.loc))
+ var/obj/O = M.loc
+ O.force_eject_occupant()
admin_forcemove(M, get_turf(usr))
feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -135,6 +154,9 @@
log_admin("[key_name(usr)] teleported [key_name(M)]")
message_admins("[key_name_admin(usr)] teleported [key_name(M)]", 1)
if(M)
+ if(isobj(M.loc))
+ var/obj/O = M.loc
+ O.force_eject_occupant()
admin_forcemove(M, get_turf(usr))
admin_forcemove(usr, M.loc)
feedback_add_details("admin_verb","GK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -148,6 +170,9 @@
var/area/A = input(usr, "Pick an area.", "Pick an area") in return_sorted_areas()
if(A)
+ if(isobj(M.loc))
+ var/obj/O = M.loc
+ O.force_eject_occupant()
admin_forcemove(M, pick(get_area_turfs(A)))
feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] teleported [key_name(M)] to [A]")
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 43db66cabc5..03b9dfb60e7 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -917,6 +917,9 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
if(istype(landmark))
var/datum/map_template/ruin/template = landmark.ruin_template
+ if(isobj(usr.loc))
+ var/obj/O = usr.loc
+ O.force_eject_occupant()
admin_forcemove(usr, get_turf(landmark))
to_chat(usr, "[template.name]")