mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-31 09:00:25 +01:00
Adds the parcel cart to operations. (#21288)
This adds a parcel cart to the mail room in operations, which can be loaded with up to 17 packages. These packages can be any that can be held in the hand, so not crates but anything smaller effectively yes as long as it can be wrapped in package wrapper. When it is loaded with 5 packages, it gives a slowdown to the person pushing it, and further slowdown at 11 packages. The cart can have a total of 17 packages at the moment, as that is the amount of different sprites I have for it. The code is based on the engineering cart, and also contain a small bugfix so the engineering cart give back steel when taken apart, as that is what is used to build it. https://github.com/user-attachments/assets/b8613c9e-55e1-4f76-926a-60f4acd6269e ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | icons/obj/parcelcart.dmi | Tomixcomics (Aurora Station) | CC-BY |
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
ABSTRACT_TYPE(/obj/structure/cart)
|
||||
name = "cart parent item"
|
||||
desc = DESC_PARENT
|
||||
icon_state = "cart"
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
climbable = TRUE
|
||||
build_amt = 15
|
||||
material = DEFAULT_WALL_MATERIAL
|
||||
slowdown = 0
|
||||
var/movesound = 'sound/effects/roll.ogg'
|
||||
var/driving
|
||||
var/mob/living/pulling
|
||||
|
||||
/obj/structure/cart/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "\
|
||||
You can <b>CTRL-Click</b> to start dragging this cart. This object has a special dragging behaviour: when dragged, character's movement \
|
||||
directs the cart and the character is subsequently pulled by it. \
|
||||
"
|
||||
|
||||
/obj/structure/cart/disassembly_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "An empty cart can be taken apart with a <b>wrench</b> or a <b>welder</b>. Or a <b>plasma cutter</b>, if you're that hardcore."
|
||||
|
||||
/obj/structure/cart/proc/take_apart(var/mob/user = null, var/obj/I)
|
||||
if(user)
|
||||
if(iswelder(I))
|
||||
var/obj/item/welder = I
|
||||
welder.play_tool_sound(get_turf(src), 50)
|
||||
|
||||
user.visible_message("<b>[user]</b> starts taking apart the [src]...", SPAN_NOTICE("You start disassembling the [src]..."))
|
||||
if (!do_after(user, 30, do_flags = DO_DEFAULT & ~DO_USER_SAME_HAND))
|
||||
return
|
||||
|
||||
dismantle()
|
||||
|
||||
/obj/structure/cart/ex_act(severity)
|
||||
spill(100 / severity)
|
||||
..()
|
||||
|
||||
/obj/structure/cart/proc/spill(var/chance = 100)
|
||||
|
||||
/obj/structure/cart/proc/update_slowdown()
|
||||
|
||||
/obj/structure/cart/relaymove(mob/living/user, direction)
|
||||
. = ..()
|
||||
|
||||
if(user.stat || user.stunned || user.weakened || user.paralysis || user.lying || user.restrained())
|
||||
if(user==pulling)
|
||||
pulling = null
|
||||
user.pulledby = null
|
||||
to_chat(user, SPAN_WARNING("You lost your grip!"))
|
||||
return
|
||||
if(user.pulling && (user == pulling))
|
||||
pulling = null
|
||||
user.pulledby = null
|
||||
return
|
||||
if(pulling && (get_dist(src, pulling) > 1))
|
||||
pulling = null
|
||||
user.pulledby = null
|
||||
if(user==pulling)
|
||||
return
|
||||
if(pulling && (get_dir(src.loc, pulling.loc) == direction))
|
||||
to_chat(user, SPAN_WARNING("You cannot go there."))
|
||||
return
|
||||
|
||||
driving = 1
|
||||
var/turf/T = null
|
||||
if(pulling)
|
||||
T = pulling.loc
|
||||
if(get_dist(src, pulling) >= 1)
|
||||
step(pulling, get_dir(pulling.loc, src.loc))
|
||||
step(src, direction)
|
||||
set_dir(direction)
|
||||
if(pulling)
|
||||
if(pulling.loc == src.loc)
|
||||
pulling.forceMove(T)
|
||||
else
|
||||
spawn(0)
|
||||
if(get_dist(src, pulling) > 1)
|
||||
pulling = null
|
||||
user.pulledby = null
|
||||
pulling.set_dir(get_dir(pulling, src))
|
||||
driving = 0
|
||||
|
||||
|
||||
/obj/structure/cart/Move()
|
||||
. = ..()
|
||||
if (pulling && (get_dist(src, pulling) > 1))
|
||||
pulling.pulledby = null
|
||||
to_chat(pulling, SPAN_WARNING("You lost your grip!"))
|
||||
pulling = null
|
||||
if(has_gravity())
|
||||
playsound(src, movesound, 50, 1)
|
||||
|
||||
/obj/structure/cart/CtrlClick(var/mob/user)
|
||||
if(in_range(src, user))
|
||||
if(!ishuman(user)) return
|
||||
if(!pulling)
|
||||
pulling = user
|
||||
user.pulledby = src
|
||||
if(user.pulling)
|
||||
user.stop_pulling()
|
||||
user.set_dir(get_dir(user, src))
|
||||
to_chat(user, SPAN_NOTICE("You grip \the [name]'s handles."))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You let go of \the [name]'s handles."))
|
||||
pulling.pulledby = null
|
||||
pulling = null
|
||||
return
|
||||
|
||||
/obj/structure/cart/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(air_group || (height==0))
|
||||
return TRUE
|
||||
if(mover?.movement_type & PHASING)
|
||||
return TRUE
|
||||
if(istype(mover) && mover.pass_flags & PASSTABLE)
|
||||
return TRUE
|
||||
if(istype(mover, /mob/living) && mover == pulling)
|
||||
return TRUE
|
||||
else
|
||||
if(istype(mover, /obj/projectile))
|
||||
return prob(20)
|
||||
else
|
||||
return !density
|
||||
|
||||
ABSTRACT_TYPE(/obj/structure/cart/storage)
|
||||
var/has_items = FALSE
|
||||
|
||||
/// Used for displaying and handling radial menu. Collective list of every single item this object contains.
|
||||
var/list/storage_contents = list()
|
||||
|
||||
/obj/structure/cart/storage/proc/handle_storing(var/attacking_item, var/mob/user, var/should_store, var/storage_is_full)
|
||||
|
||||
/obj/structure/cart/storage/proc/get_storage_contents_list()
|
||||
|
||||
/obj/structure/cart/storage/take_apart(var/mob/user = null, var/obj/I)
|
||||
if(has_items)
|
||||
spill()
|
||||
. = ..()
|
||||
@@ -0,0 +1,322 @@
|
||||
/obj/structure/cart/storage/engineeringcart
|
||||
name = "engineering cart"
|
||||
desc = "A cart for your engineering-related storage needs."
|
||||
icon = 'icons/obj/engicart.dmi'
|
||||
icon_state = "cart"
|
||||
|
||||
var/list/my_glass = list()
|
||||
var/list/my_metal = list()
|
||||
var/list/my_plasteel = list()
|
||||
var/obj/item/device/lightreplacer/my_lightreplacer = null
|
||||
var/obj/item/storage/toolbox/mechanical/my_blue_toolbox = null
|
||||
var/obj/item/storage/toolbox/electrical/my_yellow_toolbox = null
|
||||
var/obj/item/storage/toolbox/emergency/my_red_toolbox = null
|
||||
/// Amount of stacks the cart is capable to store.
|
||||
var/stack_capacity = 2
|
||||
|
||||
var/static/list/allowed_types = typecacheof(list(
|
||||
/obj/item/stack/material/glass,
|
||||
/obj/item/stack/material/steel,
|
||||
/obj/item/stack/material/plasteel,
|
||||
/obj/item/device/lightreplacer,
|
||||
/obj/item/storage/toolbox/mechanical,
|
||||
/obj/item/storage/toolbox/electrical,
|
||||
/obj/item/storage/toolbox/emergency
|
||||
))
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "You can use steel, plasteel, glass sheets, toolboxes and light replacers on the cart to store them."
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/feedback_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
if(distance <= 1)
|
||||
if(locate(/obj/item/stack/material) in storage_contents)
|
||||
var/metal_amount
|
||||
var/plasteel_amount
|
||||
var/glass_amount
|
||||
var/obj/item/stack/material/steel/S
|
||||
var/obj/item/stack/material/plasteel/P
|
||||
var/obj/item/stack/material/glass/G
|
||||
if(LAZYLEN(my_metal))
|
||||
for(var/I in my_metal) // we already handle the type-check in `atttackby()` so it's safe to assume the lists contain what they're intended to
|
||||
S = I
|
||||
metal_amount += S.amount
|
||||
. += "[icon2html(S, user)] This cart contains <b>[metal_amount] sheet\s</b> of steel!"
|
||||
if(LAZYLEN(my_plasteel))
|
||||
for(var/I in my_plasteel)
|
||||
P = I
|
||||
plasteel_amount += P.amount
|
||||
. += "[icon2html(P, user)] This cart contains <b>[plasteel_amount] sheet\s</b> of plasteel!"
|
||||
if(LAZYLEN(my_glass))
|
||||
for(var/I in my_glass)
|
||||
G = I
|
||||
glass_amount += G.amount
|
||||
. += "[icon2html(G, user)] This cart contains <b>[glass_amount] sheet\s</b> of glass!"
|
||||
else
|
||||
. += "[icon2html(src, user)] There is no material in this cart!"
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/get_storage_contents_list()
|
||||
storage_contents.Cut()
|
||||
var/list/lists_to_check = list(
|
||||
my_glass, my_metal, my_plasteel
|
||||
)
|
||||
for(var/list/list_to_check in lists_to_check)
|
||||
if(list_to_check?.len) //null check
|
||||
storage_contents += list_to_check
|
||||
|
||||
var/list/non_sheet_objects = list(my_lightreplacer, my_blue_toolbox, my_yellow_toolbox, my_red_toolbox)
|
||||
|
||||
for(var/obj/O in non_sheet_objects)
|
||||
if(O)
|
||||
storage_contents += O
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/Destroy()
|
||||
QDEL_NULL(my_glass)
|
||||
QDEL_NULL(my_metal)
|
||||
QDEL_NULL(my_plasteel)
|
||||
QDEL_NULL(my_lightreplacer)
|
||||
QDEL_NULL(my_blue_toolbox)
|
||||
QDEL_NULL(my_yellow_toolbox)
|
||||
QDEL_NULL(my_red_toolbox)
|
||||
return ..()
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/attackby(obj/item/attacking_item, mob/user)
|
||||
if(is_type_in_typecache(attacking_item, allowed_types))
|
||||
var/should_store = FALSE
|
||||
var/storage_is_full = FALSE
|
||||
if(istype(attacking_item, /obj/item/stack/material)) //---- stack materials
|
||||
switch(attacking_item.type)
|
||||
if(/obj/item/stack/material/glass, /obj/item/stack/material/glass/full)
|
||||
if(my_glass.len < stack_capacity)
|
||||
my_glass += attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
if(/obj/item/stack/material/steel, /obj/item/stack/material/steel/full)
|
||||
if(my_metal.len < stack_capacity)
|
||||
my_metal += attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
if(/obj/item/stack/material/plasteel, /obj/item/stack/material/plasteel/full)
|
||||
if(my_plasteel.len < stack_capacity)
|
||||
my_plasteel += attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
handle_storing(attacking_item, user, should_store, storage_is_full)
|
||||
return TRUE
|
||||
|
||||
if(istype(attacking_item, /obj/item/storage/toolbox)) //---- toolboxes
|
||||
switch(attacking_item.type)
|
||||
if(/obj/item/storage/toolbox/mechanical)
|
||||
if(!my_blue_toolbox)
|
||||
my_blue_toolbox = attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
if(/obj/item/storage/toolbox/electrical)
|
||||
if(!my_yellow_toolbox)
|
||||
my_yellow_toolbox = attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
if(/obj/item/storage/toolbox/emergency)
|
||||
if(!my_red_toolbox)
|
||||
my_red_toolbox = attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
handle_storing(attacking_item, user, should_store, storage_is_full)
|
||||
return TRUE
|
||||
|
||||
if(istype(attacking_item, /obj/item/device/lightreplacer)) //---- light replacer
|
||||
if(!my_lightreplacer)
|
||||
my_lightreplacer = attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
handle_storing(attacking_item, user, should_store, storage_is_full)
|
||||
return TRUE
|
||||
|
||||
else if (!has_items && (attacking_item.iswrench() || attacking_item.iswelder() || istype(attacking_item, /obj/item/gun/energy/plasmacutter)))
|
||||
take_apart(user, attacking_item)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/spill(var/chance = 100)
|
||||
var/turf/dropspot = get_turf(src)
|
||||
if(LAZYLEN(my_glass) && prob(chance))
|
||||
var/obj/item/stack/material/glass/G
|
||||
for(var/I in my_glass)
|
||||
G = I
|
||||
G.forceMove(dropspot)
|
||||
G.tumble(1)
|
||||
my_glass -= G
|
||||
my_glass.Cut()
|
||||
|
||||
if(LAZYLEN(my_metal) && prob(chance))
|
||||
var/obj/item/stack/material/glass/M
|
||||
for(var/I in my_metal)
|
||||
M = I
|
||||
M.forceMove(dropspot)
|
||||
M.tumble(1)
|
||||
my_metal -= M
|
||||
my_metal.Cut()
|
||||
|
||||
if(LAZYLEN(my_plasteel) && prob(chance))
|
||||
var/obj/item/stack/material/glass/P
|
||||
for(var/I in my_plasteel)
|
||||
P = I
|
||||
P.forceMove(dropspot)
|
||||
P.tumble(1)
|
||||
my_plasteel -= P
|
||||
my_plasteel.Cut()
|
||||
|
||||
if(my_lightreplacer && prob(chance))
|
||||
my_lightreplacer.forceMove(dropspot)
|
||||
my_lightreplacer.tumble(2)
|
||||
my_lightreplacer = null
|
||||
|
||||
if(my_blue_toolbox && prob(chance))
|
||||
my_blue_toolbox.forceMove(dropspot)
|
||||
my_blue_toolbox.tumble(2)
|
||||
my_blue_toolbox = null
|
||||
|
||||
if(my_yellow_toolbox && prob(chance))
|
||||
my_yellow_toolbox.forceMove(dropspot)
|
||||
my_yellow_toolbox.tumble(2)
|
||||
my_yellow_toolbox = null
|
||||
|
||||
if(my_red_toolbox && prob(chance))
|
||||
my_red_toolbox.forceMove(dropspot)
|
||||
my_red_toolbox.tumble(2)
|
||||
my_red_toolbox = null
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/handle_storing(var/attacking_item, var/mob/user, var/should_store, var/storage_is_full)
|
||||
if(should_store)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
get_storage_contents_list()
|
||||
update_icon()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
else if(storage_is_full)
|
||||
to_chat(user, SPAN_WARNING("There isn't any space to store [attacking_item] in [src]!"))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("You can't store this here!"))
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/attack_hand(mob/user)
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
if(LAZYLEN(storage_contents))
|
||||
for(var/obj/O in storage_contents)
|
||||
storage_contents[O] = image(O.icon, O.icon_state)
|
||||
|
||||
var/obj/item/chosen_item = show_radial_menu(user, src, storage_contents, require_near = TRUE, tooltips = TRUE)
|
||||
|
||||
if(isnull(chosen_item))
|
||||
return
|
||||
if(chosen_item in storage_contents)
|
||||
switch(chosen_item.type)
|
||||
if(/obj/item/stack/material/glass, /obj/item/stack/material/glass/full)
|
||||
if(my_glass.len)
|
||||
user.put_in_hands(chosen_item)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_glass[chosen_item]] from [src]."))
|
||||
my_glass -= chosen_item
|
||||
if(/obj/item/stack/material/steel, /obj/item/stack/material/steel/full)
|
||||
if(my_metal.len)
|
||||
user.put_in_hands(chosen_item)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_metal[chosen_item]] from [src]."))
|
||||
my_metal -= chosen_item
|
||||
if(/obj/item/stack/material/plasteel, /obj/item/stack/material/plasteel/full)
|
||||
if(my_plasteel.len)
|
||||
user.put_in_hands(chosen_item)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_plasteel[chosen_item]] from [src]."))
|
||||
my_plasteel -= chosen_item
|
||||
if(/obj/item/device/lightreplacer)
|
||||
if(my_lightreplacer)
|
||||
user.put_in_hands(my_lightreplacer)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_lightreplacer] from [src]."))
|
||||
my_lightreplacer = null
|
||||
if(/obj/item/storage/toolbox/mechanical)
|
||||
if(my_blue_toolbox)
|
||||
user.put_in_hands(my_blue_toolbox)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_blue_toolbox] from [src]."))
|
||||
my_blue_toolbox = null
|
||||
if(/obj/item/storage/toolbox/electrical)
|
||||
if(my_yellow_toolbox)
|
||||
user.put_in_hands(my_yellow_toolbox)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_yellow_toolbox] from [src]."))
|
||||
my_yellow_toolbox = null
|
||||
if(/obj/item/storage/toolbox/emergency)
|
||||
if(my_red_toolbox)
|
||||
user.put_in_hands(my_red_toolbox)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_red_toolbox] from [src]."))
|
||||
my_red_toolbox = null
|
||||
|
||||
get_storage_contents_list()
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("\The [chosen_item] is not in the cart anymore!"))
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/update_icon()
|
||||
ClearOverlays()
|
||||
has_items = FALSE
|
||||
if(my_plasteel.len)
|
||||
AddOverlays("cart_plasteel")
|
||||
has_items = TRUE
|
||||
if(my_metal.len)
|
||||
AddOverlays("cart_metal")
|
||||
has_items = TRUE
|
||||
if(my_glass.len)
|
||||
AddOverlays("cart_glass")
|
||||
has_items = TRUE
|
||||
if(my_lightreplacer)
|
||||
AddOverlays("cart_flashlight")
|
||||
has_items = TRUE
|
||||
if(my_blue_toolbox)
|
||||
AddOverlays("cart_bluetoolbox")
|
||||
has_items = TRUE
|
||||
if(my_yellow_toolbox)
|
||||
AddOverlays("cart_yellowtoolbox")
|
||||
has_items = TRUE
|
||||
if(my_red_toolbox)
|
||||
AddOverlays("cart_redtoolbox")
|
||||
has_items = TRUE
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/half_filled
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/half_filled/Initialize()
|
||||
. = ..()
|
||||
my_blue_toolbox = new /obj/item/storage/toolbox/mechanical(src)
|
||||
my_yellow_toolbox = new /obj/item/storage/toolbox/electrical(src)
|
||||
my_red_toolbox = new /obj/item/storage/toolbox/emergency(src)
|
||||
get_storage_contents_list()
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/full
|
||||
|
||||
/obj/structure/cart/storage/engineeringcart/full/Initialize()
|
||||
. = ..()
|
||||
my_lightreplacer = new /obj/item/device/lightreplacer(src)
|
||||
my_blue_toolbox = new /obj/item/storage/toolbox/mechanical(src)
|
||||
my_yellow_toolbox = new /obj/item/storage/toolbox/electrical(src)
|
||||
my_red_toolbox = new /obj/item/storage/toolbox/emergency(src)
|
||||
my_glass += new /obj/item/stack/material/glass/full(src)
|
||||
my_glass += new /obj/item/stack/material/glass/full(src)
|
||||
my_metal += new /obj/item/stack/material/steel/full(src)
|
||||
my_metal += new /obj/item/stack/material/steel/full(src)
|
||||
my_plasteel += new /obj/item/stack/material/plasteel/full(src)
|
||||
my_plasteel += new /obj/item/stack/material/plasteel/full(src)
|
||||
get_storage_contents_list()
|
||||
update_icon()
|
||||
@@ -0,0 +1,330 @@
|
||||
/obj/structure/cart/storage/janitorialcart
|
||||
name = "custodial cart"
|
||||
desc = "The ultimate in custodial carts. Has space for water, mops, signs, trash bags, and more."
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "cart"
|
||||
|
||||
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
|
||||
var/obj/item/storage/bag/trash/mybag = null
|
||||
var/obj/item/mop/mymop = null
|
||||
var/obj/item/reagent_containers/spray/myspray = null
|
||||
var/obj/item/device/lightreplacer/myreplacer = null
|
||||
var/obj/structure/mopbucket/mybucket = null
|
||||
var/signs = 0 //maximum capacity hardcoded below
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "Click and drag a mop bucket onto the cart to mount it."
|
||||
. += "ALT-Click with a mop to put it away; a normal click will wet it in the bucket."
|
||||
. += "ALT-Click with a container, such as a bucket, to pour its contents into the mounted bucket. A normal click will toss it into the trash."
|
||||
. += "You can use a light replacer, spraybottle (of space cleaner) and four wet-floor signs on the cart to store them."
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/feedback_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
if(distance <= 1)
|
||||
if (mybucket)
|
||||
var/contains = mybucket.reagents.total_volume
|
||||
. += "[icon2html(src, user)] The bucket contains <b>[contains] unit\s</b> of liquid!"
|
||||
else
|
||||
. += "[icon2html(src, user)] There is no bucket mounted on it!"
|
||||
//everything else is visible, so doesn't need to be mentioned
|
||||
|
||||
// Regular Variant
|
||||
// No trashbag and no light replacer, this is inside the custodian's locker.
|
||||
/obj/structure/cart/storage/janitorialcart/Initialize()
|
||||
. = ..()
|
||||
mymop = new /obj/item/mop(src)
|
||||
myspray = new /obj/item/reagent_containers/spray/cleaner(src)
|
||||
|
||||
mybucket = new /obj/structure/mopbucket(src)
|
||||
|
||||
for(signs, signs < 4, signs++)
|
||||
new /obj/item/clothing/suit/caution(src)
|
||||
|
||||
update_icon()
|
||||
|
||||
// Full Variant
|
||||
// Has everything.
|
||||
/obj/structure/cart/storage/janitorialcart/full/Initialize()
|
||||
. = ..()
|
||||
mybag = new /obj/item/storage/bag/trash(src)
|
||||
mymop = new /obj/item/mop(src)
|
||||
myspray = new /obj/item/reagent_containers/spray/cleaner(src)
|
||||
myreplacer = new /obj/item/device/lightreplacer(src)
|
||||
|
||||
mybucket = new /obj/structure/mopbucket(src)
|
||||
|
||||
for(signs, signs < 4, signs++)
|
||||
new /obj/item/clothing/suit/caution(src)
|
||||
|
||||
update_icon()
|
||||
|
||||
// Full with Water Variant
|
||||
// Has everything as well as water in the mop bucket.
|
||||
/obj/structure/cart/storage/janitorialcart/full/water/Initialize()
|
||||
. = ..()
|
||||
mybag = new /obj/item/storage/bag/trash(src)
|
||||
mymop = new /obj/item/mop(src)
|
||||
myspray = new /obj/item/reagent_containers/spray/cleaner(src)
|
||||
myreplacer = new /obj/item/device/lightreplacer(src)
|
||||
|
||||
mybucket = new /obj/structure/mopbucket(src)
|
||||
mybucket.reagents.add_reagent(/singleton/reagent/water, mybucket.bucketsize)
|
||||
|
||||
for(signs, signs < 4, signs++)
|
||||
new /obj/item/clothing/suit/caution(src)
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/New()
|
||||
..()
|
||||
if(is_station_turf(get_turf(src)))
|
||||
GLOB.janitorial_supplies |= src
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/Destroy()
|
||||
if(src in GLOB.janitorial_supplies)
|
||||
GLOB.janitorial_supplies -= src
|
||||
QDEL_NULL(mybag)
|
||||
QDEL_NULL(mymop)
|
||||
QDEL_NULL(myspray)
|
||||
QDEL_NULL(myreplacer)
|
||||
QDEL_NULL(mybucket)
|
||||
return ..()
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/proc/get_short_status()
|
||||
return "Contents: [english_list(contents)]"
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/mouse_drop_receive(atom/dropped, mob/user, params)
|
||||
var/atom/movable/O = dropped
|
||||
if (istype(O, /obj/structure/mopbucket) && !mybucket)
|
||||
O.forceMove(src)
|
||||
mybucket = O
|
||||
to_chat(user, "You mount the [O] on the janicart.")
|
||||
update_icon()
|
||||
else
|
||||
..()
|
||||
|
||||
//New Altclick functionality!
|
||||
//Altclick the cart with a mop to stow the mop away
|
||||
//Altclick the cart with a reagent container to pour things into the bucket without putting the bottle in trash
|
||||
/obj/structure/cart/storage/janitorialcart/AltClick()
|
||||
if(!usr || usr.stat || usr.lying || usr.restrained() || !Adjacent(usr)) return
|
||||
var/obj/I = usr.get_active_hand()
|
||||
if(istype(I, /obj/item/mop))
|
||||
if(!mymop)
|
||||
usr.drop_from_inventory(I,src)
|
||||
mymop = I
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
to_chat(usr, SPAN_NOTICE("You put [I] into [src]."))
|
||||
else
|
||||
to_chat(usr, SPAN_NOTICE("The cart already has a mop attached"))
|
||||
return
|
||||
else if(istype(I, /obj/item/reagent_containers) && mybucket)
|
||||
var/obj/item/reagent_containers/C = I
|
||||
C.afterattack(mybucket, usr, 1)
|
||||
else if(istype (I, /obj/item/device/lightreplacer))
|
||||
var/obj/item/device/lightreplacer/LR = I
|
||||
if (LR.store_broken)
|
||||
return mybag.attackby(I, usr)
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/attackby(obj/item/attacking_item, mob/user)
|
||||
if(istype(attacking_item, /obj/item/mop) || istype(attacking_item, /obj/item/reagent_containers/glass/rag) || istype(attacking_item, /obj/item/soap))
|
||||
if (mybucket)
|
||||
if(attacking_item.reagents.total_volume < attacking_item.reagents.maximum_volume)
|
||||
if(mybucket.reagents.total_volume < 1)
|
||||
to_chat(user, SPAN_NOTICE("[mybucket] is empty!"))
|
||||
update_icon()
|
||||
else
|
||||
mybucket.reagents.trans_to_obj(attacking_item, 5) //
|
||||
to_chat(user, SPAN_NOTICE("You wet [attacking_item] in [mybucket]."))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("[attacking_item] can't absorb anymore liquid!"))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("There is no bucket mounted here to dip [attacking_item] into!"))
|
||||
return 1
|
||||
|
||||
else if(istype(attacking_item, /obj/item/reagent_containers/spray) && !myspray)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
myspray = attacking_item
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
return 1
|
||||
|
||||
else if(istype(attacking_item, /obj/item/device/lightreplacer) && !myreplacer)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
myreplacer = attacking_item
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
return 1
|
||||
|
||||
else if(istype(attacking_item, /obj/item/storage/bag/trash) && !mybag)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
mybag = attacking_item
|
||||
attacking_item.forceMove(src)
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
return 1
|
||||
|
||||
else if(istype(attacking_item, /obj/item/clothing/suit/caution))
|
||||
if(signs < 4)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
signs++
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("[src] can't hold any more signs."))
|
||||
return 1
|
||||
|
||||
else if(mybag)
|
||||
return mybag.attackby(attacking_item, user)
|
||||
//This return will prevent afterattack from executing if the object goes into the trashbag,
|
||||
//This prevents dumb stuff like splashing the cart with the contents of a container, after putting said container into trash
|
||||
|
||||
else if (!has_items && (attacking_item.iswrench() || attacking_item.iswelder() || istype(attacking_item, /obj/item/gun/energy/plasmacutter)))
|
||||
take_apart(user, attacking_item)
|
||||
return
|
||||
..()
|
||||
|
||||
//This is called if the cart is caught in an explosion, or destroyed by weapon fire
|
||||
/obj/structure/cart/storage/janitorialcart/spill(var/chance = 100)
|
||||
var/turf/dropspot = get_turf(src)
|
||||
if (mymop && prob(chance))
|
||||
mymop.forceMove(dropspot)
|
||||
mymop.tumble(2)
|
||||
mymop = null
|
||||
|
||||
if (myspray && prob(chance))
|
||||
myspray.forceMove(dropspot)
|
||||
myspray.tumble(3)
|
||||
myspray = null
|
||||
|
||||
if (myreplacer && prob(chance))
|
||||
myreplacer.forceMove(dropspot)
|
||||
myreplacer.tumble(3)
|
||||
myreplacer = null
|
||||
|
||||
if (mybucket && prob(chance*0.5))//bucket is heavier, harder to knock off
|
||||
mybucket.forceMove(dropspot)
|
||||
mybucket.tumble(1)
|
||||
mybucket = null
|
||||
|
||||
if (signs)
|
||||
for (var/obj/item/clothing/suit/caution/Sign in src)
|
||||
if (prob(min((chance*2),100)))
|
||||
signs--
|
||||
Sign.forceMove(dropspot)
|
||||
Sign.tumble(3)
|
||||
if (signs < 0)//safety for something that shouldn't happen
|
||||
signs = 0
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if (mybag && prob(min((chance*2),100)))//Bag is flimsy
|
||||
mybag.forceMove(dropspot)
|
||||
mybag.tumble(1)
|
||||
mybag.spill()//trashbag spills its contents too
|
||||
mybag = null
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/attack_hand(mob/user)
|
||||
ui_interact(user)
|
||||
return
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
data["name"] = capitalize(name)
|
||||
data["bag"] = mybag ? capitalize(mybag.name) : null
|
||||
data["bucket"] = mybucket ? capitalize(mybucket.name) : null
|
||||
data["mop"] = mymop ? capitalize(mymop.name) : null
|
||||
data["spray"] = myspray ? capitalize(myspray.name) : null
|
||||
data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null
|
||||
data["signs"] = signs ? "[signs] sign\s" : null
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "janitorcart.tmpl", "Janitorial cart", 240, 160)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/Topic(href, href_list)
|
||||
if(!in_range(src, usr))
|
||||
return
|
||||
if(!isliving(usr))
|
||||
return
|
||||
var/mob/living/user = usr
|
||||
if(href_list["take"])
|
||||
switch(href_list["take"])
|
||||
if("garbage")
|
||||
if(mybag)
|
||||
user.put_in_hands(mybag)
|
||||
to_chat(user, SPAN_NOTICE("You take [mybag] from [src]."))
|
||||
mybag = null
|
||||
if("mop")
|
||||
if(mymop)
|
||||
user.put_in_hands(mymop)
|
||||
to_chat(user, SPAN_NOTICE("You take [mymop] from [src]."))
|
||||
mymop = null
|
||||
if("spray")
|
||||
if(myspray)
|
||||
user.put_in_hands(myspray)
|
||||
to_chat(user, SPAN_NOTICE("You take [myspray] from [src]."))
|
||||
myspray = null
|
||||
if("replacer")
|
||||
if(myreplacer)
|
||||
user.put_in_hands(myreplacer)
|
||||
to_chat(user, SPAN_NOTICE("You take [myreplacer] from [src]."))
|
||||
myreplacer = null
|
||||
if("sign")
|
||||
if(signs)
|
||||
var/obj/item/clothing/suit/caution/Sign = locate() in src
|
||||
if(Sign)
|
||||
user.put_in_hands(Sign)
|
||||
to_chat(user, SPAN_NOTICE("You take \a [Sign] from [src]."))
|
||||
signs--
|
||||
else
|
||||
warning("[src] signs ([signs]) didn't match contents")
|
||||
signs = 0
|
||||
if("bucket")
|
||||
if(mybucket)
|
||||
mybucket.forceMove(get_turf(user))
|
||||
to_chat(user, SPAN_NOTICE("You unmount [mybucket] from [src]."))
|
||||
mybucket.update_icon()
|
||||
mybucket = null
|
||||
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/structure/cart/storage/janitorialcart/update_icon()
|
||||
ClearOverlays()
|
||||
has_items = 0
|
||||
if(mybucket)
|
||||
AddOverlays("cart_bucket")
|
||||
has_items = 1
|
||||
if(mybucket.reagents.total_volume > 0)
|
||||
AddOverlays("cart_water")
|
||||
if(mybag)
|
||||
AddOverlays("cart_garbage")
|
||||
has_items = 1
|
||||
if(mymop)
|
||||
AddOverlays("cart_mop")
|
||||
has_items = 1
|
||||
if(myspray)
|
||||
AddOverlays("cart_spray")
|
||||
has_items = 1
|
||||
if(myreplacer)
|
||||
if (istype(myreplacer, /obj/item/device/lightreplacer/advanced))
|
||||
AddOverlays("cart_adv_lightreplacer")
|
||||
else
|
||||
AddOverlays("cart_replacer")
|
||||
has_items = 1
|
||||
if(signs)
|
||||
AddOverlays("cart_sign[signs]")
|
||||
has_items = 1
|
||||
@@ -0,0 +1,123 @@
|
||||
/obj/structure/cart/storage/parcelcart
|
||||
name = "parcel cart"
|
||||
desc = "A cart for moving parcels and packages around."
|
||||
icon = 'icons/obj/parcelcart.dmi'
|
||||
icon_state = "cart"
|
||||
|
||||
var/list/my_parcels = list()
|
||||
|
||||
/// Amount of parcels the cart is capable to store.
|
||||
var/parcel_capacity = 17
|
||||
|
||||
var/static/list/allowed_types = typecacheof(list(
|
||||
/obj/item/smallDelivery
|
||||
))
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "You can use hand held parcels on the cart to store them."
|
||||
. += "It slows down at 5 packages, and becomes even slower when there is 11 packages or more loaded."
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/get_storage_contents_list()
|
||||
storage_contents.Cut()
|
||||
var/list/lists_to_check = list(
|
||||
my_parcels
|
||||
)
|
||||
for(var/list/list_to_check in lists_to_check)
|
||||
if(list_to_check?.len) //null check
|
||||
storage_contents += list_to_check
|
||||
|
||||
var/list/non_sheet_objects = list(my_parcels)
|
||||
|
||||
for(var/obj/O in non_sheet_objects)
|
||||
if(O)
|
||||
storage_contents += O
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/Destroy()
|
||||
QDEL_NULL(my_parcels)
|
||||
return ..()
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/attackby(obj/item/attacking_item, mob/user)
|
||||
if(is_type_in_typecache(attacking_item, allowed_types))
|
||||
var/should_store = FALSE
|
||||
var/storage_is_full = FALSE
|
||||
if(my_parcels.len < parcel_capacity)
|
||||
my_parcels += attacking_item
|
||||
should_store = TRUE
|
||||
else
|
||||
storage_is_full = TRUE
|
||||
|
||||
handle_storing(attacking_item, user, should_store, storage_is_full)
|
||||
return TRUE
|
||||
|
||||
else if (!has_items && (attacking_item.iswrench() || attacking_item.iswelder() || istype(attacking_item, /obj/item/gun/energy/plasmacutter)))
|
||||
take_apart(user, attacking_item)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/spill(var/chance = 100)
|
||||
var/turf/dropspot = get_turf(src)
|
||||
|
||||
if(LAZYLEN(my_parcels) && prob(chance))
|
||||
var/obj/item/smallDelivery/M
|
||||
for(var/I in my_parcels)
|
||||
M = I
|
||||
M.forceMove(dropspot)
|
||||
M.tumble(1)
|
||||
my_parcels -= M
|
||||
my_parcels.Cut()
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/handle_storing(var/attacking_item, var/mob/user, var/should_store, var/storage_is_full)
|
||||
if(should_store)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
get_storage_contents_list()
|
||||
update_slowdown()
|
||||
update_icon()
|
||||
to_chat(user, SPAN_NOTICE("You put [attacking_item] into [src]."))
|
||||
else if(storage_is_full)
|
||||
to_chat(user, SPAN_WARNING("There isn't any space to store [attacking_item] in [src]!"))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("You can't store this here!"))
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/update_slowdown()
|
||||
if(my_parcels.len <= 4)
|
||||
slowdown = 0
|
||||
else if(my_parcels.len > 4 && my_parcels.len < 11)
|
||||
slowdown = 1
|
||||
else if(my_parcels.len >= 11)
|
||||
slowdown = 2
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/attack_hand(mob/user)
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
if(LAZYLEN(storage_contents))
|
||||
for(var/obj/O in storage_contents)
|
||||
storage_contents[O] = image(O.icon, O.icon_state)
|
||||
|
||||
var/obj/item/chosen_item = show_radial_menu(user, src, storage_contents, require_near = TRUE, tooltips = TRUE)
|
||||
|
||||
if(isnull(chosen_item))
|
||||
return
|
||||
if(chosen_item in storage_contents)
|
||||
switch(chosen_item.type)
|
||||
if(/obj/item/smallDelivery)
|
||||
if(my_parcels.len)
|
||||
user.put_in_hands(chosen_item)
|
||||
to_chat(user, SPAN_NOTICE("You take [my_parcels[chosen_item]] from [src]."))
|
||||
my_parcels -= chosen_item
|
||||
|
||||
get_storage_contents_list()
|
||||
update_slowdown()
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("\The [chosen_item] is not in the cart anymore!"))
|
||||
|
||||
/obj/structure/cart/storage/parcelcart/update_icon()
|
||||
ClearOverlays()
|
||||
has_items = FALSE
|
||||
if(my_parcels.len)
|
||||
var/amount_to_show = min(length(my_parcels), parcel_capacity)
|
||||
AddOverlays("pack_[amount_to_show]")
|
||||
has_items = TRUE
|
||||
Reference in New Issue
Block a user