diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 647f48e0a62..5899bb7a4b7 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -1,11 +1,19 @@
-// Disposal bin
-// Holds items for disposal into pipe system
-// Draws air from turf, gradually charges internal reservoir
-// Once full (~1 atm), uses air resv to flush items into the pipes
-// Automatically recharges air (unless off), will flush when ready if pre-set
-// Can hold items and human size things, no other draggables
-// Toilets are a type of disposal bin for small objects only and work on magic. By magic, I mean torque rotation
-#define SEND_PRESSURE 0.05*ONE_ATMOSPHERE
+////////////////////////////////////////
+// MARK: Disposal unit
+////////////////////////////////////////
+/*
+* Holds items for disposal into pipe system
+* Draws air from turf, gradually charges internal reservoir
+* Once full (~1 atm), uses air resv to flush items into the pipes
+* Automatically recharges air (unless off), will flush when ready if pre-set
+* Can hold items and human size things, no other draggables
+* Toilets are a type of disposal bin for small objects only and work on magic. By magic, I mean torque rotation
+*/
+#define SEND_PRESSURE 0.05 * ONE_ATMOSPHERE
+#define DISPOSALS_UNSCREWED -1
+#define DISPOSALS_OFF 0
+#define DISPOSALS_RECHARGING 1
+#define DISPOSALS_CHARGED 2
/obj/machinery/disposal
name = "disposal unit"
@@ -22,22 +30,30 @@
active_power_consumption = 600
idle_power_consumption = 100
- var/datum/gas_mixture/air_contents // internal reservoir
- var/mode = 1 // item mode 0=off 1=charging 2=charged
- var/flush = 0 // true if flush handle is pulled
- var/obj/structure/disposalpipe/trunk/trunk = null // the attached pipe trunk
- var/flushing = 0 // true if flushing in progress
- var/flush_every_ticks = 30 //Every 30 ticks it will look whether it is ready to flush
- var/flush_count = 0 //this var adds 1 once per tick. When it reaches flush_every_ticks it resets and tries to flush.
+ /// Internal gas reservoir.
+ var/datum/gas_mixture/air_contents
+ /// Can be one of: DISPOSALS_UNSCREWED (power off and panel unscrewed), DISPOSALS_OFF (power switched off), DISPOSALS_RECHARGING (active and charging), or DISPOSALS_CHARGED (active and ready to flush)
+ var/mode = DISPOSALS_RECHARGING
+ /// Has the flush handle been pulled?
+ var/flush = FALSE
+ /// The attached pipe trunk.
+ var/obj/structure/disposalpipe/trunk/trunk = null
+ /// Is the disposals bin flushing right now?
+ var/flushing = FALSE
+ /// After the specified number of ticks, the disposals bin will check if it is ready to flush.
+ var/flush_every_ticks = 30
+ /// Counter that increments by 1 per tick. Resets when it reaches the value of flush_every_ticks and attempts to perform a flush.
+ var/flush_count = 0
var/last_sound = 0
- var/required_mode_to_deconstruct = -1
+ var/required_mode_to_deconstruct = DISPOSALS_UNSCREWED
+ /// What does this drop when deconstructed?
var/deconstructs_to = PIPE_DISPOSALS_BIN
/obj/machinery/disposal/proc/trunk_check()
var/obj/structure/disposalpipe/trunk/T = locate() in loc
if(!T)
- mode = 0
- flush = 0
+ mode = DISPOSALS_OFF
+ flush = FALSE
else
mode = initial(mode)
flush = initial(flush)
@@ -52,7 +68,10 @@
if(T.intact)
var/turf/simulated/floor/F = T
F.remove_tile(null,TRUE,TRUE)
- T.visible_message("The floortile is ripped from the floor!", "You hear a loud bang!")
+ T.visible_message(
+ "The floortile is ripped from the floor!",
+ "You hear a loud bang!"
+ )
if(trunk)
trunk.remove_trunk_links()
var/obj/structure/disposalconstruct/C = new (loc)
@@ -118,64 +137,114 @@
var/obj/item/storage/S = I
if(!S.removal_allowed_check(user))
return
+
if((S.allow_quick_empty || S.allow_quick_gather) && length(S.contents))
S.hide_from(user)
- user.visible_message("[user] empties \the [S] into \the [src].", "You empty \the [S] into \the [src].")
+ user.visible_message(
+ "[user] empties [S] into the disposal unit.",
+ "You empty [S] into disposal unit.",
+ "You hear someone emptying something into a disposal unit."
+ )
for(var/obj/item/O in S.contents)
S.remove_from_storage(O, src)
S.update_icon() // For content-sensitive icons
update()
return
+ // Borg using their gripper to throw stuff away.
+ if(istype(I, /obj/item/gripper/))
+ var/obj/item/gripper/gripper = I
+ // Gripper is empty.
+ if(!gripper.gripped_item)
+ to_chat(user, "There's nothing in your gripper to throw away!")
+ return
+
+ gripper.gripped_item.forceMove(src)
+ user.visible_message(
+ "[user] places [gripper.gripped_item] into the disposal unit.",
+ "You place [gripper.gripped_item] into the disposal unit.",
+ "You hear someone dropping something into a disposal unit."
+ )
+ return
+
+ // Someone has a mob in a grab.
var/obj/item/grab/G = I
- if(istype(G)) // handle grabbed mob
- if(ismob(G.affecting))
- var/mob/GM = G.affecting
- for(var/mob/V in viewers(usr))
- V.show_message("[usr] starts putting [GM] into the disposal.", 3)
- if(do_after(usr, 20, target = GM))
- GM.forceMove(src)
- for(var/mob/C in viewers(src))
- C.show_message("[GM] has been placed in [src] by [user].", 3)
- qdel(G)
- add_attack_logs(usr, GM, "Disposal'ed", !!GM.ckey ? null : ATKLOG_ALL)
+ if(istype(G))
+ // If there's not actually a mob in the grab, stop it. Get some help.
+ if(!ismob(G.affecting))
+ return
+
+ var/mob/GM = G.affecting
+ user.visible_message(
+ "[user] starts stuffing [GM] into the disposal unit!",
+ "You start stuffing [GM] into the disposal unit.",
+ "You hear someone trying to stuff someone else into a disposal unit!"
+ )
+
+ // Abort if the target manages to scurry away.
+ if(!do_after(user, 2 SECONDS, target = GM))
+ return
+
+ GM.forceMove(src)
+ user.visible_message(
+ "[GM] has been stuffed into the disposal unit by [user]!",
+ "You stuff [GM] into the disposal unit.",
+ "You hear someone being stuffed into a disposal unit!"
+ )
+ qdel(G)
+ update()
+ add_attack_logs(user, GM, "Disposal'ed", !GM.ckey ? null : ATKLOG_ALL)
return
if(!user.drop_item() || QDELETED(I))
return
+ // If we're here, it's an item without any special interactions, drop it in the bin without any further delay.
I.forceMove(src)
- user.visible_message("[user] places [I] into [src].", "You place [I] into [src].")
+ user.visible_message(
+ "[user] places [I] into the disposal unit.",
+ "You place [I] into the disposal unit.",
+ "You hear someone dropping something into a disposal unit."
+ )
update()
-
-
-
/obj/machinery/disposal/screwdriver_act(mob/user, obj/item/I)
- if(mode>0) // It's on
+ if(mode != DISPOSALS_OFF) // It's on
+ to_chat(user, "You need to turn the disposal unit off first!")
return
+
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
+
if(length(contents) > 0)
- to_chat(user, "Eject the items first!")
+ to_chat(user, "You need to empty the contents of the disposal unit first!")
return
- if(mode==0) // It's off but still not unscrewed
- mode=-1 // Set it to doubleoff l0l
- else if(mode==-1)
- mode=0
- to_chat(user, "You [mode ? "unfasten": "fasten"] the screws around the power connection.")
+
+ if(mode == DISPOSALS_OFF) // It's off but still not unscrewed
+ mode = DISPOSALS_UNSCREWED
+ else if(mode == DISPOSALS_UNSCREWED)
+ mode = DISPOSALS_OFF
+ user.visible_message(
+ "[user] [mode ? "unfastens": "fastens"] the screws around the power connection of the disposal unit.",
+ "You [mode ? "unfasten": "fasten"] the screws around the power connection of the disposal unit.",
+ "You hear screws being [mode ? "unfastened": "fastened"]."
+ )
update()
/obj/machinery/disposal/welder_act(mob/user, obj/item/I)
- if(mode != required_mode_to_deconstruct)
+ if(mode != DISPOSALS_UNSCREWED)
+ to_chat(user, "You need to unscrew the disposal unit first!")
return
+
. = TRUE
if(length(contents) > 0)
- to_chat(user, "Eject the items first!")
+ to_chat(user, "You need to empty the contents of the disposal unit first!")
return
+
if(!I.tool_use_check(user, 0))
return
+
WELDER_ATTEMPT_FLOOR_SLICE_MESSAGE
if(I.use_tool(src, user, 20, volume = I.tool_volume))
WELDER_FLOOR_SLICE_SUCCESS_MESSAGE
@@ -188,9 +257,9 @@
/obj/machinery/disposal/shove_impact(mob/living/target, mob/living/attacker)
target.visible_message(
- "[attacker] shoves [target] inside of [src]!",
- "[attacker] shoves you inside of [src]!",
- "You hear the sound of something being thrown in the trash."
+ "[attacker] shoves [target] inside of the disposal unit!",
+ "[attacker] shoves you inside of the disposal unit!",
+ "You hear the sound of someone being thrown into a disposal unit."
)
target.forceMove(src)
add_attack_logs(attacker, target, "Shoved into disposals", target.ckey ? null : ATKLOG_ALL)
@@ -203,32 +272,54 @@
/obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user)
if(!istype(target) || target.buckled || target.has_buckled_mobs() || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || isAI(user))
return
+
+ // Animals cannot put mobs other than themselves into disposals.
if(isanimal(user) && target != user)
- return //animals cannot put mobs other than themselves into disposal
+ return
+
src.add_fingerprint(user)
- for(var/mob/V in viewers(usr))
- if(target == user && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
- V.show_message("[usr] starts climbing into the disposal.", 3)
- if(target != user && !user.restrained() && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
- if(target.anchored) return
- V.show_message("[usr] starts stuffing [target.name] into the disposal.", 3)
+ if(target == user && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
+ user.visible_message(
+ "[user] starts climbing into the disposal unit.",
+ "You start climbing into the disposal unit.",
+ "You hear someone trying to climb into a disposal unit."
+ )
+
+ if(target != user && !user.restrained() && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
+ if(target.anchored)
+ return
+ user.visible_message("[user] starts stuffing [target.name] into the disposal.")
+ user.visible_message(
+ "[user] starts stuffing [target] into the disposal unit!",
+ "You start stuffing [target] into the disposal unit.",
+ "You hear someone trying to stuff someone else into a disposal unit!"
+ )
INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/machinery/disposal, put_in), target, user)
return TRUE
/obj/machinery/disposal/proc/put_in(mob/living/target, mob/living/user) // need this proc to use INVOKE_ASYNC in other proc. You're not recommended to use that one
- var/msg
- var/target_loc = target.loc
- if(!do_after(usr, 20, target = target))
+ if(!do_after(user, 20, target = target))
return
+
+ var/target_loc = target.loc
if(QDELETED(src) || target_loc != target.loc)
return
- if(target == user && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed()) // if drop self, then climbed in
- // must be awake, not stunned or whatever
- msg = "[user.name] climbs into [src]."
- to_chat(user, "You climb into [src].")
+
+ // All the extra checks ensure you cannot disposal yourself/others whilst incapacitated.
+ if(target == user && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
+ user.visible_message(
+ "[user] climbs into the disposal unit.",
+ "You climb into the disposal unit.",
+ "You hear someone climbing into a disposal unit."
+ )
+
else if(target != user && !user.restrained() && !user.stat && !user.IsWeakened() && !user.IsStunned() && !user.IsParalyzed())
- msg = "[user.name] stuffs [target.name] into [src]!"
- to_chat(user, "You stuff [target.name] into [src]!")
+ user.visible_message(
+ "[user] stuffs [target] into the disposal unit.",
+ "You stuff [target] into the disposal unit.",
+ "You hear the sound of someone being stuffed into a disposal unit."
+ )
+
if(!iscarbon(user))
target.LAssailant = null
else
@@ -236,14 +327,9 @@
add_attack_logs(user, target, "Disposal'ed", !!target.ckey ? null : ATKLOG_ALL)
else
return
+
QDEL_LIST_CONTENTS(target.grabbed_by)
target.forceMove(src)
-
- for(var/mob/C in viewers(src))
- if(C == user)
- continue
- C.show_message(msg, 3)
-
update()
// attempt to move while inside
@@ -311,11 +397,11 @@
if(..())
return
if(usr.loc == src)
- to_chat(usr, "You cannot reach the controls from inside.")
+ to_chat(usr, "You cannot reach the controls from inside!")
return
- if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection
- to_chat(usr, "The disposal units power is disabled.")
+ if(mode == DISPOSALS_UNSCREWED && action != "eject") // If the mode is DISPOSALS_UNSCREWED, only allow ejection
+ to_chat(usr, "The disposal unit's power is disabled!")
return
if(stat & BROKEN)
@@ -328,18 +414,18 @@
if(isturf(src.loc))
if(action == "pumpOn")
- mode = 1
+ mode = DISPOSALS_RECHARGING
update()
if(action == "pumpOff")
- mode = 0
+ mode = DISPOSALS_OFF
update()
if(!issilicon(usr))
if(action == "engageHandle")
- flush = 1
+ flush = TRUE
update()
if(action == "disengageHandle")
- flush = 0
+ flush = FALSE
update()
if(action == "eject")
@@ -358,21 +444,24 @@
if(!Adjacent(user) || !ishuman(user) || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
return
user.visible_message(
- "[user] tries to eject the contents of [src] manually.",
- "You operate the manual ejection lever on [src]."
+ "[user] tries to eject the contents of the disposal unit manually.",
+ "You operate the manual ejection lever on the disposal unit.",
+ "You hear a lever being pulled."
)
+
if(do_after(user, 5 SECONDS, target = src))
user.visible_message(
- "[user] ejects the contents of [src].",
- "You eject the contents of [src]."
+ "[user] ejects the contents of the disposal unit.",
+ "You eject the contents of the disposal unit.",
+ "You hear a sudden gush of air and the clattering of objects."
)
eject()
// update the icon & overlays to reflect mode & status
/obj/machinery/disposal/proc/update()
if(stat & BROKEN)
- mode = 0
- flush = 0
+ mode = DISPOSALS_OFF
+ flush = FALSE
update_icon()
@@ -392,7 +481,7 @@
if(flush)
. += "dispover-handle"
- if(stat & (NOPOWER|BROKEN) || mode == -1)
+ if(stat & (NOPOWER|BROKEN) || mode == DISPOSALS_UNSCREWED)
return
// check for items in disposal - occupied light
@@ -402,12 +491,12 @@
// charging and ready light
switch(mode)
- if(-1)
+ if(DISPOSALS_UNSCREWED)
. += "dispover-unscrewed"
- if(1)
+ if(DISPOSALS_RECHARGING)
. += "dispover-charge"
underlays += emissive_appearance(icon, "dispover-charge")
- if(2)
+ if(DISPOSALS_CHARGED)
. += "dispover-ready"
underlays += emissive_appearance(icon, "dispover-ready")
@@ -421,7 +510,7 @@
flush_count++
if(flush_count >= flush_every_ticks)
if(length(contents))
- if(mode == 2)
+ if(mode == DISPOSALS_CHARGED)
spawn(0)
flush()
flush_count = 0
@@ -436,7 +525,7 @@
change_power_mode(IDLE_POWER_USE)
- if(mode != 1) // if off or ready, no need to charge
+ if(mode != DISPOSALS_RECHARGING) // if off or ready, no need to charge
return
// otherwise charge
@@ -445,7 +534,6 @@
var/datum/milla_safe/disposal_suck_air/milla = new()
milla.invoke_async(src)
-
// perform a flush
/obj/machinery/disposal/proc/flush()
@@ -481,8 +569,8 @@
flushing = 0
// now reset disposal state
flush = 0
- if(mode == 2) // if was ready,
- mode = 1 // switch to charging
+ if(mode == DISPOSALS_CHARGED) // if was ready,
+ mode = DISPOSALS_RECHARGING // switch to charging
update()
return
@@ -527,16 +615,24 @@
var/obj/item/I = mover
if(isprojectile(I))
return
+
var/atom/movable/thrower = mover.throwing?.get_thrower()
if(prob(75) || (istype(thrower) && (HAS_TRAIT(thrower, TRAIT_BADASS) || HAS_TRAIT(thrower, TRAIT_NEVER_MISSES_DISPOSALS))))
I.forceMove(src)
- for(var/mob/M in viewers(src))
- M.show_message("[I] lands in [src].", 3)
+ visible_message(
+ "[I] lands in [src].",
+ "You hear something being tossed into a disposal unit."
+ )
update()
+ return
+
else
- for(var/mob/M in viewers(src))
- M.show_message("\the [I] bounces off of \the [src]'s rim!", 3)
- return 0
+ visible_message(
+ "[I] bounces off of [src]'s rim!",
+ "You hear something bouncing off the rim of a disposal unit!"
+ )
+ return
+
else
return ..(mover, target, height)
@@ -552,11 +648,18 @@
/obj/machinery/disposal/force_eject_occupant(mob/target)
target.forceMove(get_turf(src))
+#undef DISPOSALS_UNSCREWED
+#undef DISPOSALS_OFF
+#undef DISPOSALS_RECHARGING
+#undef DISPOSALS_CHARGED
+
+////////////////////////////////////////
+// MARK: Disposal holder
+////////////////////////////////////////
// virtual disposal object
// travels through pipes in lieu of actual items
// contents will be items flushed by the disposal
// this allows the gas flushed to be tracked
-
/obj/structure/disposalholder
invisibility = INVISIBILITY_MAXIMUM
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -720,7 +823,9 @@
if(istype(location))
location.blind_release_air(gas)
-// Disposal pipes
+////////////////////////////////////////
+// MARK: Disposals pipes
+////////////////////////////////////////
/obj/structure/disposalpipe
icon = 'icons/obj/pipes/disposal.dmi'
@@ -1013,7 +1118,9 @@
/obj/structure/disposalpipe/segment/corner
icon_state = "pipe-c"
-//a three-way junction with dir being the dominant direction
+////////////////////////////////////////
+// MARK: Disposals junction
+////////////////////////////////////////
/obj/structure/disposalpipe/junction
icon_state = "pipe-j1"
@@ -1062,7 +1169,9 @@
else
return mask & (~setbit)
-//a three-way junction that sorts objects
+////////////////////////////////////////
+// MARK: Sorting junction
+////////////////////////////////////////
/obj/structure/disposalpipe/sortjunction
name = "disposal sort junction"
icon_state = "pipe-j1s"
@@ -1197,7 +1306,9 @@
return P
-
+////////////////////////////////////////
+// MARK: Wrap sort junction
+////////////////////////////////////////
//a three-way junction that sorts objects destined for the mail office mail table (tomail = 1)
/obj/structure/disposalpipe/wrapsortjunction
desc = "An underfloor disposal pipe which sorts wrapped and unwrapped objects."
@@ -1363,7 +1474,9 @@
else
return 0
-// a broken pipe
+////////////////////////////////////////
+// MARK: Broken pipe
+////////////////////////////////////////
/obj/structure/disposalpipe/broken
icon_state = "pipe-b"
dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes
@@ -1382,8 +1495,9 @@
qdel(src)
return TRUE
-// the disposal outlet machine
-
+////////////////////////////////////////
+// MARK: Disposals outlet
+////////////////////////////////////////
/obj/structure/disposaloutlet
name = "disposal outlet"
desc = "An outlet for the pneumatic disposal system."
@@ -1475,7 +1589,11 @@
if(T.intact)
var/turf/simulated/floor/F = T
F.remove_tile(null,TRUE,TRUE)
- T.visible_message("The floortile is ripped from the floor!", "You hear a loud bang!")
+ T.visible_message(
+ "The floortile is ripped from the floor!",
+ "You hear a loud bang!"
+ )
+
if(linkedtrunk)
linkedtrunk.remove_trunk_links()
var/obj/structure/disposalconstruct/C = new (loc)