diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index 4ce388b844..ca06277551 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -202,8 +202,6 @@ datum/pipeline
//surface must be the surface area in m^2
proc/radiate_heat_to_space(surface, thermal_conductivity)
- var/total_heat_capacity = air.heat_capacity()
-
//if the h/e pipes radiate less than the AVERAGE_SOLAR_RADIATION, then they will heat up, otherwise they will cool down. It turns out the critical temperature is -26 C
var/heat_gain = surface*(AVERAGE_SOLAR_RADIATION - STEFAN_BOLTZMANN_CONSTANT*thermal_conductivity*(air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4)
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index eff51fc697..88c72ec198 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -64,7 +64,7 @@
playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
flick("[base_state]_flash", src)
src.last_flash = world.time
- use_power(1000)
+ use_power(1500)
for (var/mob/O in viewers(src, null))
if (get_dist(src, O) > src.range)
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 0280599d5e..e6fe39f903 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -5,7 +5,9 @@
// 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 SEND_PRESSURE 700 //kPa. 7 bar - Based on existing pneumatic conveyor pressures.
+#define PRESSURE_TANK_VOLUME 70 //L - a 0.3 m diameter * 1 m long cylindrical tank. Happens to be the same volume as the regular oxygen tanks, so seems appropriate.
+#define PUMP_MAX_FLOW_RATE 50 //L/s - 2 m/s using a 15 cm by 15 cm inlet
/obj/machinery/disposal
name = "disposal unit"
@@ -22,460 +24,459 @@
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.
var/last_sound = 0
- active_power_usage = 600
+ active_power_usage = 1500 //the pneumatic pump power. 2 HP ~ 1500W
idle_power_usage = 100
- // create a new disposal
- // find the attached trunk (if present) and init gas resvr.
- New()
- ..()
- spawn(5)
- trunk = locate() in src.loc
- if(!trunk)
- mode = 0
- flush = 0
- else
- trunk.linked = src // link the pipe trunk to self
-
- air_contents = new/datum/gas_mixture()
- //gas.volume = 1.05 * CELLSTANDARD
- update()
-
-
- // attack by item places it in to disposal
- attackby(var/obj/item/I, var/mob/user)
- if(stat & BROKEN || !I || !user)
- return
-
- if(isrobot(user) && !istype(I, /obj/item/weapon/storage/bag/trash))
- return
- src.add_fingerprint(user)
- if(mode<=0) // It's off
- if(istype(I, /obj/item/weapon/screwdriver))
- if(contents.len > 0)
- user << "Eject the items first!"
- return
- if(mode==0) // It's off but still not unscrewed
- mode=-1 // Set it to doubleoff l0l
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You remove the screws around the power connection."
- return
- else if(mode==-1)
- mode=0
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- user << "You attach the screws around the power connection."
- return
- else if(istype(I,/obj/item/weapon/weldingtool) && mode==-1)
- if(contents.len > 0)
- user << "Eject the items first!"
- return
- var/obj/item/weapon/weldingtool/W = I
- if(W.remove_fuel(0,user))
- playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
- user << "You start slicing the floorweld off the disposal unit."
-
- if(do_after(user,20))
- if(!src || !W.isOn()) return
- user << "You sliced the floorweld off the disposal unit."
- var/obj/structure/disposalconstruct/C = new (src.loc)
- src.transfer_fingerprints_to(C)
- C.ptype = 6 // 6 = disposal unit
- C.anchored = 1
- C.density = 1
- C.update()
- del(src)
- return
- else
- user << "You need more welding fuel to complete this task."
- return
-
- if(istype(I, /obj/item/weapon/melee/energy/blade))
- user << "You can't place that item inside the disposal unit."
- return
-
- if(istype(I, /obj/item/weapon/storage/bag/trash))
- var/obj/item/weapon/storage/bag/trash/T = I
- user << "\blue You empty the bag."
- for(var/obj/item/O in T.contents)
- T.remove_from_storage(O,src)
- T.update_icon()
- update()
- return
-
- var/obj/item/weapon/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.name] into the disposal.", 3)
- if(do_after(usr, 20))
- if (GM.client)
- GM.client.perspective = EYE_PERSPECTIVE
- GM.client.eye = src
- GM.loc = src
- for (var/mob/C in viewers(src))
- C.show_message("\red [GM.name] has been placed in the [src] by [user].", 3)
- del(G)
- usr.attack_log += text("\[[time_stamp()]\] Has placed [GM.name] ([GM.ckey]) in disposals.")
- GM.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [usr.name] ([usr.ckey])")
- msg_admin_attack("[usr] ([usr.ckey]) placed [GM] ([GM.ckey]) in a disposals unit. (JMP)")
- return
-
- if(!I) return
-
- user.drop_item()
- if(I)
- I.loc = src
-
- user << "You place \the [I] into the [src]."
- for(var/mob/M in viewers(src))
- if(M == user)
- continue
- M.show_message("[user.name] places \the [I] into the [src].", 3)
-
- update()
-
- // mouse drop another mob or self
- //
- MouseDrop_T(mob/target, mob/user)
- if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
- return
- if(isanimal(user) && target != user) return //animals cannot put mobs other than themselves into disposal
- src.add_fingerprint(user)
- var/target_loc = target.loc
- var/msg
- for (var/mob/V in viewers(usr))
- if(target == user && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
- V.show_message("[usr] starts climbing into the disposal.", 3)
- if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
- if(target.anchored) return
- V.show_message("[usr] starts stuffing [target.name] into the disposal.", 3)
- if(!do_after(usr, 20))
- return
- if(target_loc != target.loc)
- return
- if(target == user && !user.stat && !user.weakened && !user.stunned && !user.paralysis) // if drop self, then climbed in
- // must be awake, not stunned or whatever
- msg = "[user.name] climbs into the [src]."
- user << "You climb into the [src]."
- else if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
- msg = "[user.name] stuffs [target.name] into the [src]!"
- user << "You stuff [target.name] into the [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. (JMP)")
- else
- return
- if (target.client)
- target.client.perspective = EYE_PERSPECTIVE
- target.client.eye = src
- target.loc = src
-
- for (var/mob/C in viewers(src))
- if(C == user)
- continue
- C.show_message(msg, 3)
-
- update()
- return
-
- // can breath normally in the disposal
- alter_health()
- return get_turf(src)
-
- // attempt to move while inside
- relaymove(mob/user as mob)
- if(user.stat || src.flushing)
- return
- src.go_out(user)
- return
-
- // leave the disposal
- proc/go_out(mob/user)
-
- if (user.client)
- user.client.eye = user.client.mob
- user.client.perspective = MOB_PERSPECTIVE
- user.loc = src.loc
- update()
- return
-
-
- // monkeys can only pull the flush lever
- attack_paw(mob/user as mob)
- if(stat & BROKEN)
- return
-
- flush = !flush
- update()
- return
-
- // ai as human but can't flush
- attack_ai(mob/user as mob)
- interact(user, 1)
-
- // human interact with machine
- attack_hand(mob/user as mob)
- if(user && user.loc == src)
- usr << "\red You cannot reach the controls from inside."
- return
- /*
- if(mode==-1)
- usr << "\red The disposal units power is disabled."
- return
- */
- interact(user, 0)
-
- // user interaction
- interact(mob/user, var/ai=0)
-
- src.add_fingerprint(user)
- if(stat & BROKEN)
- user.unset_machine()
- return
-
- var/dat = "
Waste Disposal UnitWaste Disposal Unit
"
-
- if(!ai) // AI can't pull flush handle
- if(flush)
- dat += "Disposal handle: Disengage Engaged"
- else
- dat += "Disposal handle: Disengaged Engage"
-
- dat += "
Eject contents
"
-
- if(mode <= 0)
- dat += "Pump: Off On
"
- else if(mode == 1)
- dat += "Pump: Off On (pressurizing)
"
- else
- dat += "Pump: Off On (idle)
"
-
- var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE)
-
- dat += "Pressure: [round(per, 1)]%
"
-
-
- user.set_machine(src)
- user << browse(dat, "window=disposal;size=360x170")
- onclose(user, "disposal")
-
- // handle machine interaction
-
- Topic(href, href_list)
- if(usr.loc == src)
- usr << "\red You cannot reach the controls from inside."
- return
-
- if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
- usr << "\red The disposal units power is disabled."
- return
- ..()
- src.add_fingerprint(usr)
- if(stat & BROKEN)
- return
- if(usr.stat || usr.restrained() || src.flushing)
- return
-
- if (in_range(src, usr) && istype(src.loc, /turf))
- usr.set_machine(src)
-
- if(href_list["close"])
- usr.unset_machine()
- usr << browse(null, "window=disposal")
- return
-
- if(href_list["pump"])
- if(text2num(href_list["pump"]))
- mode = 1
- else
- mode = 0
- update()
-
- if(href_list["handle"])
- flush = text2num(href_list["handle"])
- update()
-
- if(href_list["eject"])
- eject()
- else
- usr << browse(null, "window=disposal")
- usr.unset_machine()
- return
- return
-
- // eject the contents of the disposal unit
- proc/eject()
- for(var/atom/movable/AM in src)
- AM.loc = src.loc
- AM.pipe_eject(0)
- update()
-
- // update the icon & overlays to reflect mode & status
- proc/update()
- overlays.Cut()
- if(stat & BROKEN)
- icon_state = "disposal-broken"
+// create a new disposal
+// find the attached trunk (if present) and init gas resvr.
+/obj/machinery/disposal/New()
+ ..()
+ spawn(5)
+ trunk = locate() in src.loc
+ if(!trunk)
mode = 0
flush = 0
- return
+ else
+ trunk.linked = src // link the pipe trunk to self
- // flush handle
- if(flush)
- overlays += image('icons/obj/pipes/disposal.dmi', "dispover-handle")
-
- // only handle is shown if no power
- if(stat & NOPOWER || mode == -1)
- return
-
- // check for items in disposal - occupied light
- if(contents.len > 0)
- overlays += image('icons/obj/pipes/disposal.dmi', "dispover-full")
-
- // charging and ready light
- if(mode == 1)
- overlays += image('icons/obj/pipes/disposal.dmi', "dispover-charge")
- else if(mode == 2)
- overlays += image('icons/obj/pipes/disposal.dmi', "dispover-ready")
-
- // timed process
- // charge the gas reservoir and perform flush if ready
- process()
- use_power = 0
- if(stat & BROKEN) // nothing can happen if broken
- return
-
- if(!air_contents) // Potentially causes a runtime otherwise (if this is really shitty, blame pete //Donkie)
- return
-
- flush_count++
- if( flush_count >= flush_every_ticks )
- if( contents.len )
- if(mode == 2)
- spawn(0)
- feedback_inc("disposal_auto_flush",1)
- flush()
- flush_count = 0
-
- src.updateDialog()
-
- if(flush && air_contents.return_pressure() >= SEND_PRESSURE ) // flush can happen even without power
- flush()
-
- if(stat & NOPOWER) // won't charge if no power
- return
-
- use_power = 1
-
- if(mode != 1) // if off or ready, no need to charge
- return
-
- // otherwise charge
- use_power = 2
-
- var/atom/L = loc // recharging from loc turf
-
- var/datum/gas_mixture/env = L.return_air()
- var/pressure_delta = (SEND_PRESSURE*1.01) - air_contents.return_pressure()
-
- if(env.temperature > 0)
- var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION)
-
- //Actually transfer the gas
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
- air_contents.merge(removed)
+ air_contents = new/datum/gas_mixture()
+ air_contents.volume = PRESSURE_TANK_VOLUME
+ update()
- // if full enough, switch to ready mode
- if(air_contents.return_pressure() >= SEND_PRESSURE)
- mode = 2
- update()
+// attack by item places it in to disposal
+/obj/machinery/disposal/attackby(var/obj/item/I, var/mob/user)
+ if(stat & BROKEN || !I || !user)
return
- // perform a flush
- proc/flush()
+ if(isrobot(user) && !istype(I, /obj/item/weapon/storage/bag/trash))
+ return
+ src.add_fingerprint(user)
+ if(mode<=0) // It's off
+ if(istype(I, /obj/item/weapon/screwdriver))
+ if(contents.len > 0)
+ user << "Eject the items first!"
+ return
+ if(mode==0) // It's off but still not unscrewed
+ mode=-1 // Set it to doubleoff l0l
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You remove the screws around the power connection."
+ return
+ else if(mode==-1)
+ mode=0
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ user << "You attach the screws around the power connection."
+ return
+ else if(istype(I,/obj/item/weapon/weldingtool) && mode==-1)
+ if(contents.len > 0)
+ user << "Eject the items first!"
+ return
+ var/obj/item/weapon/weldingtool/W = I
+ if(W.remove_fuel(0,user))
+ playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
+ user << "You start slicing the floorweld off the disposal unit."
- flushing = 1
- flick("[icon_state]-flush", src)
+ if(do_after(user,20))
+ if(!src || !W.isOn()) return
+ user << "You sliced the floorweld off the disposal unit."
+ var/obj/structure/disposalconstruct/C = new (src.loc)
+ src.transfer_fingerprints_to(C)
+ C.ptype = 6 // 6 = disposal unit
+ C.anchored = 1
+ C.density = 1
+ C.update()
+ del(src)
+ return
+ else
+ user << "You need more welding fuel to complete this task."
+ return
- var/wrapcheck = 0
- var/obj/structure/disposalholder/H = new() // virtual holder object which actually
- // travels through the pipes.
- //Hacky test to get drones to mail themselves through disposals.
- for(var/mob/living/silicon/robot/drone/D in src)
- wrapcheck = 1
+ if(istype(I, /obj/item/weapon/melee/energy/blade))
+ user << "You can't place that item inside the disposal unit."
+ return
- for(var/obj/item/smallDelivery/O in src)
- wrapcheck = 1
-
- if(wrapcheck == 1)
- H.tomail = 1
-
-
- air_contents = new() // new empty gas resv.
-
- sleep(10)
- if(last_sound < world.time + 1)
- playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0)
- last_sound = world.time
- sleep(5) // wait for animation to finish
-
-
- H.init(src) // copy the contents of disposer to holder
-
- H.start(src) // start the holder processing movement
- flushing = 0
- // now reset disposal state
- flush = 0
- if(mode == 2) // if was ready,
- mode = 1 // switch to charging
+ if(istype(I, /obj/item/weapon/storage/bag/trash))
+ var/obj/item/weapon/storage/bag/trash/T = I
+ user << "\blue You empty the bag."
+ for(var/obj/item/O in T.contents)
+ T.remove_from_storage(O,src)
+ T.update_icon()
update()
return
-
- // called when area power changes
- power_change()
- ..() // do default setting/reset of stat NOPOWER bit
- update() // update icon
+ var/obj/item/weapon/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.name] into the disposal.", 3)
+ if(do_after(usr, 20))
+ if (GM.client)
+ GM.client.perspective = EYE_PERSPECTIVE
+ GM.client.eye = src
+ GM.loc = src
+ for (var/mob/C in viewers(src))
+ C.show_message("\red [GM.name] has been placed in the [src] by [user].", 3)
+ del(G)
+ usr.attack_log += text("\[[time_stamp()]\] Has placed [GM.name] ([GM.ckey]) in disposals.")
+ GM.attack_log += text("\[[time_stamp()]\] Has been placed in disposals by [usr.name] ([usr.ckey])")
+ msg_admin_attack("[usr] ([usr.ckey]) placed [GM] ([GM.ckey]) in a disposals unit. (JMP)")
return
+ if(!I) return
- // called when holder is expelled from a disposal
- // should usually only occur if the pipe network is modified
- proc/expel(var/obj/structure/disposalholder/H)
+ user.drop_item()
+ if(I)
+ I.loc = src
- var/turf/target
- playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
- if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it
- for(var/atom/movable/AM in H)
- target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
+ user << "You place \the [I] into the [src]."
+ for(var/mob/M in viewers(src))
+ if(M == user)
+ continue
+ M.show_message("[user.name] places \the [I] into the [src].", 3)
- AM.loc = src.loc
- AM.pipe_eject(0)
- if(!istype(AM,/mob/living/silicon/robot/drone)) //Poor drones kept smashing windows and taking system damage being fired out of disposals. ~Z
- spawn(1)
- if(AM)
- AM.throw_at(target, 5, 1)
+ update()
- H.vent_gas(loc)
- del(H)
+// mouse drop another mob or self
+//
+/obj/machinery/disposal/MouseDrop_T(mob/target, mob/user)
+ if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
+ return
+ if(isanimal(user) && target != user) return //animals cannot put mobs other than themselves into disposal
+ src.add_fingerprint(user)
+ var/target_loc = target.loc
+ var/msg
+ for (var/mob/V in viewers(usr))
+ if(target == user && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
+ V.show_message("[usr] starts climbing into the disposal.", 3)
+ if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
+ if(target.anchored) return
+ V.show_message("[usr] starts stuffing [target.name] into the disposal.", 3)
+ if(!do_after(usr, 20))
+ return
+ if(target_loc != target.loc)
+ return
+ if(target == user && !user.stat && !user.weakened && !user.stunned && !user.paralysis) // if drop self, then climbed in
+ // must be awake, not stunned or whatever
+ msg = "[user.name] climbs into the [src]."
+ user << "You climb into the [src]."
+ else if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
+ msg = "[user.name] stuffs [target.name] into the [src]!"
+ user << "You stuff [target.name] into the [src]!"
- CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
- if (istype(mover,/obj/item) && mover.throwing)
- var/obj/item/I = mover
- if(istype(I, /obj/item/projectile))
- return
- if(prob(75))
- I.loc = src
- for(var/mob/M in viewers(src))
- M.show_message("\the [I] lands in \the [src].", 3)
- else
- for(var/mob/M in viewers(src))
- M.show_message("\the [I] bounces off of \the [src]'s rim!.", 3)
- return 0
+ 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. (JMP)")
+ else
+ return
+ if (target.client)
+ target.client.perspective = EYE_PERSPECTIVE
+ target.client.eye = src
+ target.loc = src
+
+ for (var/mob/C in viewers(src))
+ if(C == user)
+ continue
+ C.show_message(msg, 3)
+
+ update()
+ return
+
+// can breath normally in the disposal
+/obj/machinery/disposal/alter_health()
+ return get_turf(src)
+
+// attempt to move while inside
+/obj/machinery/disposal/relaymove(mob/user as mob)
+ if(user.stat || src.flushing)
+ return
+ src.go_out(user)
+ return
+
+// leave the disposal
+/obj/machinery/disposal/proc/go_out(mob/user)
+
+ if (user.client)
+ user.client.eye = user.client.mob
+ user.client.perspective = MOB_PERSPECTIVE
+ user.loc = src.loc
+ update()
+ return
+
+
+// monkeys can only pull the flush lever
+/obj/machinery/disposal/attack_paw(mob/user as mob)
+ if(stat & BROKEN)
+ return
+
+ flush = !flush
+ update()
+ return
+
+// ai as human but can't flush
+/obj/machinery/disposal/attack_ai(mob/user as mob)
+ interact(user, 1)
+
+// human interact with machine
+/obj/machinery/disposal/attack_hand(mob/user as mob)
+ if(user && user.loc == src)
+ usr << "\red You cannot reach the controls from inside."
+ return
+ /*
+ if(mode==-1)
+ usr << "\red The disposal units power is disabled."
+ return
+ */
+ interact(user, 0)
+
+// user interaction
+/obj/machinery/disposal/interact(mob/user, var/ai=0)
+
+ src.add_fingerprint(user)
+ if(stat & BROKEN)
+ user.unset_machine()
+ return
+
+ var/dat = "Waste Disposal UnitWaste Disposal Unit
"
+
+ if(!ai) // AI can't pull flush handle
+ if(flush)
+ dat += "Disposal handle: Disengage Engaged"
else
- return ..(mover, target, height, air_group)
+ dat += "Disposal handle: Disengaged Engage"
+
+ dat += "
Eject contents
"
+
+ if(mode <= 0)
+ dat += "Pump: Off On
"
+ else if(mode == 1)
+ dat += "Pump: Off On (pressurizing)
"
+ else
+ dat += "Pump: Off On (idle)
"
+
+ var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE)
+
+ dat += "Pressure: [round(per, 1)]%
"
+
+
+ user.set_machine(src)
+ user << browse(dat, "window=disposal;size=360x170")
+ onclose(user, "disposal")
+
+// handle machine interaction
+
+/obj/machinery/disposal/Topic(href, href_list)
+ if(usr.loc == src)
+ usr << "\red You cannot reach the controls from inside."
+ return
+
+ if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
+ usr << "\red The disposal units power is disabled."
+ return
+ ..()
+ src.add_fingerprint(usr)
+ if(stat & BROKEN)
+ return
+ if(usr.stat || usr.restrained() || src.flushing)
+ return
+
+ if (in_range(src, usr) && istype(src.loc, /turf))
+ usr.set_machine(src)
+
+ if(href_list["close"])
+ usr.unset_machine()
+ usr << browse(null, "window=disposal")
+ return
+
+ if(href_list["pump"])
+ if(text2num(href_list["pump"]))
+ mode = 1
+ else
+ mode = 0
+ update()
+
+ if(href_list["handle"])
+ flush = text2num(href_list["handle"])
+ update()
+
+ if(href_list["eject"])
+ eject()
+ else
+ usr << browse(null, "window=disposal")
+ usr.unset_machine()
+ return
+ return
+
+// eject the contents of the disposal unit
+/obj/machinery/disposal/proc/eject()
+ for(var/atom/movable/AM in src)
+ AM.loc = src.loc
+ AM.pipe_eject(0)
+ update()
+
+// update the icon & overlays to reflect mode & status
+/obj/machinery/disposal/proc/update()
+ overlays.Cut()
+ if(stat & BROKEN)
+ icon_state = "disposal-broken"
+ mode = 0
+ flush = 0
+ return
+
+ // flush handle
+ if(flush)
+ overlays += image('icons/obj/pipes/disposal.dmi', "dispover-handle")
+
+ // only handle is shown if no power
+ if(stat & NOPOWER || mode == -1)
+ return
+
+ // check for items in disposal - occupied light
+ if(contents.len > 0)
+ overlays += image('icons/obj/pipes/disposal.dmi', "dispover-full")
+
+ // charging and ready light
+ if(mode == 1)
+ overlays += image('icons/obj/pipes/disposal.dmi', "dispover-charge")
+ else if(mode == 2)
+ overlays += image('icons/obj/pipes/disposal.dmi', "dispover-ready")
+
+// timed process
+// charge the gas reservoir and perform flush if ready
+/obj/machinery/disposal/process()
+ if(!air_contents || (stat & BROKEN)) // nothing can happen if broken
+ update_use_power(0)
+ return
+
+ flush_count++
+ if( flush_count >= flush_every_ticks )
+ if( contents.len )
+ if(mode == 2)
+ spawn(0)
+ feedback_inc("disposal_auto_flush",1)
+ flush()
+ flush_count = 0
+
+ src.updateDialog()
+
+ if(flush && air_contents.return_pressure() >= SEND_PRESSURE ) // flush can happen even without power
+ flush()
+
+ if(mode != 1) // if off or ready, no need to charge
+ update_use_power(1)
+ return
+
+ // otherwise charge
+ src.pressurize()
+
+ // if full enough, switch to ready mode
+ if(air_contents.return_pressure() >= SEND_PRESSURE)
+ mode = 2
+ update()
+ return
+
+/obj/machinery/disposal/proc/pressurize()
+ if(stat & NOPOWER) // won't charge if no power
+ update_use_power(0)
+ return
+
+ var/atom/L = loc // recharging from loc turf
+ var/datum/gas_mixture/env = L.return_air()
+
+ var/power_draw = -1
+ if(env && env.temperature > 0)
+ var/transfer_moles = (PUMP_MAX_FLOW_RATE/env.volume)*env.total_moles //group_multiplier is divided out here
+ power_draw = pump_gas(src, env, air_contents, transfer_moles, active_power_usage)
+
+ if (power_draw < 0)
+ //update_use_power(0)
+ use_power = 1 //don't force update - easier on CPU
+ else
+ handle_power_draw(power_draw)
+
+// perform a flush
+/obj/machinery/disposal/proc/flush()
+
+ flushing = 1
+ flick("[icon_state]-flush", src)
+
+ var/wrapcheck = 0
+ var/obj/structure/disposalholder/H = new() // virtual holder object which actually
+ // travels through the pipes.
+ //Hacky test to get drones to mail themselves through disposals.
+ for(var/mob/living/silicon/robot/drone/D in src)
+ wrapcheck = 1
+
+ for(var/obj/item/smallDelivery/O in src)
+ wrapcheck = 1
+
+ if(wrapcheck == 1)
+ H.tomail = 1
+
+
+ air_contents = new() // new empty gas resv.
+
+ sleep(10)
+ if(last_sound < world.time + 1)
+ playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0)
+ last_sound = world.time
+ sleep(5) // wait for animation to finish
+
+
+ H.init(src) // copy the contents of disposer to holder
+
+ H.start(src) // start the holder processing movement
+ flushing = 0
+ // now reset disposal state
+ flush = 0
+ if(mode == 2) // if was ready,
+ mode = 1 // switch to charging
+ update()
+ return
+
+
+// called when area power changes
+/obj/machinery/disposal/power_change()
+ ..() // do default setting/reset of stat NOPOWER bit
+ update() // update icon
+ return
+
+
+// called when holder is expelled from a disposal
+// should usually only occur if the pipe network is modified
+/obj/machinery/disposal/proc/expel(var/obj/structure/disposalholder/H)
+
+ var/turf/target
+ playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
+ if(H) // Somehow, someone managed to flush a window which broke mid-transit and caused the disposal to go in an infinite loop trying to expel null, hopefully this fixes it
+ for(var/atom/movable/AM in H)
+ target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
+
+ AM.loc = src.loc
+ AM.pipe_eject(0)
+ if(!istype(AM,/mob/living/silicon/robot/drone)) //Poor drones kept smashing windows and taking system damage being fired out of disposals. ~Z
+ spawn(1)
+ if(AM)
+ AM.throw_at(target, 5, 1)
+
+ H.vent_gas(loc)
+ del(H)
+
+/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ if (istype(mover,/obj/item) && mover.throwing)
+ var/obj/item/I = mover
+ if(istype(I, /obj/item/projectile))
+ return
+ if(prob(75))
+ I.loc = src
+ for(var/mob/M in viewers(src))
+ M.show_message("\the [I] lands in \the [src].", 3)
+ else
+ for(var/mob/M in viewers(src))
+ M.show_message("\the [I] bounces off of \the [src]'s rim!.", 3)
+ return 0
+ else
+ return ..(mover, target, height, air_group)
// virtual disposal object
// travels through pipes in lieu of actual items