//disposal bin and Delivery chute. #define SEND_PRESSURE 0.05*ONE_ATMOSPHERE /obj/machinery/disposal icon = 'icons/obj/atmospherics/pipes/disposal.dmi' anchored = 1 density = 1 var/datum/gas_mixture/air_contents // internal reservoir var/mode = 1 // mode -1=screws removed 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. var/last_sound = 0 var/obj/structure/disposalconstruct/stored // create a new disposal // find the attached trunk (if present) and init gas resvr. /obj/machinery/disposal/New(loc, var/obj/structure/disposalconstruct/make_from) ..() if(make_from) dir = make_from.dir make_from.loc = 0 stored = make_from else stored = new /obj/structure/disposalconstruct(0,DISP_END_BIN,dir) trunk_check() air_contents = new/datum/gas_mixture() //gas.volume = 1.05 * CELLSTANDARD update() /obj/machinery/disposal/proc/trunk_check() trunk = locate() in src.loc if(!trunk) mode = 0 flush = 0 else mode = initial(mode) flush = initial(flush) trunk.linked = src // link the pipe trunk to self /obj/machinery/disposal/Destroy() eject() if(trunk) trunk.linked = null return ..() /obj/machinery/disposal/singularity_pull(S, current_size) if(current_size >= STAGE_FIVE) Deconstruct() /obj/machinery/disposal/initialize() // this will get a copy of the air turf and take a SEND PRESSURE amount of air from it var/atom/L = loc var/datum/gas_mixture/env = new env.copy_from(L.return_air()) var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1) air_contents.merge(removed) trunk_check() /obj/machinery/disposal/attackby(obj/item/I, mob/user, params) if(stat & BROKEN || !I || !user) return 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) mode=-1 else mode=0 playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) user << "You [mode==0?"attach":"remove"] the screws around the power connection." return else if(istype(I,/obj/item/weapon/weldingtool) && mode==-1) var/obj/item/weapon/weldingtool/W = I if(W.remove_fuel(0,user)) if(contents.len > 0) user << "Eject the items first!" return playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) user << "You start slicing the floorweld off \the [src]..." if(do_after(user,20/I.toolspeed, target = src)) if(!W.isOn()) return user << "You slice the floorweld off \the [src]." Deconstruct() return return 1 // mouse drop another mob or self /obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user) if(istype(target)) stuff_mob_in(target, user) /obj/machinery/disposal/proc/stuff_mob_in(mob/living/target, mob/living/user) if(!iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves. return if(!istype(user.loc, /turf/)) //No magically doing it from inside closets return if(target.buckled || target.buckled_mob) return if(target.mob_size > MOB_SIZE_HUMAN) user << "[target] doesn't fit inside [src]!" return add_fingerprint(user) if(user == target) user.visible_message("[user] starts climbing into [src].", \ "You start climbing into [src]...") else target.visible_message("[user] starts putting [target] into [src].", \ "[user] starts putting you into [src]!") if(do_mob(user, target, 20)) if (!loc) return target.forceMove(src) if(user == target) user.visible_message("[user] climbs into [src].", \ "You climb into [src].") else target.visible_message("[user] has placed [target] in [src].", \ "[user] has placed [target] in [src].") add_logs(user, target, "stuffed", addition="into [src]") target.LAssailant = user update() // can breath normally in the disposal /obj/machinery/disposal/alter_health() return get_turf(src) /obj/machinery/disposal/relaymove(mob/user) attempt_escape(user) // resist to escape the bin /obj/machinery/disposal/container_resist() attempt_escape(usr) /obj/machinery/disposal/proc/attempt_escape(mob/user) if(src.flushing) return go_out(user) return // leave the disposal /obj/machinery/disposal/proc/go_out(mob/user) user.loc = src.loc user.reset_perspective(null) update() return // monkeys and xenos can only pull the flush lever /obj/machinery/disposal/attack_paw(mob/user) if(stat & BROKEN) return flush = !flush update() // ai as human but can't flush /obj/machinery/disposal/attack_ai(mob/user) interact(user, 1) // human interact with machine /obj/machinery/disposal/attack_hand(mob/user) if(user && user.loc == src) usr << "You cannot reach the controls from inside!" return /* if(mode==-1) usr << "\red The disposal units power is disabled." return */ interact(user, 0) // hostile mob escape from disposals /obj/machinery/disposal/attack_animal(mob/living/simple_animal/M) if(M.environment_smash) M.do_attack_animation(src) visible_message("[M.name] smashes \the [src] apart!") qdel(src) return // eject the contents of the disposal unit /obj/machinery/disposal/proc/eject() var/turf/T = get_turf(src) for(var/atom/movable/AM in src) AM.forceMove(T) AM.pipe_eject(0) update() // update the icon & overlays to reflect mode & status /obj/machinery/disposal/proc/update() return /obj/machinery/disposal/proc/flush() flushing = 1 flushAnimation() sleep(10) if(last_sound < world.time + 1) playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) last_sound = world.time sleep(5) if(qdeleted(src)) return var/obj/structure/disposalholder/H = new() newHolderDestination(H) H.init(src) air_contents = new() H.start(src) flushing = 0 flush = 0 /obj/machinery/disposal/bin/flush() ..() if(mode == 2) mode = 1 update() /obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H) for(var/obj/item/smallDelivery/O in src) H.tomail = 1 return /obj/machinery/disposal/proc/flushAnimation() flick("[icon_state]-flush", src) // 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(obj/structure/disposalholder/H) var/turf/T = get_turf(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)) AM.forceMove(T) AM.pipe_eject(0) AM.throw_at_fast(target, 5, 1) H.vent_gas(loc) qdel(H) /obj/machinery/disposal/Deconstruct() if(stored) var/turf/T = loc stored.loc = T src.transfer_fingerprints_to(stored) stored.anchored = 0 stored.density = 1 stored.update() ..() //How disposal handles getting a storage dump from a storage object /obj/machinery/disposal/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user) for(var/obj/item/I in src_object) if(user.s_active != src_object) if(I.on_found(user)) return src_object.remove_from_storage(I, src) return 1 // 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 /obj/machinery/disposal/bin name = "disposal unit" desc = "A pneumatic waste disposal unit." icon_state = "disposal" // attack by item places it in to disposal /obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params) if(!..()) return if(istype(I, /obj/item/weapon/storage/bag/trash)) var/obj/item/weapon/storage/bag/trash/T = I user << "You empty the bag." for(var/obj/item/O in T.contents) T.remove_from_storage(O,src) T.update_icon() update() return if(!user.drop_item()) return I.loc = src user.visible_message("[user.name] places \the [I] into \the [src].", \ "You place \the [I] into \the [src].") update() // user interaction /obj/machinery/disposal/bin/interact(mob/user, 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 = Clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100) 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/bin/Topic(href, href_list) if(..()) return if(usr.loc == src) usr << "You cannot reach the controls from inside!" return if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1 usr << "\The [src]'s power is disabled." return ..() 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() return /obj/machinery/disposal/bin/CanPass(atom/movable/mover, turf/target, height=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 visible_message("\the [I] lands in \the [src].") update() else visible_message("\the [I] bounces off of \the [src]'s rim!") return 0 else return ..(mover, target, height) /obj/machinery/disposal/bin/update() overlays.Cut() if(stat & BROKEN) mode = 0 flush = 0 return // flush handle if(flush) overlays += image('icons/obj/atmospherics/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/atmospherics/pipes/disposal.dmi', "dispover-full") // charging and ready light if(mode == 1) overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-charge") else if(mode == 2) overlays += image('icons/obj/atmospherics/pipes/disposal.dmi', "dispover-ready") // timed process // charge the gas reservoir and perform flush if ready /obj/machinery/disposal/bin/process() if(stat & BROKEN) // nothing can happen if broken 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 spawn(0) flush() if(stat & NOPOWER) // won't charge if no power return use_power(100) // base power usage if(mode != 1) // if off or ready, no need to charge return // otherwise charge use_power(500) // charging power usage 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_update_turf() // if full enough, switch to ready mode if(air_contents.return_pressure() >= SEND_PRESSURE) mode = 2 update() return /obj/machinery/disposal/bin/get_remote_view_fullscreens(mob/user) if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS))) user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 2) //Delivery Chute /obj/machinery/disposal/deliveryChute name = "delivery chute" desc = "A chute for big and small packages alike!" density = 1 icon_state = "intake" mode = 0 // the chute doesn't need charging and always works /obj/machinery/disposal/deliveryChute/New(loc,var/obj/structure/disposalconstruct/make_from) ..() stored.ptype = DISP_END_CHUTE spawn(5) trunk = locate() in loc if(trunk) trunk.linked = src // link the pipe trunk to self /obj/machinery/disposal/deliveryChute/Bumped(atom/movable/AM) //Go straight into the chute if(!AM.disposalEnterTry()) return switch(dir) if(NORTH) if(AM.loc.y != loc.y+1) return if(EAST) if(AM.loc.x != loc.x+1) return if(SOUTH) if(AM.loc.y != loc.y-1) return if(WEST) if(AM.loc.x != loc.x-1) return if(istype(AM, /obj)) var/obj/O = AM O.loc = src else if(istype(AM, /mob)) var/mob/M = AM if(prob(2)) // to prevent mobs being stuck in infinite loops M << "You hit the edge of the chute." return M.forceMove(src) flush() /atom/movable/proc/disposalEnterTry() return 1 /obj/item/projectile/disposalEnterTry() return /obj/effect/disposalEnterTry() return /obj/mecha/disposalEnterTry() return /obj/machinery/disposal/deliveryChute/newHolderDestination(obj/structure/disposalholder/H) H.destinationTag = 1