diff --git a/code/__defines/dcs/signals/signals_disposals.dm b/code/__defines/dcs/signals/signals_disposals.dm index be5b57eff0..d53bd9d744 100644 --- a/code/__defines/dcs/signals/signals_disposals.dm +++ b/code/__defines/dcs/signals/signals_disposals.dm @@ -1,11 +1,20 @@ ///called when a disposal connected object flushes its contents into the disposal pipe network #define COMSIG_DISPOSAL_FLUSH "disposal_system_flushing" -///called when a disposal connected object gets a packet from the disposal pipe network -#define COMSIG_DISPOSAL_RECEIVING "disposal_system_receiving" +///called when a disposal trunk attempts to send a packet, to be recieved by an atom with a disposal network connection component. +#define COMSIG_DISPOSAL_SEND "disposal_system_sending" -///called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, obj/machinery/disposal/source) +///called when a disposal connected object recieves an object from it's connected trunk +#define COMSIG_DISPOSAL_RECEIVE "disposal_system_receiving" + +///called when the movable is added to a disposal holder object for disposal movement: (obj/structure/disposalholder/holder, atom/source) //#define COMSIG_MOVABLE_DISPOSING "movable_disposing" //This is in signals_atom_movable.dm but kept here for housekeeping. ///Called right after the atom is flushed into a disposal holder and sent through the disposal network: (/obj/structure/disposalholder) #define COMSIG_ATOM_DISPOSAL_FLUSHED "atom_disposal_flushed" + +///called when a disposal connected object attempts to link to a trunk: (/obj/structure/disposalpipe/trunk) +#define COMSIG_DISPOSAL_LINK "disposal_system_linkage" + +///called when a disposal connected object should unlink from a trunk it's attached to. +#define COMSIG_DISPOSAL_UNLINK "disposal_system_unlink" diff --git a/code/datums/autolathe/tools.dm b/code/datums/autolathe/tools.dm index 698cbe1001..f3166f445d 100644 --- a/code/datums/autolathe/tools.dm +++ b/code/datums/autolathe/tools.dm @@ -63,3 +63,8 @@ /datum/category_item/autolathe/tools/rsf name = "rapid service fabricator" path = /obj/item/rsf + +/datum/category_item/autolathe/tools/dest_tagger + name = "destination tagger" + path = /obj/item/destTagger + resources = list(MAT_STEEL = 250, MAT_GLASS = 125) diff --git a/code/datums/components/machinery/disposal_connection.dm b/code/datums/components/machinery/disposal_connection.dm index 57a0c7e81e..47b3160d11 100644 --- a/code/datums/components/machinery/disposal_connection.dm +++ b/code/datums/components/machinery/disposal_connection.dm @@ -1,75 +1,104 @@ ///Disposal connection component, allows an atom to recieve and send disposal packages if attached to a disposal trunk. /datum/component/disposal_system_connection - VAR_PROTECTED/obj/disposal_owner = null + //The connected trunk. Also determines if we're linked already or not. + var/obj/structure/disposalpipe/trunk/connected_trunk = null -/datum/component/disposal_system_connection/Initialize() + var/atom/disposal_owner + /// The proc that the owner has that'll accept a list of items from recieved disposal packets. + var/visible_connection + +/datum/component/disposal_system_connection/Initialize(visibly_connects = TRUE) + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + if(isarea(parent)) + return COMPONENT_INCOMPATIBLE disposal_owner = parent - RegisterSignal(disposal_owner, COMSIG_DISPOSAL_FLUSH, PROC_REF(on_flush)) - RegisterSignal(disposal_owner, COMSIG_DISPOSAL_RECEIVING, PROC_REF(on_recieve)) - RegisterSignal(disposal_owner, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + visible_connection = visibly_connects /datum/component/disposal_system_connection/Destroy() - UnregisterSignal(disposal_owner, COMSIG_DISPOSAL_FLUSH) - UnregisterSignal(disposal_owner, COMSIG_DISPOSAL_RECEIVING) - UnregisterSignal(disposal_owner, COMSIG_ATOM_EXAMINE) - disposal_owner = null + if(connected_trunk) + UnregisterSignal(connected_trunk, COMSIG_DISPOSAL_SEND) + connected_trunk = null . = ..() + disposal_owner = null + +/datum/component/disposal_system_connection/RegisterWithParent() + RegisterSignal(disposal_owner, COMSIG_DISPOSAL_FLUSH, PROC_REF(on_flush)) + RegisterSignal(disposal_owner, COMSIG_DISPOSAL_LINK, PROC_REF(link_to_trunk)) + RegisterSignal(disposal_owner, COMSIG_DISPOSAL_UNLINK, PROC_REF(unlink_from_trunk)) + RegisterSignal(disposal_owner, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + + +/datum/component/disposal_system_connection/UnregisterFromParent() + UnregisterSignal(disposal_owner, COMSIG_DISPOSAL_FLUSH) + UnregisterSignal(disposal_owner, COMSIG_DISPOSAL_LINK) + UnregisterSignal(disposal_owner, COMSIG_DISPOSAL_UNLINK) + UnregisterSignal(disposal_owner, COMSIG_ATOM_EXAMINE) + // Signal handling /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/component/disposal_system_connection/proc/on_flush(datum/source,datum/gas_mixture/flush_gas) +/datum/component/disposal_system_connection/proc/on_flush(datum/source, list/flushed_items, datum/gas_mixture/flush_gas) SIGNAL_HANDLER SHOULD_NOT_OVERRIDE(TRUE) - if(!can_accept()) - return FALSE // Important note, the flush_gas will be passed to the disposal packet when it's made. Caller should make a fresh gasmix datum after flushing this one! - return handle_flush(flush_gas) + return handle_flush(flushed_items, flush_gas) -/datum/component/disposal_system_connection/proc/on_recieve(datum/source,obj/structure/disposalholder/packet) +/datum/component/disposal_system_connection/proc/link_to_trunk(datum/source, obj/structure/disposalpipe/trunk/trunk) SIGNAL_HANDLER SHOULD_NOT_OVERRIDE(TRUE) - if(!can_accept()) + if(!trunk) return FALSE + if(trunk.linked) //Already linked to something + return FALSE + connected_trunk = trunk + trunk.linked = disposal_owner + RegisterSignal(trunk, COMSIG_DISPOSAL_SEND, PROC_REF(on_recieve)) + +/datum/component/disposal_system_connection/proc/unlink_from_trunk(datum/source) + SIGNAL_HANDLER + SHOULD_NOT_OVERRIDE(TRUE) + if(connected_trunk) + UnregisterSignal(connected_trunk, COMSIG_DISPOSAL_SEND) + connected_trunk = null + +/datum/component/disposal_system_connection/proc/on_recieve(datum/source, obj/structure/disposalholder/packet) + SIGNAL_HANDLER + SHOULD_NOT_OVERRIDE(TRUE) return handle_expel(packet) /datum/component/disposal_system_connection/proc/on_examine(datum/source, mob/user, list/examine_texts) SIGNAL_HANDLER - var/has_connection = FALSE - if(can_accept() && (locate(/obj/structure/disposalpipe/trunk) in get_turf(disposal_owner))) - has_connection = TRUE - examine_texts += span_notice("It [has_connection ? "is connected" : "can be connected"] to a disposal pipe network.") + if(!visible_connection) + return + examine_texts += span_notice("It [connected_trunk ? "is connected" : "can be connected"] to a disposal pipe network.") // Flush handling, can be override by subtypes but excepts parent proc to handle core logic /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/component/disposal_system_connection/proc/handle_flush(datum/gas_mixture/flush_gas) +/datum/component/disposal_system_connection/proc/handle_flush(list/flushed_items, datum/gas_mixture/flush_gas) PROTECTED_PROC(TRUE) SHOULD_CALL_PARENT(TRUE) var/obj/structure/disposalholder/packet = new() // virtual holder object which actually travels through the pipes. - packet.init(get_flushed_item_list(), flush_gas) - finish_flush(packet) - return TRUE + packet.init(flushed_items, flush_gas) -/datum/component/disposal_system_connection/proc/finish_flush(obj/structure/disposalholder/packet) - PROTECTED_PROC(TRUE) - SHOULD_CALL_PARENT(TRUE) // if no trunk connected, expel immediately - var/obj/structure/disposalpipe/trunk/trunk = locate() in get_turf(disposal_owner) - if(!trunk) + if(!connected_trunk) handle_expel(packet) - return + return TRUE // start the holder processing movement - packet.forceMove(trunk) + packet.forceMove(connected_trunk) packet.active = TRUE packet.set_dir(DOWN) packet.move() + return TRUE + // Expel handling, can be override by subtypes but excepts parent proc to handle core logic /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/component/disposal_system_connection/proc/handle_expel(obj/structure/disposalholder/packet, delay_time = 0) +/datum/component/disposal_system_connection/proc/handle_expel(obj/structure/disposalholder/packet) // Returns true if our owner could handle this packet, used by our child procs to animate our owner. PROTECTED_PROC(TRUE) - SHOULD_CALL_PARENT(TRUE) if(!packet || QDELETED(packet)) return FALSE @@ -82,71 +111,5 @@ var/datum/gas_mixture/gas = new() gas.copy_from(packet.gas) qdel(packet) - - // Handle expelling stuff, most things have a delay before ejecting. - if(delay_time <= 0) // Someone is going to pass a negative, I just know it. No, BAD, cutting this off before it gets the chance. - expel_finish(expelled_items, gas) - else - addtimer(CALLBACK(src, PROC_REF(expel_finish), expelled_items, gas), delay_time, TIMER_DELETE_ME) + SEND_SIGNAL(disposal_owner, COMSIG_DISPOSAL_RECEIVE, expelled_items, gas) return TRUE - -/datum/component/disposal_system_connection/proc/expel_finish(list/expelled_items,datum/gas_mixture/gas) - PROTECTED_PROC(TRUE) - SHOULD_CALL_PARENT(TRUE) - // This proc has some checks just incase we have a subtype that wants to handle expelled items or if it vents gasses itself. - // This way it can just pass nulls to this parent proc if it does it's own handling for those things. Like a machine that eats all stuff dumped into it instead of ejecting. - - // Drop all those items - if(expelled_items.len) - var/turf/target = get_expel_target() - for(var/atom/movable/AM in expelled_items) - if(QDELETED(AM)) - continue - AM.forceMove(get_turf(disposal_owner)) - AM.pipe_eject(disposal_owner.dir) - if(istype(AM,/mob/living/silicon/robot/drone)) //Drones keep smashing windows from being fired out of chutes. Bad for the station. ~Z - continue - AM.throw_at(target, 3, 1) - expelled_items.Cut() - - // vent gasses to turf - if(gas) - if(gas.return_pressure() > 0) - playsound(disposal_owner, 'sound/machines/hiss.ogg', 50, 0, 0) - var/turf/T = get_turf(disposal_owner) - if(T) - T.assume_air(gas) - qdel(gas) - -// Overridable procs for easily customizing subtypes -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// Override this to add additional checks if an object can flush or accept incoming packets -/datum/component/disposal_system_connection/proc/can_accept() - PROTECTED_PROC(TRUE) - return disposal_owner.anchored - -/// Override this to launch items in a specific direction -/datum/component/disposal_system_connection/proc/get_expel_target() - PROTECTED_PROC(TRUE) - return get_offset_target_turf(get_turf(disposal_owner), rand(5)-rand(5), rand(5)-rand(5)) - -/// Override this to give a custom list of items to flush instead of just the contents of the owner -/datum/component/disposal_system_connection/proc/get_flushed_item_list() - PROTECTED_PROC(TRUE) - return disposal_owner.contents - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Subtypes for handling how things are animated, if items are spat out, or deciding what items inside an object are flushed -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Disposal outlets, needs to animate with a timed buzzer before stuff ejects -/datum/component/disposal_system_connection/disposaloutlet/handle_expel(obj/structure/disposalholder/packet, delay_time) - . = ..(packet,3 SECONDS) - if(.) - flick("outlet-open", disposal_owner) - playsound(disposal_owner, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) - -/datum/component/disposal_system_connection/disposaloutlet/get_expel_target() - return get_ranged_target_turf(get_turf(disposal_owner), disposal_owner.dir, 10) diff --git a/code/datums/components/traits/unlucky.dm b/code/datums/components/traits/unlucky.dm index a59a5b1e64..d28ef3ef8e 100644 --- a/code/datums/components/traits/unlucky.dm +++ b/code/datums/components/traits/unlucky.dm @@ -195,7 +195,7 @@ our_guy.visible_message(span_danger("[our_guy] slips on a spill near the [evil_disposal] and falls in!"), span_boldwarning("You slip on a spill near the [evil_disposal] and fall in!")) living_guy.forceMove(evil_disposal) evil_disposal.flush = TRUE - evil_disposal.update() + evil_disposal.update_icon() living_guy.Stun(5) consume_omen() return diff --git a/code/game/objects/stumble_into_vr.dm b/code/game/objects/stumble_into_vr.dm index 43206c743e..911bd23262 100644 --- a/code/game/objects/stumble_into_vr.dm +++ b/code/game/objects/stumble_into_vr.dm @@ -28,7 +28,7 @@ M.Weaken(2) M.forceMove(src) M.stop_flying() - update() + update_icon() /obj/structure/inflatable/stumble_into(mob/living/M) playsound(src, "sound/effects/Glasshit.ogg", 25, 1, -1) diff --git a/code/modules/recycling/disposal_bin_subtypes.dm b/code/modules/recycling/disposal_bin_subtypes.dm index 0df64a3b63..851e512054 100644 --- a/code/modules/recycling/disposal_bin_subtypes.dm +++ b/code/modules/recycling/disposal_bin_subtypes.dm @@ -23,12 +23,12 @@ // Incin/space /obj/machinery/disposal/burn_pit - name = "disposal(hazardous)" + name = "disposal (hazardous)" desc = "A pneumatic waste disposal unit. This unit is either connected directly to the station's waste processor or dumped into space." icon_state = "red" /obj/machinery/disposal/wall/burn_pit - name = "disposal(hazardous)" + name = "disposal (hazardous)" desc = "A pneumatic waste disposal unit. This unit is either connected directly to the station's waste processor or dumped into space." icon_state = "redwall" diff --git a/code/modules/recycling/disposal_holder.dm b/code/modules/recycling/disposal_holder.dm index de9855acb0..64fcd10c30 100644 --- a/code/modules/recycling/disposal_holder.dm +++ b/code/modules/recycling/disposal_holder.dm @@ -14,6 +14,19 @@ flags = REMOTEVIEW_ON_ENTER dir = 0 +/obj/structure/disposalholder/Destroy() + QDEL_NULL(gas) + if(contents.len) + var/turf/qdelloc = get_turf(src) + if(qdelloc) + for(var/atom/movable/AM in contents) + AM.forceMove(qdelloc) + else + log_runtime("A disposal holder was deleted with contents in nullspace") //ideally, this should never happen + + active = FALSE + return ..() + // initialize a holder from the contents of a disposal unit /obj/structure/disposalholder/proc/init(list/flush_list, datum/gas_mixture/flush_gas) gas = flush_gas// transfer gas resv. into holder object -- let's be explicit about the data this proc consumes, please. @@ -23,6 +36,7 @@ for(var/mob/living/M in flush_list) if(M.stat != DEAD && !istype(M,/mob/living/silicon/robot/drone)) hasmob = TRUE + break //Checks 1 contents level deep. This means that players can be sent through disposals... //...but it should require a second person to open the package. (i.e. person inside a wrapped locker) @@ -32,21 +46,23 @@ for(var/mob/living/M in O.contents) if(M && M.stat != DEAD && !istype(M,/mob/living/silicon/robot/drone)) hasmob = TRUE + break // now everything inside the disposal gets put into the holder // note AM since can contain mobs or objs for(var/atom/movable/AM in flush_list) AM.forceMove(src) // Mail will use it's sorting tag if dropped into disposals - if(istype(AM, /obj/structure/bigDelivery) && !hasmob) - var/obj/structure/bigDelivery/T = AM - src.destinationTag = T.sortTag - if(istype(AM, /obj/item/smallDelivery) && !hasmob) - var/obj/item/smallDelivery/T = AM - src.destinationTag = T.sortTag - if(istype(AM, /obj/item/mail) && !hasmob) - var/obj/item/mail/T = AM - src.destinationTag = T.sortTag + if(!hasmob) + if(istype(AM, /obj/structure/bigDelivery)) + var/obj/structure/bigDelivery/T = AM + src.destinationTag = T.sortTag + if(istype(AM, /obj/item/smallDelivery)) + var/obj/item/smallDelivery/T = AM + src.destinationTag = T.sortTag + if(istype(AM, /obj/item/mail)) + var/obj/item/mail/T = AM + src.destinationTag = T.sortTag // Drones can mail themselves through maint. if(istype(AM, /mob/living/silicon/robot/drone)) var/mob/living/silicon/robot/drone/drone = AM @@ -112,37 +128,40 @@ else partialTag = new_tag +// Nolonger shall you be stuck forever in the tubes. ...It might just hurt a bit. +/obj/structure/disposalholder/container_resist(mob/living/escapee) + . = ..() + if(!istype(loc, /obj/structure/disposalpipe)) + return //Somehow we're not in a pipe, shits probably fucked + var/obj/structure/disposalpipe/transport_cylinder = loc + if(active) + return + to_chat(escapee, span_warning("You push against the thin pipe walls...")) + playsound(loc, 'sound/machines/door/airlock_creaking.ogg', 30, FALSE, 3) //yeah I know but at least it sounds like metal being bent. + + if(!do_after(escapee, 20 SECONDS, transport_cylinder)) + return + for(var/mob/living/jailbird in contents) + jailbird.apply_damage(rand(5,15), BRUTE) + transport_cylinder.expel(src, get_turf(loc), NONE) //Direction: NONE, this makes the stuff spew everywhere (lol) // called when player tries to move while in a pipe /obj/structure/disposalholder/relaymove(mob/living/user) if(!isliving(user)) return - - if(user.stat || user.last_special <= world.time) + // If someone has sent you here to add a delay to this proc, inform them that it is a bug with /relaymove + // it's a minor bug, but it results in the proc being called much more frequently than it should, and when the bug is fixed the delay will work properly. + if(user.stat) return - user.last_special = world.time+100 if(QDELETED(src)) return for(var/mob/M in hearers(get_turf(src))) - to_chat(M, "CLONG, clong!") + M.show_message("CLONG, clong!", AUDIBLE_MESSAGE) playsound(src, 'sound/effects/clang.ogg', 50, 0, 0) - // called to vent all gas in holder to a location +// called to vent all gas in holder to a location /obj/structure/disposalholder/proc/vent_gas(atom/location) location.assume_air(gas) // vent all gas to turf return - -/obj/structure/disposalholder/Destroy() - QDEL_NULL(gas) - if(contents.len) - var/turf/qdelloc = get_turf(src) - if(qdelloc) - for(var/atom/movable/AM in contents) - AM.forceMove(qdelloc) - else - log_and_message_admins("A disposal holder was deleted with contents in nullspace") //ideally, this should never happen - - active = FALSE - return ..() diff --git a/code/modules/recycling/disposal_machines.dm b/code/modules/recycling/disposal_machines.dm index 350beac682..8803673b6b 100644 --- a/code/modules/recycling/disposal_machines.dm +++ b/code/modules/recycling/disposal_machines.dm @@ -27,6 +27,7 @@ var/flushing = FALSE // 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 active_power_usage = 2200 //the pneumatic pump power. 3 HP ~ 2200W idle_power_usage = 100 var/stat_tracking = TRUE @@ -34,22 +35,37 @@ // create a new disposal // find the attached trunk (if present) and init gas resvr. -/obj/machinery/disposal/Initialize(mapload) +/obj/machinery/disposal/Initialize(mapload, obj/structure/disposalconstruct/make_from) . = ..() - var/obj/structure/disposalpipe/trunk/trunk = locate() in loc - if(!trunk) + if(make_from) + set_dir(make_from.dir) + /* //I dont wanna set this up yet. + make_from.moveToNullspace() + stored = make_from + */ + qdel(make_from) mode = DISPOSALMODE_OFF - flush = FALSE + + var/obj/structure/disposalpipe/trunk/trunk = locate() in loc + + AddComponent(/datum/component/disposal_system_connection) + RegisterSignal(src, COMSIG_DISPOSAL_RECEIVE, PROC_REF(expel)) + if(trunk) + SEND_SIGNAL(src, COMSIG_DISPOSAL_LINK, trunk) air_contents = new(PRESSURE_TANK_VOLUME) - update() - AddComponent(/datum/component/disposal_system_connection) + update_icon() /obj/machinery/disposal/Destroy() eject() return ..() +/obj/machinery/disposal/singularity_pull(S, current_size) + ..() + if(current_size >= STAGE_FIVE) + deconstruct() + // attack by item places it in to disposal /obj/machinery/disposal/attackby(obj/item/I, mob/user) if(stat & BROKEN || !I || !user) @@ -86,13 +102,7 @@ if(do_after(user, 2 SECONDS * W.toolspeed, target = src)) if(!src || !W.isOn()) return to_chat(user, "You sliced the floorweld off the disposal unit.") - var/obj/structure/disposalconstruct/C = new (get_turf(src)) - transfer_fingerprints_to(C) - C.ptype = 6 // 6 = disposal unit - C.anchored = TRUE - C.density = TRUE - C.update() - qdel(src) + deconstruct() return else to_chat(user, "You need more welding fuel to complete this task.") @@ -105,7 +115,7 @@ for(var/obj/item/O in T.contents) T.remove_from_storage(O,src) T.update_icon() - update() + update_icon() return if(istype(I, /obj/item/material/ashtray)) @@ -115,7 +125,7 @@ for(var/obj/item/O in A.contents) O.forceMove(src) A.update_icon() - update() + update_icon() return var/obj/item/grab/G = I @@ -123,7 +133,7 @@ if(ismob(G.affecting)) var/mob/GM = G.affecting for (var/mob/V in viewers(user)) - V.show_message("[user] starts putting [GM.name] into the disposal.", 3) + V.visible_message("[user] starts putting [GM.name] into the disposal.", 3) if(do_after(user, 2 SECONDS, target = src)) GM.forceMove(src) for (var/mob/C in viewers(src)) @@ -143,14 +153,22 @@ if(istype(I, /obj/item/holder)) var/obj/item/holder/holder = I var/mob/victim = holder.held_mob - if(ishuman(victim) || victim.client) - log_and_message_admins("placed [victim] inside \the [src]", user) + if(victim.client) + log_and_message_admins("placed [victim] inside \the [src]", user) victim.forceMove(src) + qdel(I) + user.visible_message( + span_danger("[user] tosses \the [victim] into \the [src]."), + span_danger("You toss \the [victim] into \the [src]."), + span_warning("Pr-Thunk") + ) + update_icon() + return 1 I.forceMove(src) user.visible_message("[user] places \the [I] into the [src].", "You place \the [I] into the [src].","Ca-Clunk") - update() + update_icon() // Transform into next machine type /obj/machinery/disposal/proc/alter_bin_type(mob/user) @@ -226,7 +244,7 @@ new_bin.stat = stat new_bin.dir = new_dir new_bin.mode = mode - new_bin.update() // sets up wall outlets + new_bin.update_icon() // sets up wall outlets new_bin.update_icon() new_bin.visible_message("\The [src] reconfigures into \a [new_bin]!") // Effects @@ -241,71 +259,66 @@ // mouse drop another mob or self // -/obj/machinery/disposal/MouseDrop_T(mob/target, mob/user) +/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) + //animals cannot put mobs other than themselves into disposal + if(isanimal(user) && target != user) + return if(user.stat || !user.canmove || !istype(target)) return if(target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1) return - //animals cannot put mobs other than themselves into disposal - if(isanimal(user) && target != user) - return - add_fingerprint(user) - var/target_loc = target.loc - var/msg - for (var/mob/V in viewers(user)) - if(target == user && !user.stat && !user.weakened && !user.stunned && !user.paralysis) - V.show_message("[user] 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("[user] starts stuffing [target.name] into the disposal.", 3) - if(!do_after(user, 2 SECONDS, target)) - 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]." - to_chat(user, "You climb into the [src].") - log_and_message_admins("climbed into disposals!", user) - else if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis) - msg = "[user.name] stuffs [target.name] into the [src]!" - to_chat(user, "You stuff [target.name] into the [src]!") - - add_attack_logs(user,target,"Disposals dunked") + if(user == target) + user.visible_message("[user] starts climbing into [src]") else - return + target.visible_message(span_danger("[user] starts stuffing [target] into [src]."), span_userdanger("[user] starts stuffing you into [src]!")) - target.forceMove(src) - - for (var/mob/C in viewers(src)) - if(C == user) - continue - C.show_message(msg, 3) - - update() - return + if(do_after(user, 2 SECONDS, target)) + if(!loc) + return + target.forceMove(src) + if(user == target) + user.visible_message("[user] climbs into [src].", span_notice("You climb into [src]")) + log_and_message_admins("climbed into disposals!", user) + else + target.visible_message(span_danger("[user] stuffs [target] into \the [src]."), span_userdanger("[user] stuffs [target] into \the [src].")) + add_attack_logs(user,target,"Disposals dunked") + update_icon() // attempt to move while inside /obj/machinery/disposal/relaymove(mob/user) + attempt_escape(user) + +// resist to escape the bin +/obj/machinery/disposal/container_resist(mob/living/user) + attempt_escape(user) + +/obj/machinery/disposal/proc/attempt_escape(mob/user) if(user.stat || flushing) return - if(user.loc == src) - go_out(user) - return + go_out(user) // leave the disposal /obj/machinery/disposal/proc/go_out(mob/user) user.forceMove(get_turf(src)) - update() - return + update_icon() // ai as human but can't flush /obj/machinery/disposal/attack_ai(mob/user) add_hiddenprint(user) tgui_interact(user) - +/* +/obj/machinery/disposal/attack_paw() + if(stat & BROKEN) + return + flush = !flush + update_icon() +*/ // human interact with machine /obj/machinery/disposal/attack_hand(mob/user) if(stat & BROKEN) @@ -320,9 +333,19 @@ tgui_interact(user) else flush = !flush - update() + update_icon() return +/obj/machinery/disposal/click_alt(mob/user) + /* + if(user.canUseTopic) //Later... + return + */ + if(get_dist(user, src) > 1 || user.stat) //Until the above exists... + return + flush = !flush + update_icon() + // user interaction /obj/machinery/disposal/tgui_interact(mob/user, datum/tgui/ui = null) ui = SStgui.try_update_ui(user, src, ui) @@ -360,22 +383,22 @@ if(flushing) return - if(isturf(loc)) - if(action == "pumpOn") + switch(action) + if("pumpOn") mode = DISPOSALMODE_CHARGING - update() - if(action == "pumpOff") + update_icon() + if("pumpOff") mode = DISPOSALMODE_OFF - update() + update_icon() - if(action == "engageHandle") + if("engageHandle") flush = TRUE - update() - if(action == "disengageHandle") + update_icon() + if("disengageHandle") flush = FALSE - update() + update_icon() - if(action == "eject") + if("eject") eject() return TRUE @@ -394,10 +417,10 @@ for(var/atom/movable/AM in src) AM.forceMove(get_turf(src)) AM.pipe_eject(0) - update() + update_icon() // update the icon & overlays to reflect mode & status -/obj/machinery/disposal/proc/update() +/obj/machinery/disposal/update_icon() cut_overlays() if(stat & BROKEN) icon_state = "disposal-broken" @@ -446,7 +469,7 @@ update_use_power(USE_POWER_IDLE) else if(air_contents.return_pressure() >= SEND_PRESSURE) mode = DISPOSALMODE_CHARGED //if full enough, switch to ready mode - update() + update_icon() else pressurize() //otherwise charge @@ -468,61 +491,119 @@ // perform a flush /obj/machinery/disposal/proc/flush() - if(flushing) - return - - // We don't ever want digestion remains going through disposals, but people understandably thing they're doing right by trashing them - // So let's just delete them instead! - for(var/obj/item/digestion_remains/flushed_item in src) - qdel(flushed_item) - flushing = TRUE - flick("[icon_state]-flush", src) - // wait for animation to finish - addtimer(CALLBACK(src, PROC_REF(flush_animation)), 1 SECOND, TIMER_DELETE_ME) + flush_animation() + //Bit of a nasty way to do this. But sleep()s are nastier. + addtimer(CALLBACK(src, PROC_REF(flush_startup)), 1 SECOND) /obj/machinery/disposal/proc/flush_animation() PROTECTED_PROC(TRUE) - // wait for animation to finish - playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) - addtimer(CALLBACK(src, PROC_REF(flush_resolve)), 0.5 SECOND, TIMER_DELETE_ME) + flick("[icon_state]-flush", src) + +/obj/machinery/disposal/proc/flush_startup() + PROTECTED_PROC(TRUE) + if(last_sound < world.time + 1) + playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) + last_sound = world.time + addtimer(CALLBACK(src, PROC_REF(flush_complete)), 0.5 SECONDS) // wait for animation to finish + +/obj/machinery/disposal/proc/flush_complete() + PROTECTED_PROC(TRUE) + if(QDELETED(src)) + return + // We don't ever want digestion remains going through disposals, but people understandably thing they're doing right by trashing them + // So let's just delete them instead! + for(var/obj/item/digestion_remains/bone in src) + qdel(bone) + + var/list/flushed_items = list() + for(var/atom/movable/AM in src) + flushed_items += AM -/obj/machinery/disposal/proc/flush_resolve() - SEND_SIGNAL(src,COMSIG_DISPOSAL_FLUSH,air_contents) - air_contents = new(PRESSURE_TANK_VOLUME) // new empty gas resv. Disposal packet takes ownership of the original one! if(stat_tracking) GLOB.disposals_flush_shift_roundstat++ + + if(!SEND_SIGNAL(src, COMSIG_DISPOSAL_FLUSH, flushed_items, air_contents)) //If the signal isnt recieved, we'll just expel immediately. + if(length(contents)) + expel(flushed_items) + + air_contents = new(PRESSURE_TANK_VOLUME) // new empty gas resv. Disposal packet takes ownership of the original one! flushing = FALSE // now reset disposal state flush = FALSE if(mode == DISPOSALMODE_CHARGED) // if was ready, mode = DISPOSALMODE_CHARGING // switch to charging - update() - return + + update_icon() // called when area power changes /obj/machinery/disposal/power_change() ..() // do default setting/reset of stat NOPOWER bit - update() // update icon + update_icon() // update icon return -/obj/machinery/disposal/hitby(atom/movable/source, datum/thrownthing/throwingdatum) - . = ..() - if(isitem(source) && !istype(source, /obj/item/projectile)) - if(prob(75)) - source.forceMove(src) - visible_message("\The [source] lands in \the [src].") - else - visible_message("\The [source] bounces off of \the [src]'s rim!") +// called when the bin expels items, generally from a disposal network, or trying to flush without a proper connection. +// should usually only occur if the pipe network if modified or delivering mail +/obj/machinery/disposal/proc/expel(list/expelled_items, datum/gas_mixture/gas) + var/turf/T = get_turf(src) + var/turf/target + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) - if(isliving(source)) - if(prob(75)) + for(var/atom/movable/AM in expelled_items) + target = get_offset_target_turf(loc, rand(5)-rand(5), rand(5)-rand(5)) + + AM.forceMove(T) + AM.pipe_eject(0) + AM.throw_at(target, 5, 1) + + T.assume_air(gas) + +/obj/machinery/disposal/hitby(atom/movable/source, datum/thrownthing/throwingdatum) + if(!source.CanEnterDisposals()) + return ..() + + if(prob(75)) + source.forceMove(src) + if(isliving(source)) var/mob/living/to_be_dunked = source - if(ishuman(source) ||to_be_dunked.client) - log_and_message_admins("[source] was thrown into \the [src]", null) - source.forceMove(src) + if(to_be_dunked.client) + log_and_message_admins("has thrown [source] into \the [src]", throwingdatum?.get_thrower()) + //flush() + visible_message("\The [source] lands in \the [src].") // "and triggers the flush system!" + else visible_message("\The [source] lands in \the [src].") + else + visible_message("\The [source] bounces off of \the [src]'s rim!") + return ..() + update_icon() + +// Ideally, deconstruct would be a proc on /machinery, but you cant have nice things with polaris. +// AKA: FUKKIN CHANGE THIS WHEN THAT HAPPENS!!!!!1!! pls. -Reo +/obj/machinery/disposal/proc/deconstruct(disassembled = TRUE) + var/turf/T = loc + /* // More nice things... Someday we'll have flags_1 and then have proper support for anything being a hologram. + if(!(flags_1 & NODECONSTRUCT_1)) + if(stored) + stored.forceMove(T) + src.transfer_fingerprints_to(stored) + stored.anchored = FALSE + stored.density = TRUE + stored.update_icon() + */ + //This is temporary until the above gets used. Or it's permanant if you're reading this 5 years from now. + var/obj/structure/disposalconstruct/C = new (src.loc/*, null, SOUTH, FALSE, src*/) + transfer_fingerprints_to(C) + C.ptype = 6 // 6 = disposal unit + C.update_icon() + C.anchored = TRUE + C.density = TRUE + //End of "temporary" code + for(var/atom/movable/AM in src) + AM.forceMove(T) + //..() //*cough + qdel(src) //Parent above should do this, but that's not a thing as of writing this. + /obj/machinery/disposal/proc/clean_items() // Clean items before sending them @@ -544,7 +625,7 @@ density = FALSE -/obj/machinery/disposal/wall/update() +/obj/machinery/disposal/wall/update_icon() . = ..() switch(dir) if(NORTH) @@ -567,3 +648,15 @@ #undef SEND_PRESSURE #undef PRESSURE_TANK_VOLUME #undef PUMP_MAX_FLOW_RATE + +/atom/movable/proc/CanEnterDisposals() + return TRUE + +/obj/item/projectile/CanEnterDisposals() + return FALSE + +/obj/effect/CanEnterDisposals() + return FALSE + +/obj/mecha/CanEnterDisposals() + return FALSE diff --git a/code/modules/recycling/disposal_outlet.dm b/code/modules/recycling/disposal_outlet.dm index 4415379117..e974055387 100644 --- a/code/modules/recycling/disposal_outlet.dm +++ b/code/modules/recycling/disposal_outlet.dm @@ -1,3 +1,6 @@ +#define OUTLET_SCREWED 0 +#define OUTLET_UNSCREWED 1 + // the disposal outlet machine /obj/structure/disposaloutlet name = "disposal outlet" @@ -6,38 +9,58 @@ icon_state = "outlet" density = TRUE anchored = TRUE - var/active = 0 + var/active = FALSE // Code appendix. + var/turf/target // this will be where the output objects are 'thrown' to. var/mode = 0 + var/start_eject = 0 + var/eject_range = 3 //Did you know, in TGcode, it's a default of 2 tiles? /obj/structure/disposaloutlet/Initialize(mapload) . = ..() - AddComponent(/datum/component/disposal_system_connection/disposaloutlet) // Special subtype for directional tossing and it's animation/buzzer + + target = get_ranged_target_turf(src, dir, 10) + + var/obj/structure/disposalpipe/trunk/trunk = locate() in get_turf(src) + AddComponent(/datum/component/disposal_system_connection) + RegisterSignal(src, COMSIG_DISPOSAL_RECEIVE, PROC_REF(expel)) + if(trunk) + SEND_SIGNAL(src, COMSIG_DISPOSAL_LINK, trunk) + +/obj/structure/disposaloutlet/Destroy() + target = null + . = ..() /obj/structure/disposaloutlet/attackby(obj/item/I, mob/user) if(!I || !user) return src.add_fingerprint(user) if(I.has_tool_quality(TOOL_SCREWDRIVER)) - if(mode==0) - mode=1 + if(mode == OUTLET_SCREWED) + mode = OUTLET_UNSCREWED to_chat(user, "You remove the screws around the power connection.") playsound(src, I.usesound, 50, 1) return - else if(mode==1) - mode=0 + else if(mode == OUTLET_UNSCREWED) + mode = OUTLET_SCREWED to_chat(user, "You attach the screws around the power connection.") playsound(src, I.usesound, 50, 1) return - else if(I.has_tool_quality(TOOL_WELDER) && mode==1) + if(mode == OUTLET_SCREWED) + return ..() + if(I.has_tool_quality(TOOL_WELDER) && mode==1) var/obj/item/weldingtool/W = I.get_welder() + if(!W.isOn()) + to_chat(user, span_warning("Your [W] needs to be on to complete this task.")) if(W.remove_fuel(0,user)) playsound(src, W.usesound, 100, 1) to_chat(user, "You start slicing the floorweld off the disposal outlet.") if(do_after(user, 2 SECONDS * W.toolspeed, target = src)) if(!src || !W.isOn()) return to_chat(user, "You sliced the floorweld off the disposal outlet.") - var/obj/structure/disposalconstruct/C = new (src.loc) + SEND_SIGNAL(src, COMSIG_DISPOSAL_UNLINK) + var/obj/structure/disposalconstruct/C = new (src.loc/*, null, SOUTH, FALSE, src*/) src.transfer_fingerprints_to(C) + C.set_dir(dir) C.ptype = 7 // 7 = outlet C.update() C.anchored = TRUE @@ -47,3 +70,34 @@ else to_chat(user, "You need more welding fuel to complete this task.") return + else if(I.has_tool_quality(TOOL_MULTITOOL)) + var/new_range = tgui_input_number(user, "Input a new ejection distance", "Set ejection strength", 3 , 5, 1, round_value = TRUE) + eject_range = new_range + to_chat(user, span_notice("You set the range on the [src] to [new_range] tiles.")) + +/obj/structure/disposaloutlet/proc/expel(datum/source, list/received_items, datum/gas_mixture/gas) + SIGNAL_HANDLER + + flick("outlet-open", src) + if((start_eject + 30) < world.time) + start_eject = world.time + playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 0, 0) + addtimer(CALLBACK(src, PROC_REF(expel_contents), received_items, gas, TRUE), 2 SECONDS) + else + addtimer(CALLBACK(src, PROC_REF(expel_contents), received_items, gas), 2 SECONDS) + +/obj/structure/disposaloutlet/proc/expel_contents(list/ejected_items, datum/gas_mixture/gas, playsound = FALSE) + if(playsound) + playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0) + + var/turf/T = get_turf(src) + + for(var/atom/movable/AM in ejected_items) + AM.forceMove(T) + AM.pipe_eject(dir) + AM.throw_at(target, eject_range, 1) + + T.assume_air(gas) + +#undef OUTLET_SCREWED +#undef OUTLET_UNSCREWED diff --git a/code/modules/recycling/disposal_trunk.dm b/code/modules/recycling/disposal_trunk.dm index 947e9c6f83..27317c7d11 100644 --- a/code/modules/recycling/disposal_trunk.dm +++ b/code/modules/recycling/disposal_trunk.dm @@ -1,6 +1,7 @@ //a trunk joining to a disposal bin or outlet on the same turf /obj/structure/disposalpipe/trunk icon_state = "pipe-t" + var/atom/linked // The linked atom. It should have a /datum/component/disposal_connection to handle receiving disposal packets. /obj/structure/disposalpipe/trunk/Initialize(mapload) ..() @@ -10,30 +11,25 @@ /obj/structure/disposalpipe/trunk/LateInitialize() update() +/obj/structure/disposalpipe/trunk/Destroy() + if(linked) //Linked to something, better unlink. + SEND_SIGNAL(linked, COMSIG_DISPOSAL_UNLINK) + linked = null + . = ..() + // Override attackby so we disallow trunkremoval when somethings ontop /obj/structure/disposalpipe/trunk/attackby(obj/item/I, mob/user) + //Linked atom. + if(linked) + return //Disposal constructors var/turf/T = get_turf(src) - var/obj/structure/disposalconstruct/C = locate() in T - if(C && C.anchored) - return + for(var/obj/structure/disposalconstruct/C in T) + if(C.ptype == DISPOSAL_PIPE_BIN || C.ptype == DISPOSAL_PIPE_OUTLET || C.ptype == DISPOSAL_PIPE_CHUTE) + if(C.anchored) + return - if(!T.is_plating()) - return // prevent interaction with T-scanner revealed pipes - add_fingerprint(user) - if(I.has_tool_quality(TOOL_WELDER)) - var/obj/item/weldingtool/W = I.get_welder() - - if(W.remove_fuel(0,user)) - playsound(src, W.usesound, 100, 1) - to_chat(user, "Slicing the disposal pipe.") - if(do_after(user, 3 SECONDS * W.toolspeed, target = src)) - if(!src || !W.isOn()) return - welded() - else - to_chat(user, "You must stay still while welding the pipe.") - else - to_chat(user, "You need more welding fuel to cut the pipe.") + return ..() //Run the check from parent, instead of copypasta code // would transfer to next pipe segment, but we are in a trunk // if not entering from disposal bin, @@ -42,15 +38,11 @@ if(H.dir == DOWN) // we just entered from a disposer return ..() // so do base transfer proc - // Find a disposal handler component. First come first serve. - var/transfered = FALSE - var/turf/T = get_turf(src) - for(var/obj/O in T) - if(SEND_SIGNAL(O,COMSIG_DISPOSAL_RECEIVING,H)) - transfered = TRUE - break - if(!transfered) // Check if anything handled it, will be deleted if so. - expel(H, T, 0) // expel at turf if nothing handled it + if(linked) + if(SEND_SIGNAL(src, COMSIG_DISPOSAL_SEND, H)) + return //Sent, and handled. Our job is done. + + expel(H, get_turf(src), 0) // expel at turf if nothing handled it return null diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 024bc0b433..1e2b759212 100755 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -9,7 +9,10 @@ /obj/machinery/disposal/deliveryChute/interact() return -/obj/machinery/disposal/deliveryChute/update() +/obj/machinery/disposal/deliveryChute/update_icon() + return + +/obj/machinery/disposal/deliveryChute/click_alt(mob/user) //No flushing the chute return /obj/machinery/disposal/deliveryChute/Bumped(var/atom/movable/AM) //Go straight into the chute