Revert "PLASE"

This reverts commit 8af225e6e3.
This commit is contained in:
Fermi
2019-11-24 03:06:08 +00:00
parent aeb8606ce0
commit ba4fa1ef67
2145 changed files with 1387321 additions and 5257 deletions
+543
View File
@@ -0,0 +1,543 @@
// Disposal bin and Delivery chute.
#define SEND_PRESSURE (0.05*ONE_ATMOSPHERE)
/obj/machinery/disposal
icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
density = TRUE
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
max_integrity = 200
resistance_flags = FIRE_PROOF
interaction_flags_machine = INTERACT_MACHINE_OPEN | INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON
obj_flags = CAN_BE_HIT | USES_TGUI
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
var/datum/gas_mixture/air_contents // internal reservoir
var/full_pressure = FALSE
var/pressure_charging = TRUE
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/Initialize(mapload, obj/structure/disposalconstruct/make_from)
. = ..()
if(make_from)
setDir(make_from.dir)
make_from.moveToNullspace()
stored = make_from
pressure_charging = FALSE // newly built disposal bins start with pump off
else
stored = new /obj/structure/disposalconstruct(null, null , SOUTH , FALSE , src)
trunk_check()
air_contents = new /datum/gas_mixture()
//gas.volume = 1.05 * CELLSTANDARD
update_icon()
return INITIALIZE_HINT_LATELOAD //we need turfs to have air
/obj/machinery/disposal/proc/trunk_check()
trunk = locate() in loc
if(!trunk)
pressure_charging = FALSE
flush = FALSE
else
if(initial(pressure_charging))
pressure_charging = TRUE
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/LateInitialize()
//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)
add_fingerprint(user)
if(!pressure_charging && !full_pressure && !flush)
if(istype(I, /obj/item/screwdriver))
panel_open = !panel_open
I.play_tool_sound(src)
to_chat(user, "<span class='notice'>You [panel_open ? "remove":"attach"] the screws around the power connection.</span>")
return
else if(istype(I, /obj/item/weldingtool) && panel_open)
if(!I.tool_start_check(user, amount=0))
return
to_chat(user, "<span class='notice'>You start slicing the floorweld off \the [src]...</span>")
if(I.use_tool(src, user, 20, volume=100) && panel_open)
to_chat(user, "<span class='notice'>You slice the floorweld off \the [src].</span>")
deconstruct()
return
if(user.a_intent != INTENT_HARM)
if((I.item_flags & ABSTRACT) || !user.temporarilyRemoveItemFromInventory(I))
return
place_item_in_disposal(I, user)
update_icon()
return 1 //no afterattack
else
return ..()
/obj/machinery/disposal/proc/place_item_in_disposal(obj/item/I, mob/user)
I.forceMove(src)
user.visible_message("[user.name] places \the [I] into \the [src].", "<span class='notice'>You place \the [I] into \the [src].</span>")
//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(!can_stuff_mob_in(target, user))
return
add_fingerprint(user)
if(user == target)
user.visible_message("[user] starts climbing into [src].", "<span class='notice'>You start climbing into [src]...</span>")
else
target.visible_message("<span class='danger'>[user] starts putting [target] into [src].</span>", "<span class='userdanger'>[user] starts putting you into [src]!</span>")
if(do_mob(user, target, 20))
if (!loc)
return
target.forceMove(src)
if(user == target)
user.visible_message("[user] climbs into [src].", "<span class='notice'>You climb into [src].</span>")
else
target.visible_message("<span class='danger'>[user] has placed [target] in [src].</span>", "<span class='userdanger'>[user] has placed [target] in [src].</span>")
log_combat(user, target, "stuffed", addition="into [src]")
target.LAssailant = user
update_icon()
/obj/machinery/disposal/proc/can_stuff_mob_in(mob/living/target, mob/living/user, pushing = FALSE)
if(!pushing && !iscarbon(user) && !user.ventcrawler) //only carbon and ventcrawlers can climb into disposal by themselves.
if (iscyborg(user))
var/mob/living/silicon/robot/borg = user
if (!borg.module || !borg.module.canDispose)
return
else
return FALSE
if(!isturf(user.loc)) //No magically doing it from inside closets
return FALSE
if(target.buckled || target.has_buckled_mobs())
return FALSE
if(target.mob_size > MOB_SIZE_HUMAN)
if(!pushing)
to_chat(user, "<span class='warning'>[target] doesn't fit inside [src]!</span>")
return FALSE
return TRUE
/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(flushing)
return
go_out(user)
// leave the disposal
/obj/machinery/disposal/proc/go_out(mob/user)
user.forceMove(loc)
update_icon()
// monkeys and xenos can only pull the flush lever
/obj/machinery/disposal/attack_paw(mob/user)
if(stat & BROKEN)
return
flush = !flush
update_icon()
// 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_icon()
// update the icon & overlays to reflect mode & status
/obj/machinery/disposal/update_icon()
return
/obj/machinery/disposal/proc/flush()
flushing = TRUE
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(src)
newHolderDestination(H)
H.init(src)
air_contents = new()
H.start(src)
flushing = FALSE
flush = FALSE
/obj/machinery/disposal/proc/newHolderDestination(obj/structure/disposalholder/H)
for(var/obj/item/smallDelivery/O in src)
H.tomail = TRUE
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_icon() // update icon
// called when holder is expelled from a disposal
/obj/machinery/disposal/proc/expel(obj/structure/disposalholder/H)
H.active = FALSE
var/turf/T = get_turf(src)
var/turf/target
playsound(src, 'sound/machines/hiss.ogg', 50, 0, 0)
for(var/A in H)
var/atom/movable/AM = A
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)
H.vent_gas(loc)
qdel(H)
/obj/machinery/disposal/deconstruct(disassembled = TRUE)
var/turf/T = loc
if(!(flags_1 & NODECONSTRUCT_1))
if(stored)
stored.forceMove(T)
src.transfer_fingerprints_to(stored)
stored.anchored = FALSE
stored.density = TRUE
stored.update_icon()
for(var/atom/movable/AM in src) //out, out, darned crowbar!
AM.forceMove(T)
..()
/obj/machinery/disposal/get_dumping_location(obj/item/storage/source,mob/user)
return src
//How disposal handles getting a storage dump from a storage object
/obj/machinery/disposal/storage_contents_dump_act(datum/component/storage/src_object, mob/user)
. = ..()
if(.)
return
for(var/obj/item/I in src_object)
if(user.active_storage != src_object)
if(I.on_found(user))
return
src_object.remove_from_storage(I, src)
return TRUE
// 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"
var/datum/oracle_ui/themed/nano/ui
obj_flags = CAN_BE_HIT | USES_TGUI | SHOVABLE_ONTO
/obj/machinery/disposal/bin/Initialize(mapload, obj/structure/disposalconstruct/make_from)
. = ..()
ui = new /datum/oracle_ui/themed/nano(src, 330, 190, "disposal_bin")
ui.auto_refresh = TRUE
ui.can_resize = FALSE
// attack by item places it in to disposal
/obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/storage/bag/trash)) //Not doing component overrides because this is a specific type.
var/obj/item/storage/bag/trash/T = I
var/datum/component/storage/STR = T.GetComponent(/datum/component/storage)
to_chat(user, "<span class='warning'>You empty the bag.</span>")
for(var/obj/item/O in T.contents)
STR.remove_from_storage(O,src)
T.update_icon()
update_icon()
ui.soft_update_fields()
else
ui.soft_update_fields()
return ..()
// handle machine interaction
/obj/machinery/disposal/bin/ui_interact(mob/user, state)
if(stat & BROKEN)
return
if(user.loc == src)
to_chat(user, "<span class='warning'>You cannot reach the controls from inside!</span>")
return
ui.render(user)
/obj/machinery/disposal/bin/oui_canview(mob/user)
if(user.loc == src)
return FALSE
if(stat & BROKEN)
return FALSE
if(Adjacent(user))
return TRUE
return ..()
/obj/machinery/disposal/bin/oui_data(mob/user)
var/list/data = list()
data["flush"] = flush ? ui.act("Disengage", user, "handle-0", class="active") : ui.act("Engage", user, "handle-1")
data["full_pressure"] = full_pressure ? "Ready" : (pressure_charging ? "Pressurizing" : "Off")
data["pressure_charging"] = pressure_charging ? ui.act("Turn Off", user, "pump-0", class="active", disabled=full_pressure) : ui.act("Turn On", user, "pump-1", disabled=full_pressure)
var/per = full_pressure ? 100 : CLAMP(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 99)
data["per"] = "[round(per, 1)]%"
data["contents"] = ui.act("Eject Contents", user, "eject", disabled=contents.len < 1)
data["isai"] = isAI(user)
return data
/obj/machinery/disposal/bin/oui_act(mob/user, action, list/params)
if(..())
return
switch(action)
if("handle-0")
flush = FALSE
update_icon()
. = TRUE
if("handle-1")
if(!panel_open)
flush = TRUE
update_icon()
. = TRUE
if("pump-0")
if(pressure_charging)
pressure_charging = FALSE
update_icon()
. = TRUE
if("pump-1")
if(!pressure_charging)
pressure_charging = TRUE
update_icon()
. = TRUE
if("eject")
eject()
. = TRUE
ui.soft_update_fields()
/obj/machinery/disposal/bin/alt_attack_hand(mob/user)
if(can_interact(usr))
flush = !flush
update_icon()
return TRUE
return FALSE
/obj/machinery/disposal/bin/hitby(atom/movable/AM)
if(isitem(AM) && AM.CanEnterDisposals())
if(prob(75))
AM.forceMove(src)
visible_message("<span class='notice'>[AM] lands in [src].</span>")
update_icon()
else
visible_message("<span class='notice'>[AM] bounces off of [src]'s rim!</span>")
return ..()
else
return ..()
/obj/machinery/disposal/bin/shove_act(mob/living/target, mob/living/user)
if(!can_stuff_mob_in(target, user, TRUE))
return FALSE
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
target.forceMove(src)
user.visible_message("<span class='danger'>[user.name] shoves [target.name] into \the [src]!</span>",
"<span class='danger'>You shove [target.name] into \the [src]!</span>", null, COMBAT_MESSAGE_RANGE)
log_combat(user, target, "shoved", "into [src] (disposal bin)")
return TRUE
/obj/machinery/disposal/bin/flush()
..()
full_pressure = FALSE
pressure_charging = TRUE
update_icon()
ui.soft_update_fields()
/obj/machinery/disposal/bin/update_icon()
cut_overlays()
if(stat & BROKEN)
pressure_charging = FALSE
flush = FALSE
return
//flush handle
if(flush)
add_overlay("dispover-handle")
//only handle is shown if no power
if(stat & NOPOWER || panel_open)
return
//check for items in disposal - occupied light
if(contents.len > 0)
add_overlay("dispover-full")
//charging and ready light
if(pressure_charging)
add_overlay("dispover-charge")
else if(full_pressure)
add_overlay("dispover-ready")
/obj/machinery/disposal/bin/proc/do_flush()
set waitfor = FALSE
flush()
//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(full_pressure)
do_flush()
flush_count = 0
ui.soft_update_fields()
if(flush && air_contents.return_pressure() >= SEND_PRESSURE) // flush can happen even without power
do_flush()
if(stat & NOPOWER) // won't charge if no power
return
use_power(100) // base power usage
if(!pressure_charging) // 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)
full_pressure = TRUE
pressure_charging = FALSE
update_icon()
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 = TRUE
icon_state = "intake"
pressure_charging = FALSE // the chute doesn't need charging and always works
/obj/machinery/disposal/deliveryChute/Initialize(mapload, obj/structure/disposalconstruct/make_from)
. = ..()
trunk = locate() in loc
if(trunk)
trunk.linked = src // link the pipe trunk to self
/obj/machinery/disposal/deliveryChute/place_item_in_disposal(obj/item/I, mob/user)
if(I.CanEnterDisposals())
..()
flush()
/obj/machinery/disposal/deliveryChute/Bumped(atom/movable/AM) //Go straight into the chute
if(!AM.CanEnterDisposals())
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(isobj(AM))
var/obj/O = AM
O.forceMove(src)
else if(ismob(AM))
var/mob/M = AM
if(prob(2)) // to prevent mobs being stuck in infinite loops
to_chat(M, "<span class='warning'>You hit the edge of the chute.</span>")
return
M.forceMove(src)
flush()
/atom/movable/proc/CanEnterDisposals()
return TRUE
/obj/item/projectile/CanEnterDisposals()
return
/obj/effect/CanEnterDisposals()
return
/obj/mecha/CanEnterDisposals()
return
/obj/machinery/disposal/deliveryChute/newHolderDestination(obj/structure/disposalholder/H)
H.destinationTag = 1
@@ -0,0 +1,187 @@
// Disposal pipe construction
// This is the pipe that you drag around, not the attached ones.
/obj/structure/disposalconstruct
name = "disposal pipe segment"
desc = "A huge pipe segment used for constructing disposal systems."
icon = 'icons/obj/atmospherics/pipes/disposal.dmi'
icon_state = "conpipe"
anchored = FALSE
density = FALSE
pressure_resistance = 5*ONE_ATMOSPHERE
level = 2
max_integrity = 200
var/obj/pipe_type = /obj/structure/disposalpipe/segment
var/pipename
/obj/structure/disposalconstruct/Initialize(loc, _pipe_type, _dir = SOUTH, flip = FALSE, obj/make_from)
. = ..()
if(make_from)
pipe_type = make_from.type
setDir(make_from.dir)
anchored = TRUE
else
if(_pipe_type)
pipe_type = _pipe_type
setDir(_dir)
pipename = initial(pipe_type.name)
if(flip)
var/datum/component/simple_rotation/rotcomp = GetComponent(/datum/component/simple_rotation)
rotcomp.BaseRot(null,ROTATION_FLIP)
update_icon()
/obj/structure/disposalconstruct/Move()
var/old_dir = dir
..()
setDir(old_dir) //pipes changing direction when moved is just annoying and buggy
// update iconstate and dpdir due to dir and type
/obj/structure/disposalconstruct/update_icon()
icon_state = initial(pipe_type.icon_state)
if(is_pipe())
icon_state = "con[icon_state]"
if(anchored)
level = initial(pipe_type.level)
layer = initial(pipe_type.layer)
else
level = initial(level)
layer = initial(layer)
else if(ispath(pipe_type, /obj/machinery/disposal/bin))
// Disposal bins receive special icon treating
if(anchored)
icon_state = "disposal"
else
icon_state = "condisposal"
// hide called by levelupdate if turf intact status changes
// change visibility status and force update of icon
/obj/structure/disposalconstruct/hide(var/intact)
invisibility = (intact && level==1) ? INVISIBILITY_MAXIMUM: 0 // hide if floor is intact
update_icon()
/obj/structure/disposalconstruct/proc/get_disposal_dir()
if(!is_pipe())
return NONE
var/obj/structure/disposalpipe/temp = pipe_type
var/initialize_dirs = initial(temp.initialize_dirs)
var/dpdir = NONE
if(dir in GLOB.diagonals) // Bent pipes
return dir
if(initialize_dirs != DISP_DIR_NONE)
dpdir = dir
if(initialize_dirs & DISP_DIR_LEFT)
dpdir |= turn(dir, 90)
if(initialize_dirs & DISP_DIR_RIGHT)
dpdir |= turn(dir, -90)
if(initialize_dirs & DISP_DIR_FLIP)
dpdir |= turn(dir, 180)
return dpdir
/obj/structure/disposalconstruct/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_FLIP | ROTATION_VERBS ,null,CALLBACK(src, .proc/can_be_rotated), CALLBACK(src, .proc/after_rot))
/obj/structure/disposalconstruct/proc/after_rot(mob/user,rotation_type)
if(rotation_type == ROTATION_FLIP)
var/obj/structure/disposalpipe/temp = pipe_type
if(initial(temp.flip_type))
if(dir in GLOB.diagonals) // Fix RPD-induced diagonal turning
setDir(turn(dir, 45))
pipe_type = initial(temp.flip_type)
update_icon()
/obj/structure/disposalconstruct/proc/can_be_rotated(mob/user,rotation_type)
if(anchored)
to_chat(user, "<span class='warning'>You must unfasten the pipe before rotating it!</span>")
return FALSE
return TRUE
// construction/deconstruction
// wrench: (un)anchor
// weldingtool: convert to real pipe
/obj/structure/disposalconstruct/wrench_act(mob/living/user, obj/item/I)
if(anchored)
anchored = FALSE
density = FALSE
to_chat(user, "<span class='notice'>You detach the [pipename] from the underfloor.</span>")
else
var/ispipe = is_pipe() // Indicates if we should change the level of this pipe
var/turf/T = get_turf(src)
if(T.intact && isfloorturf(T))
to_chat(user, "<span class='warning'>You can only attach the [pipename] if the floor plating is removed!</span>")
return TRUE
if(!ispipe && iswallturf(T))
to_chat(user, "<span class='warning'>You can't build [pipename]s on walls, only disposal pipes!</span>")
return TRUE
if(ispipe)
var/dpdir = get_disposal_dir()
for(var/obj/structure/disposalpipe/CP in T)
var/pdir = CP.dpdir
if(istype(CP, /obj/structure/disposalpipe/broken))
pdir = CP.dir
if(pdir & dpdir)
to_chat(user, "<span class='warning'>There is already a disposal pipe at that location!</span>")
return TRUE
else // Disposal or outlet
var/found_trunk = FALSE
for(var/obj/structure/disposalpipe/CP in T)
if(istype(CP, /obj/structure/disposalpipe/trunk))
found_trunk = TRUE
break
if(!found_trunk)
to_chat(user, "<span class='warning'>The [pipename] requires a trunk underneath it in order to work!</span>")
return TRUE
anchored = TRUE
density = initial(pipe_type.density)
to_chat(user, "<span class='notice'>You attach the [pipename] to the underfloor.</span>")
I.play_tool_sound(src, 100)
update_icon()
return TRUE
/obj/structure/disposalconstruct/welder_act(mob/living/user, obj/item/I)
if(anchored)
if(!I.tool_start_check(user, amount=0))
return TRUE
to_chat(user, "<span class='notice'>You start welding the [pipename] in place...</span>")
if(I.use_tool(src, user, 8, volume=50))
to_chat(user, "<span class='notice'>The [pipename] has been welded in place.</span>")
var/obj/O = new pipe_type(loc, src)
transfer_fingerprints_to(O)
else
to_chat(user, "<span class='warning'>You need to attach it to the plating first!</span>")
return TRUE
/obj/structure/disposalconstruct/proc/is_pipe()
return ispath(pipe_type, /obj/structure/disposalpipe)
//helper proc that makes sure you can place the construct (i.e no dense objects stacking)
/obj/structure/disposalconstruct/proc/can_place()
if(is_pipe())
return TRUE
for(var/obj/structure/disposalconstruct/DC in get_turf(src))
if(DC == src)
continue
if(!DC.is_pipe()) //there's already a chute/outlet/bin there
return FALSE
return TRUE
+132
View File
@@ -0,0 +1,132 @@
// 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
dir = NONE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
var/datum/gas_mixture/gas // gas used to flush, will appear at exit point
var/active = FALSE // true if the holder is moving, otherwise inactive
var/count = 1000 // can travel 1000 steps before going inactive (in case of loops)
var/destinationTag = NONE // changes if contains a delivery container
var/tomail = FALSE // contains wrapped package
var/hasmob = FALSE // contains a mob
/obj/structure/disposalholder/Destroy()
QDEL_NULL(gas)
active = FALSE
return ..()
// initialize a holder from the contents of a disposal unit
/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D)
gas = D.air_contents// transfer gas resv. into holder object
//Check for any living mobs trigger hasmob.
//hasmob effects whether the package goes to cargo or its tagged destination.
for(var/mob/living/M in D)
if(M.client)
M.reset_perspective(src)
hasmob = TRUE
//Checks 1 contents level deep. This means that players can be sent through disposals mail...
//...but it should require a second person to open the package. (i.e. person inside a wrapped locker)
for(var/obj/O in D)
if(locate(/mob/living) in O)
hasmob = TRUE
break
// now everything inside the disposal gets put into the holder
// note AM since can contain mobs or objs
for(var/A in D)
var/atom/movable/AM = A
if(AM == src)
continue
SEND_SIGNAL(AM, COMSIG_MOVABLE_DISPOSING, src, D)
AM.forceMove(src)
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
else if(istype(AM, /mob/living/silicon/robot))
var/obj/item/destTagger/borg/tagger = locate() in AM
if (tagger)
src.destinationTag = tagger.currTag
// start the movement process
// argument is the disposal unit the holder started in
/obj/structure/disposalholder/proc/start(obj/machinery/disposal/D)
if(!D.trunk)
D.expel(src) // no trunk connected, so expel immediately
return
forceMove(D.trunk)
active = TRUE
setDir(DOWN)
move()
// movement process, persists while holder is moving through pipes
/obj/structure/disposalholder/proc/move()
set waitfor = FALSE
var/obj/structure/disposalpipe/last
while(active)
var/obj/structure/disposalpipe/curr = loc
last = curr
curr = curr.transfer(src)
if(!curr && active)
last.expel(src, loc, dir)
stoplag()
if(!(count--))
active = FALSE
// find the turf which should contain the next pipe
/obj/structure/disposalholder/proc/nextloc()
return get_step(src, dir)
// find a matching pipe on a turf
/obj/structure/disposalholder/proc/findpipe(turf/T)
if(!T)
return null
var/fdir = turn(dir, 180) // flip the movement direction
for(var/obj/structure/disposalpipe/P in T)
if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir
return P
// if no matching pipe, return null
return null
// merge two holder objects
// used when a holder meets a stuck holder
/obj/structure/disposalholder/proc/merge(obj/structure/disposalholder/other)
for(var/A in other)
var/atom/movable/AM = A
AM.forceMove(src) // move everything in other holder to this one
if(ismob(AM))
var/mob/M = AM
M.reset_perspective(src) // if a client mob, update eye to follow this holder
qdel(other)
// called when player tries to move while in a pipe
/obj/structure/disposalholder/relaymove(mob/user)
if(user.incapacitated())
return
for(var/mob/M in range(5, get_turf(src)))
M.show_message("<FONT size=[max(0, 5 - get_dist(src, M))]>CLONG, clong!</FONT>", 2)
playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0)
// called to vent all gas in holder to a location
/obj/structure/disposalholder/proc/vent_gas(turf/T)
T.assume_air(gas)
T.air_update_turf()
/obj/structure/disposalholder/AllowDrop()
return TRUE
/obj/structure/disposalholder/ex_act(severity, target)
return
+196
View File
@@ -0,0 +1,196 @@
/obj/structure/bigDelivery
name = "large parcel"
desc = "A large delivery parcel."
icon = 'icons/obj/storage.dmi'
icon_state = "deliverycloset"
density = TRUE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/giftwrapped = FALSE
var/sortTag = 0
/obj/structure/bigDelivery/interact(mob/user)
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
qdel(src)
/obj/structure/bigDelivery/Destroy()
var/turf/T = get_turf(src)
for(var/atom/movable/AM in contents)
AM.forceMove(T)
return ..()
/obj/structure/bigDelivery/contents_explosion(severity, target)
for(var/atom/movable/AM in contents)
AM.ex_act()
/obj/structure/bigDelivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/destTagger))
var/obj/item/destTagger/O = W
if(sortTag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "<span class='notice'>*[tag]*</span>")
sortTag = O.currTag
playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
else if(istype(W, /obj/item/pen))
if(!user.is_literate())
to_chat(user, "<span class='notice'>You scribble illegibly on the side of [src]!</span>")
return
var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN)
if(!user.canUseTopic(src, BE_CLOSE))
return
if(!str || !length(str))
to_chat(user, "<span class='warning'>Invalid text!</span>")
return
user.visible_message("[user] labels [src] as [str].")
name = "[name] ([str])"
else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped)
var/obj/item/stack/wrapping_paper/WP = W
if(WP.use(3))
user.visible_message("[user] wraps the package in festive paper!")
giftwrapped = TRUE
icon_state = "gift[icon_state]"
else
to_chat(user, "<span class='warning'>You need more paper!</span>")
else
return ..()
/obj/structure/bigDelivery/relay_container_resist(mob/living/user, obj/O)
if(ismovableatom(loc))
var/atom/movable/AM = loc //can't unwrap the wrapped container if it's inside something.
AM.relay_container_resist(user, O)
return
to_chat(user, "<span class='notice'>You lean on the back of [O] and start pushing to rip the wrapping around it.</span>")
if(do_after(user, 50, target = O))
if(!user || user.stat != CONSCIOUS || user.loc != O || O.loc != src )
return
to_chat(user, "<span class='notice'>You successfully removed [O]'s wrapping !</span>")
O.forceMove(loc)
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
qdel(src)
else
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
to_chat(user, "<span class='warning'>You fail to remove [O]'s wrapping!</span>")
/obj/item/smallDelivery
name = "parcel"
desc = "A brown paper delivery parcel."
icon = 'icons/obj/storage.dmi'
icon_state = "deliverypackage3"
var/giftwrapped = 0
var/sortTag = 0
/obj/item/smallDelivery/contents_explosion(severity, target)
for(var/atom/movable/AM in contents)
AM.ex_act()
/obj/item/smallDelivery/attack_self(mob/user)
user.temporarilyRemoveItemFromInventory(src, TRUE)
for(var/X in contents)
var/atom/movable/AM = X
user.put_in_hands(AM)
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
qdel(src)
/obj/item/smallDelivery/attack_self_tk(mob/user)
if(ismob(loc))
var/mob/M = loc
M.temporarilyRemoveItemFromInventory(src, TRUE)
for(var/X in contents)
var/atom/movable/AM = X
M.put_in_hands(AM)
else
for(var/X in contents)
var/atom/movable/AM = X
AM.forceMove(src.loc)
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
qdel(src)
/obj/item/smallDelivery/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/destTagger))
var/obj/item/destTagger/O = W
if(sortTag != O.currTag)
var/tag = uppertext(GLOB.TAGGERLOCATIONS[O.currTag])
to_chat(user, "<span class='notice'>*[tag]*</span>")
sortTag = O.currTag
playsound(loc, 'sound/machines/twobeep.ogg', 100, 1)
else if(istype(W, /obj/item/pen))
if(!user.is_literate())
to_chat(user, "<span class='notice'>You scribble illegibly on the side of [src]!</span>")
return
var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN)
if(!user.canUseTopic(src, BE_CLOSE))
return
if(!str || !length(str))
to_chat(user, "<span class='warning'>Invalid text!</span>")
return
user.visible_message("[user] labels [src] as [str].")
name = "[name] ([str])"
else if(istype(W, /obj/item/stack/wrapping_paper) && !giftwrapped)
var/obj/item/stack/wrapping_paper/WP = W
if(WP.use(1))
icon_state = "gift[icon_state]"
giftwrapped = 1
user.visible_message("[user] wraps the package in festive paper!")
else
to_chat(user, "<span class='warning'>You need more paper!</span>")
/obj/item/destTagger
name = "destination tagger"
desc = "Used to set the destination of properly wrapped packages."
icon = 'icons/obj/device.dmi'
icon_state = "cargotagger"
var/currTag = 0 //Destinations are stored in code\globalvars\lists\flavor_misc.dm
var/locked_destination = FALSE //if true, users can't open the destination tag window to prevent changing the tagger's current destination
w_class = WEIGHT_CLASS_TINY
item_state = "electronic"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
/obj/item/destTagger/borg
name = "cyborg destination tagger"
desc = "Used to fool the disposal mail network into thinking that you're a harmless parcel. Does actually work as a regular destination tagger as well."
/obj/item/destTagger/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] begins tagging [user.p_their()] final destination! It looks like [user.p_theyre()] trying to commit suicide!</span>")
if (islizard(user))
to_chat(user, "<span class='notice'>*HELL*</span>")//lizard nerf
else
to_chat(user, "<span class='notice'>*HEAVEN*</span>")
playsound(src, 'sound/machines/twobeep.ogg', 100, 1)
return BRUTELOSS
/obj/item/destTagger/proc/openwindow(mob/user)
var/dat = "<tt><center><h1><b>TagMaster 2.2</b></h1></center>"
dat += "<table style='width:100%; padding:4px;'><tr>"
for (var/i = 1, i <= GLOB.TAGGERLOCATIONS.len, i++)
dat += "<td><a href='?src=[REF(src)];nextTag=[i]'>[GLOB.TAGGERLOCATIONS[i]]</a></td>"
if(i%4==0)
dat += "</tr><tr>"
dat += "</tr></table><br>Current Selection: [currTag ? GLOB.TAGGERLOCATIONS[currTag] : "None"]</tt>"
user << browse(dat, "window=destTagScreen;size=450x350")
onclose(user, "destTagScreen")
/obj/item/destTagger/attack_self(mob/user)
if(!locked_destination)
openwindow(user)
return
/obj/item/destTagger/Topic(href, href_list)
add_fingerprint(usr)
if(href_list["nextTag"])
var/n = text2num(href_list["nextTag"])
currTag = n
openwindow(usr)