diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm
index 2895b3211fd3..32a292d0d8cc 100644
--- a/code/__DEFINES/mode.dm
+++ b/code/__DEFINES/mode.dm
@@ -70,6 +70,7 @@
#define MODE_LZ_PROTECTION (1<<7) /// Prevents the LZ from being mortared
#define MODE_SHIPSIDE_SD (1<<8) /// Toggles whether Predators can big SD when not on the groundmap
#define MODE_HARDCORE_PERMA (1<<9) /// Toggles Hardcore for all marines, meaning they instantly perma upon death
+#define MODE_DISPOSABLE_MOBS (1<<10) // Toggles if mobs fit in disposals or not. Off by default.
#define ROUNDSTATUS_FOG_DOWN 1
#define ROUNDSTATUS_PODDOORS_OPEN 2
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index ef539b8459c7..4936609d892e 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -415,6 +415,7 @@ DEFINE_BITFIELD(toggleable_flags, list(
"MODE_NO_COMBAT_CAS" = MODE_NO_COMBAT_CAS,
"MODE_LZ_PROTECTION" = MODE_LZ_PROTECTION,
"MODE_SHIPSIDE_SD" = MODE_SHIPSIDE_SD,
+ "MODE_DISPOSABLE_MOBS" = MODE_DISPOSABLE_MOBS,
))
DEFINE_BITFIELD(state, list(
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 20ff65ed144e..de884cfebe61 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -121,6 +121,7 @@ var/list/admin_verbs_minor_event = list(
/client/proc/toggle_sniper_upgrade,
/client/proc/toggle_attack_dead,
/client/proc/toggle_strip_drag,
+ /client/proc/toggle_disposal_mobs,
/client/proc/toggle_uniform_strip,
/client/proc/toggle_strong_defibs,
/client/proc/toggle_blood_optimization,
diff --git a/code/modules/admin/tabs/admin_tab.dm b/code/modules/admin/tabs/admin_tab.dm
index a2f3bd42df5f..6dc08c63e5de 100644
--- a/code/modules/admin/tabs/admin_tab.dm
+++ b/code/modules/admin/tabs/admin_tab.dm
@@ -708,6 +708,20 @@
SSticker.mode.toggleable_flags ^= MODE_NO_ATTACK_DEAD
message_admins("[src] has [MODE_HAS_TOGGLEABLE_FLAG(MODE_NO_ATTACK_DEAD) ? "prevented dead mobs from being" : "allowed dead mobs to be"] attacked.")
+/client/proc/toggle_disposal_mobs()
+ set name = "Toggle Disposable Mobs"
+ set category = "Admin.Flags"
+
+ if(!admin_holder || !check_rights(R_EVENT, FALSE))
+ return
+
+ if(!SSticker.mode)
+ to_chat(usr, SPAN_WARNING("A mode hasn't been selected yet!"))
+ return
+
+ SSticker.mode.toggleable_flags ^= MODE_DISPOSABLE_MOBS
+ message_admins("[src] has [MODE_HAS_TOGGLEABLE_FLAG(MODE_DISPOSABLE_MOBS) ? "allowed mobs to fit" : "prevented mobs fitting"] inside disposals.")
+
/client/proc/toggle_strip_drag()
set name = "Toggle Strip/Drag Dead"
set category = "Admin.Flags"
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 8a5a6ec960ec..2c7401ac278c 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -37,6 +37,13 @@
active_power_usage = 3500
idle_power_usage = 100
var/disposal_pressure = 0
+ ///Whether the disposals tube is too narrow for a mob to fit into.
+ var/narrow_tube = FALSE
+
+/obj/structure/machinery/disposal/delivery
+ name = "delivery chute"
+ desc = "A pneumatic delivery unit connecting two locations. It's rather narrow."
+ narrow_tube = TRUE
/obj/structure/machinery/disposal/broken
name = "broken disposal unit"
@@ -128,24 +135,42 @@
update()
return
- var/obj/item/grab/G = I
- if(istype(G)) //Handle grabbed mob
- if(ismob(G.grabbed_thing))
- to_chat(user, SPAN_WARNING("You can't fit that in there!"))
- return
- /*&& user.grab_level >= GRAB_AGGRESSIVE)
- var/mob/GM = G.grabbed_thing
- user.visible_message(SPAN_WARNING("[user] starts putting [GM] into [src]."),
- SPAN_WARNING("You start putting [GM] into [src]."))
- if(do_after(user, 20, INTERRUPT_ALL, BUSY_ICON_HOSTILE))
- GM.forceMove(src)
- user.visible_message(SPAN_WARNING("[user] puts [GM] into [src]."),
- SPAN_WARNING("[user] puts [GM] into [src]."))
- user.attack_log += text("\[[time_stamp()]\] Has placed [GM] ([GM.ckey]) in disposals.")
- GM.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [user] ([user.ckey])")
- msg_admin_attack("[user] ([user.ckey]) placed [GM] ([GM.ckey]) in a disposals unit in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z)
- flush()*/
- return
+ var/obj/item/grab/grab_effect = I
+ if(istype(grab_effect)) //Handle grabbed mob
+ if(ismob(grab_effect.grabbed_thing))
+ var/mob/grabbed_mob = grab_effect.grabbed_thing
+ if((!MODE_HAS_TOGGLEABLE_FLAG(MODE_DISPOSABLE_MOBS) && !HAS_TRAIT(grabbed_mob, TRAIT_CRAWLER)) || narrow_tube || grabbed_mob.mob_size >= MOB_SIZE_BIG)
+ to_chat(user, SPAN_WARNING("You can't fit that in there!"))
+ return FALSE
+ var/max_grab_size = user.mob_size
+ /// Amazing what you can do with a bit of dexterity.
+ if(HAS_TRAIT(user, TRAIT_DEXTROUS))
+ max_grab_size++
+ /// Strong mobs can lift above their own weight.
+ if(HAS_TRAIT(user, TRAIT_SUPER_STRONG))//NB; this will mean Yautja can bodily lift MOB_SIZE_XENO(3) and Synths can lift MOB_SIZE_XENO_SMALL(2)
+ max_grab_size++
+ if(grabbed_mob.mob_size > max_grab_size || !(grabbed_mob.status_flags & CANPUSH))
+ to_chat(user, SPAN_WARNING("You don't have the strength to move [grabbed_mob]!"))
+ return FALSE//can't tighten your grip on mobs bigger than you and mobs you can't push.
+ if(!user.grab_level >= GRAB_AGGRESSIVE)
+ to_chat(user, SPAN_WARNING("You need a better grip to force [grabbed_mob] in there!"))
+ return FALSE
+ user.visible_message(SPAN_WARNING("[user] starts putting [grabbed_mob] into [src]."),
+ SPAN_WARNING("You start putting [grabbed_mob] into [src]."))
+ if(!do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE))
+ user.visible_message(SPAN_WARNING("[user] stops putting [grabbed_mob] into [src]."),
+ SPAN_WARNING("You stop putting [grabbed_mob] into [src]."))
+ return FALSE
+
+ grabbed_mob.forceMove(src)
+ user.visible_message(SPAN_WARNING("[user] puts [grabbed_mob] into [src]."),
+ SPAN_WARNING("[user] puts [grabbed_mob] into [src]."))
+ user.attack_log += text("\[[time_stamp()]\] Has placed [key_name(grabbed_mob)] in disposals.")
+ grabbed_mob.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [user] ([user.ckey])")
+ msg_admin_attack("[user] ([user.ckey]) placed [key_name(grabbed_mob)] in a disposals unit in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z)
+ flush(TRUE)//Forcibly flushing someone if forced in by another player.
+ return TRUE
+ return FALSE
if(isrobot(user))
return
@@ -161,51 +186,50 @@
///Mouse drop another mob or self
/obj/structure/machinery/disposal/MouseDrop_T(mob/target, mob/user)
- return
-/*
- if(!istype(target) || target.anchored || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.is_mob_incapacitated(TRUE) || isRemoteControlling(user) || target.mob_size >= MOB_SIZE_BIG)
- return
- if(!(ishuman(target)) || !(ishuman(user))) return
- if(isanimal(user) && target != user) return //Animals cannot put mobs other than themselves into disposal
+ if((!MODE_HAS_TOGGLEABLE_FLAG(MODE_DISPOSABLE_MOBS) && !HAS_TRAIT(user, TRAIT_CRAWLER)) || narrow_tube)
+ to_chat(user, SPAN_WARNING("Looks a little bit too tight in there!"))
+ return FALSE
+
+ if(target != user)
+ to_chat(user, SPAN_WARNING("You need a better grip on [target] to force them into [src]!"))
+ return FALSE //Need a firm grip to put someone else in there.
+
+ if(!istype(target) || target.anchored || target.buckled || get_dist(user, src) > 1 || user.is_mob_incapacitated(TRUE) || isRemoteControlling(user) || target.mob_size >= MOB_SIZE_BIG)
+ to_chat(user, SPAN_WARNING("You cannot get into the [src]!"))
+ return FALSE
add_fingerprint(user)
var/target_loc = target.loc
if(target == user)
visible_message(SPAN_NOTICE("[user] starts climbing into the disposal."))
- else
- if(user.is_mob_restrained()) return //can't stuff someone other than you if restrained.
- visible_message(SPAN_WARNING("[user] starts stuffing [target] into the disposal."))
+
if(!do_after(user, 40, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE))
- return
+ return FALSE
if(target_loc != target.loc)
- return
+ return FALSE
+ if(user.is_mob_incapacitated(TRUE))
+ to_chat(user, SPAN_WARNING("You cannot do this while incapacitated!"))
+ return FALSE
+
if(target == user)
- if(user.is_mob_incapacitated(TRUE)) return
user.visible_message(SPAN_NOTICE("[user] climbs into [src]."),
SPAN_NOTICE("You climb into [src]."))
- else
- if(user.is_mob_incapacitated()) return
- user.visible_message(SPAN_DANGER("[user] stuffs [target] into [src]!"),
- SPAN_WARNING("You stuff [target] into [src]!"))
-
- user.attack_log += text("\[[time_stamp()]\] Has placed [target.name] ([target.ckey]) in disposals.")
- target.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [user.name] ([user.ckey])")
- msg_admin_attack("[user] ([user.ckey]) placed [target] ([target.ckey]) in a disposals unit in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z)
+ user.attack_log += text("\[[time_stamp()]\] [key_name(user)] climbed into a disposals bin!")
target.forceMove(src)
- flush()
- update()*/
+ flush()//Not forcing flush if climbing in by self.
+ update()
///Attempt to move while inside
/obj/structure/machinery/disposal/relaymove(mob/user)
if(user.stat || user.stunned || user.knocked_down || flushing)
- return
+ return FALSE
if(user.loc == src)
go_out(user)
+ return TRUE
///Leave the disposal
/obj/structure/machinery/disposal/proc/go_out(mob/user)
-
if(user.client)
user.client.eye = user.client.mob
user.client.perspective = MOB_PERSPECTIVE
@@ -364,7 +388,9 @@
return
///Perform a flush
-/obj/structure/machinery/disposal/proc/flush()
+/obj/structure/machinery/disposal/proc/flush(forced = FALSE)
+ if((disposal_pressure < SEND_PRESSURE) && !forced)
+ return FALSE
flushing = TRUE
flick("[icon_state]-flush", src)
diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm
index 741b511792b1..ce4a853acc62 100644
--- a/maps/map_files/USS_Almayer/USS_Almayer.dmm
+++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm
@@ -5011,7 +5011,7 @@
/obj/structure/disposalpipe/trunk{
dir = 1
},
-/obj/structure/machinery/disposal{
+/obj/structure/machinery/disposal/delivery{
density = 0;
desc = "A pneumatic delivery unit. Sends items to the requisitions.";
icon_state = "delivery_engi";
@@ -76155,12 +76155,12 @@
/obj/structure/disposalpipe/trunk{
dir = 1
},
-/obj/structure/machinery/disposal{
+/obj/structure/machinery/disposal/delivery{
density = 0;
desc = "A pneumatic delivery unit. Sends items to the requisitions.";
icon_state = "delivery_med";
name = "Requisitions Delivery Unit";
- pixel_y = 29
+ pixel_y = 28
},
/turf/open/floor/almayer{
icon_state = "mono"