diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index 8baf695fa..19e8b77bd 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -115,6 +115,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
/obj/item/clothing/shoes/kindleKicks = 1,
/obj/item/autosurgeon/penis = 1,
/obj/item/autosurgeon/testicles = 1,
+ /obj/item/storage/box/marshmallow = 2,
/obj/item/autosurgeon/vagina = 1,
/obj/item/autosurgeon/breasts = 1,
/obj/item/autosurgeon/womb = 1,
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 076afb97f..869f81582 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -58,6 +58,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
null, \
new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("trash bin", /obj/structure/closet/crate/bin, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE),\
null, \
new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 20), \
new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 6c3dbee78..bc4525c28 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -1,441 +1,443 @@
-/*
- * These absorb the functionality of the plant bag, ore satchel, etc
- * They use the use_to_pickup, quick_gather, and quick_empty functions
- * that were already defined in weapon/storage, but which had been
- * re-implemented in other classes.
- *
- * Contains:
- * Trash Bag
- * Mining Satchel
- * Plant Bag
- * Sheet Snatcher
- * Book Bag
- * Biowaste Bag
- *
- * -Sayu
- */
-
-// Generic non-item
-/obj/item/storage/bag
- slot_flags = ITEM_SLOT_BELT
-
-/obj/item/storage/bag/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.allow_quick_gather = TRUE
- STR.allow_quick_empty = TRUE
- STR.display_numerical_stacking = TRUE
- STR.click_gather = TRUE
-
-// -----------------------------
-// Trash bag
-// -----------------------------
-/obj/item/storage/bag/trash
- name = "trash bag"
- desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
- icon = 'icons/obj/janitor.dmi'
- icon_state = "trashbag"
- item_state = "trashbag"
- lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
-
- w_class = WEIGHT_CLASS_BULKY
- var/insertable = TRUE
-
-/obj/item/storage/bag/trash/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_combined_w_class = 30
- STR.max_items = 30
- STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear))
-
-/obj/item/storage/bag/trash/suicide_act(mob/user)
- user.visible_message("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!")
- playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
- return (TOXLOSS)
-
-/obj/item/storage/bag/trash/update_icon()
- if(contents.len == 0)
- icon_state = "[initial(icon_state)]"
- else if(contents.len < 12)
- icon_state = "[initial(icon_state)]1"
- else if(contents.len < 21)
- icon_state = "[initial(icon_state)]2"
- else icon_state = "[initial(icon_state)]3"
-
-/obj/item/storage/bag/trash/cyborg
- insertable = FALSE
-
-/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
- if(insertable)
- J.put_in_cart(src, user)
- J.mybag=src
- J.update_icon()
- else
- to_chat(user, "You are unable to fit your [name] into the [J.name].")
- return
-
-/obj/item/storage/bag/trash/bluespace
- name = "trash bag of holding"
- desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
- icon_state = "bluetrashbag"
- item_flags = NO_MAT_REDEMPTION
-
-/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 60
- STR.max_items = 60
-
-/obj/item/storage/bag/trash/bluespace/cyborg
- insertable = FALSE
-
-// -----------------------------
-// Mining Satchel
-// -----------------------------
-
-/obj/item/storage/bag/ore
- name = "mining satchel"
- desc = "This little bugger can be used to store and transport ores."
- icon = 'icons/obj/mining.dmi'
- icon_state = "satchel"
- slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET
- w_class = WEIGHT_CLASS_NORMAL
- component_type = /datum/component/storage/concrete/stack
- var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
- var/mob/listeningTo
- rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
-
-/obj/item/storage/bag/ore/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.can_hold = typecacheof(list(/obj/item/stack/ore))
- STR.max_w_class = WEIGHT_CLASS_HUGE
- STR.max_combined_stack_amount = 50
-
-/obj/item/storage/bag/ore/equipped(mob/user)
- . = ..()
- if(listeningTo == user)
- return
- if(listeningTo)
- UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
- RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
- listeningTo = user
-
-/obj/item/storage/bag/ore/dropped()
- . = ..()
- UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
- listeningTo = null
-
-/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
- var/show_message = FALSE
- var/obj/structure/ore_box/box
- var/turf/tile = user.loc
- if (!isturf(tile))
- return
- if (istype(user.pulling, /obj/structure/ore_box))
- box = user.pulling
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- if(STR)
- for(var/A in tile)
- if (!is_type_in_typecache(A, STR.can_hold))
- continue
- if (box)
- user.transferItemToLoc(A, box)
- show_message = TRUE
- else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
- show_message = TRUE
- else
- if(!spam_protection)
- to_chat(user, "Your [name] is full and can't hold any more!")
- spam_protection = TRUE
- continue
- if(show_message)
- playsound(user, "rustle", 50, TRUE)
- if (box)
- user.visible_message("[user] offloads the ores beneath [user.p_them()] into [box].", \
- "You offload the ores beneath you into your [box].")
- else
- user.visible_message("[user] scoops up the ores beneath [user.p_them()].", \
- "You scoop up the ores beneath you with your [name].")
- spam_protection = FALSE
-
-/obj/item/storage/bag/ore/cyborg
- name = "cyborg mining satchel"
-
-/obj/item/storage/bag/ore/cyborg/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.can_hold = typecacheof(list(/obj/item/stack/ore))
- STR.max_w_class = WEIGHT_CLASS_HUGE
- STR.max_combined_stack_amount = 150
-
-/obj/item/storage/bag/ore/large
- name = "large mining satchel"
- desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume."
-
-/obj/item/storage/bag/ore/large/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.can_hold = typecacheof(list(/obj/item/stack/ore))
- STR.max_w_class = WEIGHT_CLASS_HUGE
- STR.max_combined_stack_amount = 150
-
-/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
- name = "mining satchel of holding"
- desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
- icon_state = "satchel_bspace"
-
-/obj/item/storage/bag/ore/holding/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.max_items = INFINITY
- STR.max_combined_w_class = INFINITY
- STR.max_combined_stack_amount = INFINITY
-
-// -----------------------------
-// Plant bag
-// -----------------------------
-
-/obj/item/storage/bag/plants
- name = "plant bag"
- icon = 'icons/obj/hydroponics/equipment.dmi'
- icon_state = "plantbag"
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
-
-/obj/item/storage/bag/plants/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 100
- STR.max_items = 100
- STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb))
-
-////////
-
-/obj/item/storage/bag/plants/portaseeder
- name = "portable seed extractor"
- desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
- icon_state = "portaseeder"
-
-/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
- set name = "Activate Seed Extraction"
- set category = "Object"
- set desc = "Activate to convert your plants into plantable seeds."
- if(usr.stat || !usr.canmove || usr.restrained())
- return
- for(var/obj/item/O in contents)
- seedify(O, 1)
-
-// -----------------------------
-// Sheet Snatcher
-// -----------------------------
-// Because it stacks stacks, this doesn't operate normally.
-// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
-
-/obj/item/storage/bag/sheetsnatcher
- name = "sheet snatcher"
- desc = "A patented Kinaris storage system designed for any kind of mineral sheet."
- icon = 'icons/obj/mining.dmi'
- icon_state = "sheetsnatcher"
-
- var/capacity = 300; //the number of sheets it can carry.
- w_class = WEIGHT_CLASS_NORMAL
- component_type = /datum/component/storage/concrete/stack
-
-/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.can_hold = typecacheof(list(/obj/item/stack/sheet))
- STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood))
- STR.max_combined_stack_amount = 300
-
-// -----------------------------
-// Sheet Snatcher (Cyborg)
-// -----------------------------
-
-/obj/item/storage/bag/sheetsnatcher/borg
- name = "sheet snatcher 9000"
- desc = ""
- capacity = 500//Borgs get more because >specialization
-
-/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.max_combined_stack_amount = 500
-
-// -----------------------------
-// Book bag
-// -----------------------------
-
-/obj/item/storage/bag/books
- name = "book bag"
- desc = "A bag for books."
- icon = 'icons/obj/library.dmi'
- icon_state = "bookbag"
- w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
- resistance_flags = FLAMMABLE
-
-/obj/item/storage/bag/books/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
- STR.max_items = 7
- STR.display_numerical_stacking = FALSE
- STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook))
-
-/*
- * Trays - Agouri
- */
-/obj/item/storage/bag/tray
- name = "serving tray"
- icon = 'icons/obj/food/containers.dmi'
- icon_state = "tray"
- desc = "A metal tray to lay food on."
- force = 5
- throwforce = 10
- throw_speed = 3
- throw_range = 5
- w_class = WEIGHT_CLASS_BULKY
- flags_1 = CONDUCT_1
- materials = list(MAT_METAL=3000)
-
-/obj/item/storage/bag/tray/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows stuff such as Bowls, and normal sized foods, to fit.
- STR.can_hold = typecacheof(list(
- /obj/item/reagent_containers/food,
- /obj/item/reagent_containers/glass,
- /obj/item/clothing/mask/cigarette,
- /obj/item/storage/fancy,
- /obj/item/storage/box/matches,
- /obj/item/trash,
- /obj/item/lighter,
- /obj/item/rollingpaper,
- /obj/item/kitchen,
- /obj/item/organ,
- )) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools.
- STR.insert_preposition = "on"
- STR.max_items = 10
-
-/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
- . = ..()
- // Drop all the things. All of them.
- var/list/obj/item/oldContents = contents.Copy()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY)
- // Make each item scatter a bit
- for(var/obj/item/I in oldContents)
- INVOKE_ASYNC(src, .proc/do_scatter, I)
-
- if(prob(50))
- playsound(M, 'sound/items/trayhit1.ogg', 50, TRUE)
- else
- playsound(M, 'sound/items/trayhit2.ogg', 50, TRUE)
-
- if(ishuman(M))
- if(prob(10))
- M.Knockdown(40)
- update_icon()
-
-/obj/item/storage/bag/tray/proc/do_scatter(obj/item/I)
- for(var/i in 1 to rand(1,2))
- if(I)
- step(I, pick(NORTH,SOUTH,EAST,WEST))
- sleep(rand(2,4))
-
-/obj/item/storage/bag/tray/update_overlays()
- . = ..()
- for(var/obj/item/I in contents)
- var/mutable_appearance/I_copy = new(I)
- I_copy.plane = FLOAT_PLANE
- I_copy.layer = FLOAT_LAYER
- . += I_copy
-
-/obj/item/storage/bag/tray/Entered()
- . = ..()
- update_icon()
-
-/obj/item/storage/bag/tray/Exited()
- . = ..()
- update_icon()
-
-/*
- * Chemistry bag
- */
-
-/obj/item/storage/bag/chemistry
- name = "chemistry bag"
- icon = 'icons/obj/chemical.dmi'
- icon_state = "bag"
- desc = "A bag for storing pills, patches, and bottles."
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
-
-/obj/item/storage/bag/chemistry/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 50
- STR.insert_preposition = "in"
- STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack))
-
-/*
- * Biowaste bag (mostly for xenobiologists)
- */
-
-/obj/item/storage/bag/bio
- name = "bio bag"
- icon = 'icons/obj/chemical.dmi'
- icon_state = "biobag"
- desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
-
-/obj/item/storage/bag/bio/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 25
- STR.insert_preposition = "in"
- STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube))
-
-/obj/item/storage/bag/bio/holding
- name = "bio bag of holding"
- icon = 'icons/obj/chemical.dmi'
- icon_state = "bspace_biobag"
- desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
-
-/obj/item/storage/bag/bio/holding/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = INFINITY
- STR.max_items = 100
-
-/*
- * Construction bag (for engineering, holds stock parts and electronics)
- */
-
-/obj/item/storage/bag/construction
- name = "construction bag"
- icon = 'icons/obj/tools.dmi'
- icon_state = "construction_bag"
- desc = "A bag for storing small construction components."
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
-
-/obj/item/storage/bag/construction/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 100
- STR.max_items = 50
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.insert_preposition = "in"
- STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics))
+/*
+ * These absorb the functionality of the plant bag, ore satchel, etc
+ * They use the use_to_pickup, quick_gather, and quick_empty functions
+ * that were already defined in weapon/storage, but which had been
+ * re-implemented in other classes.
+ *
+ * Contains:
+ * Trash Bag
+ * Mining Satchel
+ * Plant Bag
+ * Sheet Snatcher
+ * Book Bag
+ * Biowaste Bag
+ *
+ * -Sayu
+ */
+
+// Generic non-item
+/obj/item/storage/bag
+ slot_flags = ITEM_SLOT_BELT
+
+/obj/item/storage/bag/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.allow_quick_gather = TRUE
+ STR.allow_quick_empty = TRUE
+ STR.display_numerical_stacking = TRUE
+ STR.click_gather = TRUE
+
+// -----------------------------
+// Trash bag
+// -----------------------------
+/obj/item/storage/bag/trash
+ name = "trash bag"
+ desc = "It's the heavy-duty black polymer kind. Time to take out the trash!"
+ icon = 'icons/obj/janitor.dmi'
+ icon_state = "trashbag"
+ item_state = "trashbag"
+ lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
+
+ w_class = WEIGHT_CLASS_BULKY
+ var/insertable = TRUE
+
+/obj/item/storage/bag/trash/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_SMALL
+ STR.max_combined_w_class = 30
+ STR.max_items = 30
+ STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear))
+
+/obj/item/storage/bag/trash/suicide_act(mob/user)
+ user.visible_message("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!")
+ playsound(loc, 'sound/items/eatfood.ogg', 50, 1, -1)
+ return (TOXLOSS)
+
+/obj/item/storage/bag/trash/update_icon()
+ if(contents.len == 0)
+ icon_state = "[initial(icon_state)]"
+ else if(contents.len < 12)
+ icon_state = "[initial(icon_state)]1"
+ else if(contents.len < 21)
+ icon_state = "[initial(icon_state)]2"
+ else icon_state = "[initial(icon_state)]3"
+
+/obj/item/storage/bag/trash/cyborg
+ insertable = FALSE
+
+/obj/item/storage/bag/trash/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
+ if(insertable)
+ J.put_in_cart(src, user)
+ J.mybag=src
+ J.update_icon()
+ else
+ to_chat(user, "You are unable to fit your [name] into the [J.name].")
+ return
+
+/obj/item/storage/bag/trash/bluespace
+ name = "trash bag of holding"
+ desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage."
+ icon_state = "bluetrashbag"
+ item_flags = NO_MAT_REDEMPTION
+
+/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = 60
+ STR.max_items = 60
+
+/obj/item/storage/bag/trash/bluespace/cyborg
+ insertable = FALSE
+
+// -----------------------------
+// Mining Satchel
+// -----------------------------
+
+/obj/item/storage/bag/ore
+ name = "mining satchel"
+ desc = "This little bugger can be used to store and transport ores."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "satchel"
+ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKET
+ w_class = WEIGHT_CLASS_NORMAL
+ component_type = /datum/component/storage/concrete/stack
+ var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
+ var/mob/listeningTo
+ rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
+
+/obj/item/storage/bag/ore/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.allow_quick_empty = TRUE
+ STR.can_hold = typecacheof(list(/obj/item/stack/ore))
+ STR.max_w_class = WEIGHT_CLASS_HUGE
+ STR.max_combined_stack_amount = 50
+
+/obj/item/storage/bag/ore/equipped(mob/user)
+ . = ..()
+ if(listeningTo == user)
+ return
+ if(listeningTo)
+ UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
+ listeningTo = user
+
+/obj/item/storage/bag/ore/dropped()
+ . = ..()
+ UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
+ listeningTo = null
+
+/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
+ var/show_message = FALSE
+ var/obj/structure/ore_box/box
+ var/turf/tile = user.loc
+ if (!isturf(tile))
+ return
+ if (istype(user.pulling, /obj/structure/ore_box))
+ box = user.pulling
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ if(STR)
+ for(var/A in tile)
+ if (!is_type_in_typecache(A, STR.can_hold))
+ continue
+ if (box)
+ user.transferItemToLoc(A, box)
+ show_message = TRUE
+ else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
+ show_message = TRUE
+ else
+ if(!spam_protection)
+ to_chat(user, "Your [name] is full and can't hold any more!")
+ spam_protection = TRUE
+ continue
+ if(show_message)
+ playsound(user, "rustle", 50, TRUE)
+ if (box)
+ user.visible_message("[user] offloads the ores beneath [user.p_them()] into [box].", \
+ "You offload the ores beneath you into your [box].")
+ else
+ user.visible_message("[user] scoops up the ores beneath [user.p_them()].", \
+ "You scoop up the ores beneath you with your [name].")
+ spam_protection = FALSE
+
+/obj/item/storage/bag/ore/cyborg
+ name = "cyborg mining satchel"
+
+/obj/item/storage/bag/ore/cyborg/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.allow_quick_empty = TRUE
+ STR.can_hold = typecacheof(list(/obj/item/stack/ore))
+ STR.max_w_class = WEIGHT_CLASS_HUGE
+ STR.max_combined_stack_amount = 150
+
+/obj/item/storage/bag/ore/large
+ name = "large mining satchel"
+ desc = "This bag can hold three times the ore in many small pockets. Shockingly foldable and compact for its volume."
+
+/obj/item/storage/bag/ore/large/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.allow_quick_empty = TRUE
+ STR.can_hold = typecacheof(list(/obj/item/stack/ore))
+ STR.max_w_class = WEIGHT_CLASS_HUGE
+ STR.max_combined_stack_amount = 150
+
+/obj/item/storage/bag/ore/holding //miners, your messiah has arrived
+ name = "mining satchel of holding"
+ desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
+ icon_state = "satchel_bspace"
+
+/obj/item/storage/bag/ore/holding/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.max_items = INFINITY
+ STR.max_combined_w_class = INFINITY
+ STR.max_combined_stack_amount = INFINITY
+
+// -----------------------------
+// Plant bag
+// -----------------------------
+
+/obj/item/storage/bag/plants
+ name = "plant bag"
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "plantbag"
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/plants/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL
+ STR.max_combined_w_class = 100
+ STR.max_items = 100
+ STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb))
+
+////////
+
+/obj/item/storage/bag/plants/portaseeder
+ name = "portable seed extractor"
+ desc = "For the enterprising botanist on the go. Less efficient than the stationary model, it creates one seed per plant."
+ icon_state = "portaseeder"
+
+/obj/item/storage/bag/plants/portaseeder/verb/dissolve_contents()
+ set name = "Activate Seed Extraction"
+ set category = "Object"
+ set desc = "Activate to convert your plants into plantable seeds."
+ if(usr.stat || !usr.canmove || usr.restrained())
+ return
+ for(var/obj/item/O in contents)
+ seedify(O, 1)
+
+// -----------------------------
+// Sheet Snatcher
+// -----------------------------
+// Because it stacks stacks, this doesn't operate normally.
+// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
+
+/obj/item/storage/bag/sheetsnatcher
+ name = "sheet snatcher"
+ desc = "A patented Kinaris storage system designed for any kind of mineral sheet."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "sheetsnatcher"
+
+ var/capacity = 300; //the number of sheets it can carry.
+ w_class = WEIGHT_CLASS_NORMAL
+ component_type = /datum/component/storage/concrete/stack
+
+/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.allow_quick_empty = TRUE
+ STR.can_hold = typecacheof(list(/obj/item/stack/sheet))
+ STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood))
+ STR.max_combined_stack_amount = 300
+
+// -----------------------------
+// Sheet Snatcher (Cyborg)
+// -----------------------------
+
+/obj/item/storage/bag/sheetsnatcher/borg
+ name = "sheet snatcher 9000"
+ desc = ""
+ capacity = 500//Borgs get more because >specialization
+
+/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
+ STR.max_combined_stack_amount = 500
+
+// -----------------------------
+// Book bag
+// -----------------------------
+
+/obj/item/storage/bag/books
+ name = "book bag"
+ desc = "A bag for books."
+ icon = 'icons/obj/library.dmi'
+ icon_state = "bookbag"
+ w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/books/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL
+ STR.max_combined_w_class = 21
+ STR.max_items = 7
+ STR.display_numerical_stacking = FALSE
+ STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook))
+
+/*
+ * Trays - Agouri
+ */
+/obj/item/storage/bag/tray
+ name = "serving tray"
+ icon = 'icons/obj/food/containers.dmi'
+ icon_state = "tray"
+ desc = "A metal tray to lay food on."
+ force = 5
+ throwforce = 10
+ throw_speed = 3
+ throw_range = 5
+ w_class = WEIGHT_CLASS_BULKY
+ flags_1 = CONDUCT_1
+ materials = list(MAT_METAL=3000)
+
+/obj/item/storage/bag/tray/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows stuff such as Bowls, and normal sized foods, to fit.
+ STR.can_hold = typecacheof(list(
+ /obj/item/reagent_containers/food,
+ /obj/item/reagent_containers/glass,
+ /obj/item/clothing/mask/cigarette,
+ /obj/item/storage/fancy,
+ /obj/item/storage/box/matches,
+ /obj/item/trash,
+ /obj/item/lighter,
+ /obj/item/rollingpaper,
+ /obj/item/kitchen,
+ /obj/item/organ,
+ )) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools.
+ STR.insert_preposition = "on"
+ STR.max_items = 10
+
+/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
+ . = ..()
+ // Drop all the things. All of them.
+ var/list/obj/item/oldContents = contents.Copy()
+ SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY)
+ // Make each item scatter a bit
+ for(var/obj/item/I in oldContents)
+ INVOKE_ASYNC(src, .proc/do_scatter, I)
+
+ if(prob(50))
+ playsound(M, 'sound/items/trayhit1.ogg', 50, TRUE)
+ else
+ playsound(M, 'sound/items/trayhit2.ogg', 50, TRUE)
+
+ if(ishuman(M))
+ if(prob(10))
+ M.Knockdown(40)
+ update_icon()
+
+/obj/item/storage/bag/tray/proc/do_scatter(obj/item/I)
+ for(var/i in 1 to rand(1,2))
+ if(I)
+ step(I, pick(NORTH,SOUTH,EAST,WEST))
+ sleep(rand(2,4))
+
+/obj/item/storage/bag/tray/update_overlays()
+ . = ..()
+ for(var/obj/item/I in contents)
+ var/mutable_appearance/I_copy = new(I)
+ I_copy.plane = FLOAT_PLANE
+ I_copy.layer = FLOAT_LAYER
+ . += I_copy
+
+/obj/item/storage/bag/tray/Entered()
+ . = ..()
+ update_icon()
+
+/obj/item/storage/bag/tray/Exited()
+ . = ..()
+ update_icon()
+
+/*
+ * Chemistry bag
+ */
+
+/obj/item/storage/bag/chemistry
+ name = "chemistry bag"
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "bag"
+ desc = "A bag for storing pills, patches, and bottles."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/chemistry/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = 200
+ STR.max_items = 50
+ STR.insert_preposition = "in"
+ STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack))
+
+/*
+ * Biowaste bag (mostly for xenobiologists)
+ */
+
+/obj/item/storage/bag/bio
+ name = "bio bag"
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "biobag"
+ desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/bio/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL //Allows you to pick up Lungs, Liver, and Stomach
+ STR.max_combined_w_class = 200
+ STR.max_items = 25
+ STR.insert_preposition = "in"
+ STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube, /obj/item/organ, /obj/item/reagent_containers/food/snacks/meat/slab, /obj/item/bodypart))
+ STR.cant_hold = typecacheof(list(/obj/item/organ/brain, /obj/item/organ/liver/cybernetic, /obj/item/organ/heart/cybernetic, /obj/item/organ/lungs/cybernetic, /obj/item/organ/tongue/cybernetic, /obj/item/organ/ears/cybernetic, /obj/item/organ/eyes/robotic, /obj/item/organ/cyberimp))
+
+/obj/item/storage/bag/bio/holding
+ name = "bio bag of holding"
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "bspace_biobag"
+ desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
+
+/obj/item/storage/bag/bio/holding/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = INFINITY
+ STR.max_items = 100
+
+/*
+ * Construction bag (for engineering, holds stock parts and electronics)
+ */
+
+/obj/item/storage/bag/construction
+ name = "construction bag"
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "construction_bag"
+ desc = "A bag for storing small construction components."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/construction/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = 100
+ STR.max_items = 50
+ STR.max_w_class = WEIGHT_CLASS_SMALL
+ STR.insert_preposition = "in"
+ STR.can_hold = typecacheof(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics))
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 7298839c9..278ecb93e 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -1317,3 +1317,12 @@
var/obj/item/stack/sheet/cardboard/I = new(user.drop_location())
qdel(src)
user.put_in_hands(I)
+
+/obj/item/storage/box/marshmallow
+ name = "box of marshmallows"
+ desc = "A box of marshmallows."
+ icon_state = "marshmallowbox"
+
+/obj/item/storage/box/marshmallow/PopulateContents()
+ for (var/i in 1 to 5)
+ new /obj/item/reagent_containers/food/snacks/marshmallow(src)
diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm
index 7646fdb35..bc3697a55 100644
--- a/code/game/objects/structures/crates_lockers/crates/bins.dm
+++ b/code/game/objects/structures/crates_lockers/crates/bins.dm
@@ -4,8 +4,8 @@
icon_state = "largebins"
open_sound = 'sound/effects/bin_open.ogg'
close_sound = 'sound/effects/bin_close.ogg'
- material_drop = /obj/item/stack/sheet/plastic
- material_drop_amount = 40
+ material_drop = /obj/item/stack/sheet/metal
+ material_drop_amount = 10
anchored = TRUE
horizontal = FALSE
delivery_icon = null
diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm
index ea4d09e7c..c70dd8470 100644
--- a/code/modules/cargo/exports/large_objects.dm
+++ b/code/modules/cargo/exports/large_objects.dm
@@ -6,7 +6,7 @@
k_elasticity = 0
unit_name = "crate"
export_types = list(/obj/structure/closet/crate)
- exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden)
+ exclude_types = list(/obj/structure/closet/crate/large, /obj/structure/closet/crate/wooden, /obj/structure/closet/crate/bin)
/datum/export/large/crate/total_printout(datum/export_report/ex, notes = TRUE) // That's why a goddamn metal crate costs that much.
. = ..()
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index f4ebd218e..7cb5e3df4 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -252,13 +252,17 @@
*/
/obj/item/reagent_containers/food/drinks/mug/on_reagent_change(changetype)
+ cut_overlays()
if(reagents.total_volume)
- icon_state = "tea"
+ var/mutable_appearance/MA = mutable_appearance(icon,"mugoverlay")
+ MA.color = mix_color_from_reagents(reagents.reagent_list)
+ add_overlay(MA)
else
icon_state = "tea_empty"
/obj/item/reagent_containers/food/drinks/mug/tea
name = "Duke Purple tea"
+ icon_state = "tea"
desc = "An insult to Duke Purple is an insult to the Space Queen! Any proper gentleman will fight you, if you sully this tea."
list_reagents = list(/datum/reagent/consumable/tea = 30)
price = 2
@@ -266,6 +270,7 @@
/obj/item/reagent_containers/food/drinks/mug/coco
name = "Dutch hot coco"
desc = "Made in Space South America."
+ icon_state = "coco"
list_reagents = list(/datum/reagent/consumable/hot_coco = 30, /datum/reagent/consumable/sugar = 5)
foodtype = SUGAR
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index 5c81722e9..69d943681 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -26,7 +26,7 @@
/datum/reagent/consumable/sugar = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!"),
/datum/reagent/consumable/mayonnaise = list("mayonnaise", "mayonnaise jar", "An oily condiment made from egg yolks."),
/datum/reagent/consumable/bbqsauce = list("bbqsauce", "BBQ sauce", "Hand wipes not included."),
- /datum/reagent/consumable/peanut_butter = list("peanutbutter", "peanut butter jar", "A deliciously and sticky spread made from peanuts."))
+ /datum/reagent/consumable/peanut_butter = list("peanut_butter", "peanut butter jar", "A deliciously and sticky spread made from peanuts."))
var/originalname = "condiment" //Can't use initial(name) for this. This stores the name set by condimasters.
/obj/item/reagent_containers/food/condiment/suicide_act(mob/living/carbon/user)
diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm
index f01966a0f..c65e42c0e 100644
--- a/code/modules/food_and_drinks/food/snacks_egg.dm
+++ b/code/modules/food_and_drinks/food/snacks_egg.dm
@@ -96,6 +96,16 @@
tastes = list("egg" = 4, "salt" = 1, "pepper" = 1)
foodtype = MEAT | FRIED | BREAKFAST
+/obj/item/reagent_containers/food/snacks/baconegg
+ name = "bacon and eggs"
+ desc = "A fried egg with a side of bacon. Delicious!"
+ icon_state = "baconegg"
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ bitesize = 1
+ filling_color = "#FFFFF0"
+ tastes = list("egg" = 2, "bacon" = 2, "salt" = 1, "pepper" = 1)
+ foodtype = MEAT | FRIED | BREAKFAST
+
/obj/item/reagent_containers/food/snacks/boiledegg
name = "boiled egg"
desc = "A hard boiled egg."
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index a2b65e3e0..d4569ffaf 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -625,3 +625,42 @@
tastes = list("fried corn" = 1)
foodtype = JUNKFOOD | FRIED
dunkable = TRUE
+
+/obj/item/reagent_containers/food/snacks/marshmallow
+ name = "marshmallow"
+ desc = "A marshmallow filled with fluffy marshmallow fluff."
+ icon_state = "marshmallow"
+ list_reagents = list("sugar" = 5, "nutriment" = 2)
+ filling_color = "#fafafa"
+ w_class = WEIGHT_CLASS_TINY
+ tastes = list("marshmallow" = 2)
+ foodtype = SUGAR | JUNKFOOD
+
+/obj/item/reagent_containers/food/snacks/marshmallow/attackby(obj/item/I, mob/user)
+ switch (I.get_temperature())
+ if (355 to 1500)
+ if (prob(30))
+ burnmallow()
+ if (1500 to 2000)
+ if (prob(50))
+ burnmallow()
+ else
+ burnmallow(TRUE)
+ if (2000 to 3000)
+ if (prob(10))
+ burnmallow()
+ else
+ burnmallow(TRUE)
+ if (3000 to INFINITY)
+ burnmallow(TRUE)
+ ..()
+
+/obj/item/reagent_containers/food/snacks/marshmallow/proc/burnmallow(reallyburned = FALSE)
+ if (reallyburned && icon_state != "marshmallowrburned")
+ icon_state = "marshmallowrburned"
+ desc = "[initial(desc)] It looks very burned."
+ tastes = list("charcoal" = 2)
+ else if (icon_state != "marshmallowrburned")
+ icon_state = "marshmallowburned"
+ desc = "[initial(desc)] It looks just right for eating!"
+ tastes = list("marshmallow" = 1, "cream" = 1)
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index 3e6f57ba4..e01b770ba 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -364,6 +364,13 @@
tastes = list("muffin" = 3, "spookiness" = 1)
foodtype = GRAIN | FRUIT | SUGAR | BREAKFAST
+/obj/item/reagent_containers/food/snacks/muffin/poppy
+ name = "poppy muffin"
+ icon_state = "poppymuffin"
+ desc = "A classic lemon poppy seed muffin. Do not consume prior to drug testing."
+ tastes = list("muffin" = 3, "lemon" = 1, "seeds" = 1)
+ foodtype = GRAIN | SUGAR | BREAKFAST
+
/obj/item/reagent_containers/food/snacks/chawanmushi
name = "chawanmushi"
desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat."
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
index 6d495d1c7..c049cd756 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
@@ -13,6 +13,15 @@
result = /obj/item/reagent_containers/food/snacks/friedegg
subcategory = CAT_EGG
+/datum/crafting_recipe/food/baconegg
+ name = "Bacon and Eggs"
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/friedegg = 1,
+ /obj/item/reagent_containers/food/snacks/meat/bacon = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/baconegg
+ subcategory = CAT_EGG
+
/datum/crafting_recipe/food/omelette
name = "Omelette"
reqs = list(
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
index d21649a04..7c34fc8c2 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
@@ -574,6 +574,17 @@ datum/crafting_recipe/food/donut/meat
result = /obj/item/reagent_containers/food/snacks/muffin/booberry
subcategory = CAT_PASTRY
+/datum/crafting_recipe/food/poppymuffin
+ name = "Poppy muffin"
+ reqs = list(
+ /datum/reagent/consumable/milk = 5,
+ /obj/item/reagent_containers/food/snacks/pastrybase = 1,
+ /obj/item/reagent_containers/food/snacks/grown/citrus/lemon = 1,
+ /obj/item/seeds/poppy = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/muffin/poppy
+ subcategory = CAT_PASTRY
+
/datum/crafting_recipe/food/chawanmushi
name = "Chawanmushi"
reqs = list(
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index b5384f8ae..36c0945f6 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -384,7 +384,7 @@
name = "Hot Chocolate"
description = "Made with love! And coco beans."
nutriment_factor = 3 * REAGENTS_METABOLISM
- color = "#403010" // rgb: 64, 48, 16
+ color = "#660000" // rgb: 221, 202, 134
taste_description = "creamy chocolate"
glass_icon_state = "chocolateglass"
glass_name = "glass of chocolate"
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index e42694055..70659d45e 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -1,314 +1,315 @@
-/obj/item/reagent_containers/spray
- name = "spray bottle"
- desc = "A spray bottle, with an unscrewable top."
- icon = 'icons/obj/janitor.dmi'
- icon_state = "cleaner"
- item_state = "cleaner"
- lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
- item_flags = NOBLUDGEON
- reagent_flags = OPENCONTAINER
- slot_flags = ITEM_SLOT_BELT
- throwforce = 0
- w_class = WEIGHT_CLASS_SMALL
- throw_speed = 3
- throw_range = 7
- var/stream_mode = 0 //whether we use the more focused mode
- var/current_range = 3 //the range of tiles the sprayer will reach.
- var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode.
- var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode.
- var/stream_amount = 10 //the amount of reagents transfered when in stream mode.
- var/spray_delay = 3 //The amount of sleep() delay between each chempuff step.
- var/can_fill_from_container = TRUE
- amount_per_transfer_from_this = 5
- volume = 250
- possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
-
-/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
- . = ..()
- if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
- return
-
- if((A.is_drainable() && !A.is_refillable()) && get_dist(src,A) <= 1 && can_fill_from_container)
- if(!A.reagents.total_volume)
- to_chat(user, "[A] is empty.")
- return
-
- if(reagents.holder_full())
- to_chat(user, "[src] is full.")
- return
-
- var/trans = A.reagents.trans_to(src, 50) //transfer 50u , using the spray's transfer amount would take too long to refill
- to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [A].")
- return
-
- if(reagents.total_volume < amount_per_transfer_from_this)
- to_chat(user, "[src] is empty!")
- return
-
- spray(A)
-
- playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
- user.changeNext_move(CLICK_CD_RANGE*2)
- user.newtonian_move(get_dir(A, user))
- var/turf/T = get_turf(src)
- if(reagents.has_reagent(/datum/reagent/toxin/acid))
- message_admins("[ADMIN_LOOKUPFLW(user)] fired sulphuric acid from \a [src] at [ADMIN_VERBOSEJMP(T)].")
- log_game("[key_name(user)] fired sulphuric acid from \a [src] at [AREACOORD(T)].")
- if(reagents.has_reagent(/datum/reagent/toxin/acid/fluacid))
- message_admins("[ADMIN_LOOKUPFLW(user)] fired Fluacid from \a [src] at [ADMIN_VERBOSEJMP(T)].")
- log_game("[key_name(user)] fired Fluacid from \a [src] at [AREACOORD(T)].")
- if(reagents.has_reagent(/datum/reagent/lube))
- message_admins("[ADMIN_LOOKUPFLW(user)] fired Space lube from \a [src] at [ADMIN_VERBOSEJMP(T)].")
- log_game("[key_name(user)] fired Space lube from \a [src] at [AREACOORD(T)].")
- return
-
-/obj/item/reagent_containers/spray/proc/spray(atom/A)
- var/range = CLAMP(get_dist(src, A), 1, current_range)
- var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src))
- D.create_reagents(amount_per_transfer_from_this)
- var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed
- if(stream_mode)
- reagents.trans_to(D, amount_per_transfer_from_this)
- puff_reagent_left = 1
- else
- reagents.trans_to(D, amount_per_transfer_from_this, 1/range)
- D.color = mix_color_from_reagents(D.reagents.reagent_list)
- var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2)
- do_spray(A, wait_step, D, range, puff_reagent_left)
-
-/obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left)
- set waitfor = FALSE
- var/range_left = range
- for(var/i=0, i 0 && (!stream_mode || !range_left))
- D.reagents.reaction(get_turf(D), VAPOR)
- puff_reagent_left -= 1
-
- if(puff_reagent_left <= 0) // we used all the puff so we delete it.
- qdel(D)
- return
- qdel(D)
-
-/obj/item/reagent_containers/spray/attack_self(mob/user)
- stream_mode = !stream_mode
- if(stream_mode)
- amount_per_transfer_from_this = stream_amount
- current_range = stream_range
- else
- amount_per_transfer_from_this = initial(amount_per_transfer_from_this)
- current_range = spray_range
- to_chat(user, "You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""]. You'll now use [amount_per_transfer_from_this] units per use.")
-
-/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, params)
- var/hotness = I.is_hot()
- if(hotness && reagents)
- reagents.expose_temperature(hotness)
- to_chat(user, "You heat [name] with [I]!")
- return ..()
-
-/obj/item/reagent_containers/spray/verb/empty()
- set name = "Empty Spray Bottle"
- set category = "Object"
- set src in usr
- if(usr.incapacitated())
- return
- if (alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", "Yes", "No") != "Yes")
- return
- if(isturf(usr.loc) && src.loc == usr)
- to_chat(usr, "You empty \the [src] onto the floor.")
- reagents.reaction(usr.loc)
- src.reagents.clear_reagents()
-
-//space cleaner
-/obj/item/reagent_containers/spray/cleaner
- name = "space cleaner"
- desc = "BLAM!-brand non-foaming space cleaner!"
- volume = 100
- list_reagents = list(/datum/reagent/space_cleaner = 100)
- amount_per_transfer_from_this = 2
- stream_amount = 5
-
-/obj/item/reagent_containers/spray/cleaner/suicide_act(mob/user)
- user.visible_message("[user] is putting the nozzle of \the [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!")
- if(do_mob(user,user,30))
- if(reagents.total_volume >= amount_per_transfer_from_this)//if not empty
- user.visible_message("[user] pulls the trigger!")
- src.spray(user)
- return BRUTELOSS
- else
- user.visible_message("[user] pulls the trigger...but \the [src] is empty!")
- return SHAME
- else
- user.visible_message("[user] decided life was worth living.")
- return
-
-//Drying Agent
-/obj/item/reagent_containers/spray/drying_agent
- name = "drying agent spray"
- desc = "A spray bottle for drying agent."
- volume = 100
- list_reagents = list(/datum/reagent/drying_agent = 100)
- amount_per_transfer_from_this = 2
- stream_amount = 5
-
-//spray tan
-/obj/item/reagent_containers/spray/spraytan
- name = "spray tan"
- volume = 50
- desc = "Gyaro brand spray tan. Do not spray near eyes or other orifices."
- list_reagents = list(/datum/reagent/spraytan = 50)
-
-
-//pepperspray
-/obj/item/reagent_containers/spray/pepper
- name = "pepperspray"
- desc = "Manufactured by UhangInc, used to blind and down an opponent quickly."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "pepperspray"
- item_state = "pepperspray"
- lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- volume = 40
- stream_range = 4
- spray_delay = 1
- amount_per_transfer_from_this = 5
- list_reagents = list(/datum/reagent/consumable/condensedcapsaicin = 40)
-
-/obj/item/reagent_containers/spray/pepper/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins huffing \the [src]! It looks like [user.p_theyre()] getting a dirty high!")
- return OXYLOSS
-
-// Fix pepperspraying yourself
-/obj/item/reagent_containers/spray/pepper/afterattack(atom/A as mob|obj, mob/user)
- if (A.loc == user)
- return
- . = ..()
-
-//water flower
-/obj/item/reagent_containers/spray/waterflower
- name = "water flower"
- desc = "A seemingly innocent sunflower...with a twist."
- icon = 'icons/obj/hydroponics/harvest.dmi'
- icon_state = "sunflower"
- item_state = "sunflower"
- amount_per_transfer_from_this = 1
- volume = 10
- list_reagents = list(/datum/reagent/water = 10)
-
-/obj/item/reagent_containers/spray/waterflower/attack_self(mob/user) //Don't allow changing how much the flower sprays
- return
-
-/obj/item/reagent_containers/spray/waterflower/cyborg
- reagent_flags = NONE
- volume = 100
- list_reagents = list(/datum/reagent/water = 100)
- var/generate_amount = 5
- var/generate_type = /datum/reagent/water
- var/last_generate = 0
- var/generate_delay = 10 //deciseconds
- can_fill_from_container = FALSE
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/hacked
- name = "nova flower"
- desc = "This doesn't look safe at all..."
- list_reagents = list(/datum/reagent/clf3 = 3)
- volume = 3
- generate_type = /datum/reagent/clf3
- generate_amount = 1
- generate_delay = 40 //deciseconds
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/Initialize()
- . = ..()
- START_PROCESSING(SSfastprocess, src)
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- return ..()
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/process()
- if(world.time < last_generate + generate_delay)
- return
- last_generate = world.time
- generate_reagents()
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/empty()
- to_chat(usr, "You can not empty this!")
- return
-
-/obj/item/reagent_containers/spray/waterflower/cyborg/proc/generate_reagents()
- reagents.add_reagent(generate_type, generate_amount)
-
-//chemsprayer
-/obj/item/reagent_containers/spray/chemsprayer
- name = "chem sprayer"
- desc = "A utility used to spray large amounts of reagents in a given area."
- icon = 'icons/obj/guns/projectile.dmi'
- icon_state = "chemsprayer"
- item_state = "chemsprayer"
- lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
- throwforce = 0
- w_class = WEIGHT_CLASS_NORMAL
- stream_mode = 1
- current_range = 7
- spray_range = 4
- stream_range = 7
- amount_per_transfer_from_this = 10
- volume = 600
-
-/obj/item/reagent_containers/spray/chemsprayer/afterattack(atom/A as mob|obj, mob/user)
- // Make it so the bioterror spray doesn't spray yourself when you click your inventory items
- if (A.loc == user)
- return
- . = ..()
-
-/obj/item/reagent_containers/spray/chemsprayer/spray(atom/A)
- var/direction = get_dir(src, A)
- var/turf/T = get_turf(A)
- var/turf/T1 = get_step(T,turn(direction, 90))
- var/turf/T2 = get_step(T,turn(direction, -90))
- var/list/the_targets = list(T,T1,T2)
-
- for(var/i=1, i<=3, i++) // intialize sprays
- if(reagents.total_volume < 1)
- return
- ..(the_targets[i])
-
-/obj/item/reagent_containers/spray/chemsprayer/bioterror
- list_reagents = list(/datum/reagent/toxin/sodium_thiopental = 100, /datum/reagent/toxin/coniine = 100, /datum/reagent/toxin/venom = 100, /datum/reagent/consumable/condensedcapsaicin = 100, /datum/reagent/toxin/initropidril = 100, /datum/reagent/toxin/polonium = 100)
-
-// Plant-B-Gone
-/obj/item/reagent_containers/spray/plantbgone // -- Skie
- name = "Plant-B-Gone"
- desc = "Kills those pesky weeds!"
- icon = 'icons/obj/hydroponics/equipment.dmi'
- icon_state = "plantbgone"
- item_state = "plantbgone"
- lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
- volume = 50
- list_reagents = list(/datum/reagent/toxin/plantbgone = 50)
+/obj/item/reagent_containers/spray
+ name = "spray bottle"
+ desc = "A spray bottle, with an unscrewable top."
+ icon = 'icons/obj/janitor.dmi'
+ icon_state = "cleaner"
+ item_state = "cleaner"
+ lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
+ item_flags = NOBLUDGEON
+ reagent_flags = OPENCONTAINER
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 0
+ w_class = WEIGHT_CLASS_SMALL
+ throw_speed = 3
+ throw_range = 7
+ var/stream_mode = 0 //whether we use the more focused mode
+ var/current_range = 3 //the range of tiles the sprayer will reach.
+ var/spray_range = 3 //the range of tiles the sprayer will reach when in spray mode.
+ var/stream_range = 1 //the range of tiles the sprayer will reach when in stream mode.
+ var/stream_amount = 10 //the amount of reagents transfered when in stream mode.
+ var/spray_delay = 3 //The amount of sleep() delay between each chempuff step.
+ var/can_fill_from_container = TRUE
+ amount_per_transfer_from_this = 5
+ volume = 250
+ possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
+
+/obj/item/reagent_containers/spray/afterattack(atom/A, mob/user)
+ . = ..()
+ if(istype(A, /obj/structure/sink) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/machinery/hydroponics))
+ return
+
+ if((A.is_drainable() && !A.is_refillable()) && get_dist(src,A) <= 1 && can_fill_from_container)
+ if(!A.reagents.total_volume)
+ to_chat(user, "[A] is empty.")
+ return
+
+ if(reagents.holder_full())
+ to_chat(user, "[src] is full.")
+ return
+
+ var/trans = A.reagents.trans_to(src, 50) //transfer 50u , using the spray's transfer amount would take too long to refill
+ to_chat(user, "You fill \the [src] with [trans] units of the contents of \the [A].")
+ return
+
+ if(reagents.total_volume < amount_per_transfer_from_this)
+ to_chat(user, "[src] is empty!")
+ return
+
+ spray(A)
+
+ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1, -6)
+ user.changeNext_move(CLICK_CD_RANGE*2)
+ user.newtonian_move(get_dir(A, user))
+ var/turf/T = get_turf(src)
+ if(reagents.has_reagent(/datum/reagent/toxin/acid))
+ message_admins("[ADMIN_LOOKUPFLW(user)] fired sulphuric acid from \a [src] at [ADMIN_VERBOSEJMP(T)].")
+ log_game("[key_name(user)] fired sulphuric acid from \a [src] at [AREACOORD(T)].")
+ if(reagents.has_reagent(/datum/reagent/toxin/acid/fluacid))
+ message_admins("[ADMIN_LOOKUPFLW(user)] fired Fluacid from \a [src] at [ADMIN_VERBOSEJMP(T)].")
+ log_game("[key_name(user)] fired Fluacid from \a [src] at [AREACOORD(T)].")
+ if(reagents.has_reagent(/datum/reagent/lube))
+ message_admins("[ADMIN_LOOKUPFLW(user)] fired Space lube from \a [src] at [ADMIN_VERBOSEJMP(T)].")
+ log_game("[key_name(user)] fired Space lube from \a [src] at [AREACOORD(T)].")
+ return
+
+/obj/item/reagent_containers/spray/proc/spray(atom/A)
+ var/range = CLAMP(get_dist(src, A), 1, current_range)
+ var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src))
+ D.create_reagents(amount_per_transfer_from_this)
+ var/puff_reagent_left = range //how many turf, mob or dense objet we can react with before we consider the chem puff consumed
+ if(stream_mode)
+ reagents.trans_to(D, amount_per_transfer_from_this)
+ puff_reagent_left = 1
+ else
+ reagents.trans_to(D, amount_per_transfer_from_this, 1/range)
+ D.color = mix_color_from_reagents(D.reagents.reagent_list)
+ var/wait_step = max(round(2+ spray_delay * INVERSE(range)), 2)
+ do_spray(A, wait_step, D, range, puff_reagent_left)
+
+/obj/item/reagent_containers/spray/proc/do_spray(atom/A, wait_step, obj/effect/decal/chempuff/D, range, puff_reagent_left)
+ set waitfor = FALSE
+ var/range_left = range
+ for(var/i=0, i 0 && (!stream_mode || !range_left))
+ D.reagents.reaction(get_turf(D), VAPOR)
+ puff_reagent_left -= 1
+
+ if(puff_reagent_left <= 0) // we used all the puff so we delete it.
+ qdel(D)
+ return
+ qdel(D)
+
+/obj/item/reagent_containers/spray/attack_self(mob/user)
+ stream_mode = !stream_mode
+ if(stream_mode)
+ amount_per_transfer_from_this = stream_amount
+ current_range = stream_range
+ else
+ amount_per_transfer_from_this = initial(amount_per_transfer_from_this)
+ current_range = spray_range
+ to_chat(user, "You switch the nozzle setting to [stream_mode ? "\"stream\"":"\"spray\""]. You'll now use [amount_per_transfer_from_this] units per use.")
+
+/obj/item/reagent_containers/spray/attackby(obj/item/I, mob/user, params)
+ var/hotness = I.is_hot()
+ if(hotness && reagents)
+ reagents.expose_temperature(hotness)
+ to_chat(user, "You heat [name] with [I]!")
+ return ..()
+
+/obj/item/reagent_containers/spray/verb/empty()
+ set name = "Empty Spray Bottle"
+ set category = "Object"
+ set src in usr
+ if(usr.incapacitated())
+ return
+ if (alert(usr, "Are you sure you want to empty that?", "Empty Bottle:", "Yes", "No") != "Yes")
+ return
+ if(isturf(usr.loc) && src.loc == usr)
+ to_chat(usr, "You empty \the [src] onto the floor.")
+ reagents.reaction(usr.loc)
+ src.reagents.clear_reagents()
+
+//space cleaner
+/obj/item/reagent_containers/spray/cleaner
+ name = "space cleaner"
+ desc = "BLAM!-brand non-foaming space cleaner!"
+ volume = 100
+ list_reagents = list(/datum/reagent/space_cleaner = 100)
+ amount_per_transfer_from_this = 2
+ stream_amount = 5
+
+/obj/item/reagent_containers/spray/cleaner/suicide_act(mob/user)
+ user.visible_message("[user] is putting the nozzle of \the [src] in [user.p_their()] mouth. It looks like [user.p_theyre()] trying to commit suicide!")
+ if(do_mob(user,user,30))
+ if(reagents.total_volume >= amount_per_transfer_from_this)//if not empty
+ user.visible_message("[user] pulls the trigger!")
+ src.spray(user)
+ return BRUTELOSS
+ else
+ user.visible_message("[user] pulls the trigger...but \the [src] is empty!")
+ return SHAME
+ else
+ user.visible_message("[user] decided life was worth living.")
+ return
+
+//Drying Agent
+/obj/item/reagent_containers/spray/drying_agent
+ name = "drying agent spray"
+ desc = "A spray bottle for drying agent."
+ icon_state = "cleaner_drying"
+ volume = 100
+ list_reagents = list(/datum/reagent/drying_agent = 100)
+ amount_per_transfer_from_this = 2
+ stream_amount = 5
+
+//spray tan
+/obj/item/reagent_containers/spray/spraytan
+ name = "spray tan"
+ volume = 50
+ desc = "Gyaro brand spray tan. Do not spray near eyes or other orifices."
+ list_reagents = list(/datum/reagent/spraytan = 50)
+
+
+//pepperspray
+/obj/item/reagent_containers/spray/pepper
+ name = "pepperspray"
+ desc = "Manufactured by UhangInc, used to blind and down an opponent quickly."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "pepperspray"
+ item_state = "pepperspray"
+ lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
+ volume = 40
+ stream_range = 4
+ spray_delay = 1
+ amount_per_transfer_from_this = 5
+ list_reagents = list(/datum/reagent/consumable/condensedcapsaicin = 40)
+
+/obj/item/reagent_containers/spray/pepper/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins huffing \the [src]! It looks like [user.p_theyre()] getting a dirty high!")
+ return OXYLOSS
+
+// Fix pepperspraying yourself
+/obj/item/reagent_containers/spray/pepper/afterattack(atom/A as mob|obj, mob/user)
+ if (A.loc == user)
+ return
+ . = ..()
+
+//water flower
+/obj/item/reagent_containers/spray/waterflower
+ name = "water flower"
+ desc = "A seemingly innocent sunflower...with a twist."
+ icon = 'icons/obj/hydroponics/harvest.dmi'
+ icon_state = "sunflower"
+ item_state = "sunflower"
+ amount_per_transfer_from_this = 1
+ volume = 10
+ list_reagents = list(/datum/reagent/water = 10)
+
+/obj/item/reagent_containers/spray/waterflower/attack_self(mob/user) //Don't allow changing how much the flower sprays
+ return
+
+/obj/item/reagent_containers/spray/waterflower/cyborg
+ reagent_flags = NONE
+ volume = 100
+ list_reagents = list(/datum/reagent/water = 100)
+ var/generate_amount = 5
+ var/generate_type = /datum/reagent/water
+ var/last_generate = 0
+ var/generate_delay = 10 //deciseconds
+ can_fill_from_container = FALSE
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/hacked
+ name = "nova flower"
+ desc = "This doesn't look safe at all..."
+ list_reagents = list(/datum/reagent/clf3 = 3)
+ volume = 3
+ generate_type = /datum/reagent/clf3
+ generate_amount = 1
+ generate_delay = 40 //deciseconds
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Initialize()
+ . = ..()
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/process()
+ if(world.time < last_generate + generate_delay)
+ return
+ last_generate = world.time
+ generate_reagents()
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/empty()
+ to_chat(usr, "You can not empty this!")
+ return
+
+/obj/item/reagent_containers/spray/waterflower/cyborg/proc/generate_reagents()
+ reagents.add_reagent(generate_type, generate_amount)
+
+//chemsprayer
+/obj/item/reagent_containers/spray/chemsprayer
+ name = "chem sprayer"
+ desc = "A utility used to spray large amounts of reagents in a given area."
+ icon = 'icons/obj/guns/projectile.dmi'
+ icon_state = "chemsprayer"
+ item_state = "chemsprayer"
+ lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
+ throwforce = 0
+ w_class = WEIGHT_CLASS_NORMAL
+ stream_mode = 1
+ current_range = 7
+ spray_range = 4
+ stream_range = 7
+ amount_per_transfer_from_this = 10
+ volume = 600
+
+/obj/item/reagent_containers/spray/chemsprayer/afterattack(atom/A as mob|obj, mob/user)
+ // Make it so the bioterror spray doesn't spray yourself when you click your inventory items
+ if (A.loc == user)
+ return
+ . = ..()
+
+/obj/item/reagent_containers/spray/chemsprayer/spray(atom/A)
+ var/direction = get_dir(src, A)
+ var/turf/T = get_turf(A)
+ var/turf/T1 = get_step(T,turn(direction, 90))
+ var/turf/T2 = get_step(T,turn(direction, -90))
+ var/list/the_targets = list(T,T1,T2)
+
+ for(var/i=1, i<=3, i++) // intialize sprays
+ if(reagents.total_volume < 1)
+ return
+ ..(the_targets[i])
+
+/obj/item/reagent_containers/spray/chemsprayer/bioterror
+ list_reagents = list(/datum/reagent/toxin/sodium_thiopental = 100, /datum/reagent/toxin/coniine = 100, /datum/reagent/toxin/venom = 100, /datum/reagent/consumable/condensedcapsaicin = 100, /datum/reagent/toxin/initropidril = 100, /datum/reagent/toxin/polonium = 100)
+
+// Plant-B-Gone
+/obj/item/reagent_containers/spray/plantbgone // -- Skie
+ name = "Plant-B-Gone"
+ desc = "Kills those pesky weeds!"
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "plantbgone"
+ item_state = "plantbgone"
+ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
+ volume = 50
+ list_reagents = list(/datum/reagent/toxin/plantbgone = 50)
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index df51f0233..7ac9ff789 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -324,6 +324,16 @@
////////////Janitor Designs//////////////
/////////////////////////////////////////
+/datum/design/mop
+ name = "Mop"
+ desc = "Just your everyday standard mop."
+ id = "mop"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1200, MAT_GLASS = 100)
+ build_path = /obj/item/mop
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
/datum/design/advmop
name = "Advanced Mop"
desc = "An upgraded mop with a large internal capacity for holding water or other cleaning chemicals."
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index c01e7f35a..061676899 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -5,6 +5,7 @@
force = 3
throwforce = 3
icon = 'icons/mob/human_parts.dmi'
+ w_class = WEIGHT_CLASS_SMALL
icon_state = ""
layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor
var/mob/living/carbon/owner = null
diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm
index bdd12bb19..a463d53dc 100644
--- a/code/modules/vending/snack.dm
+++ b/code/modules/vending/snack.dm
@@ -11,10 +11,20 @@
/obj/item/reagent_containers/food/snacks/no_raisin = 6,
/obj/item/reagent_containers/food/snacks/spacetwinkie = 6,
/obj/item/reagent_containers/food/snacks/cheesiehonkers = 6,
- /obj/item/reagent_containers/food/snacks/bird_seed =6,
+ /obj/item/reagent_containers/food/snacks/cornchips = 5,
+ /obj/item/reagent_containers/food/snacks/bird_seed = 6,
/obj/item/reagent_containers/food/snacks/soyfood = 6)
- contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6)
- premium = list(/obj/item/storage/box/donkpockets = 1,
+ contraband = list(
+ /obj/item/reagent_containers/food/snacks/cracker = 10,
+ /obj/item/reagent_containers/food/snacks/honeybar = 5,
+ /obj/item/reagent_containers/food/snacks/syndicake = 5,
+ /obj/item/reagent_containers/food/snacks/beans = 2)
+ premium = list(
+ /obj/item/reagent_containers/food/snacks/lollipop = 2,
+ /obj/item/reagent_containers/food/snacks/spiderlollipop = 2,
+ /obj/item/reagent_containers/food/snacks/chococoin = 1,
+ /obj/item/storage/box/marshmallow = 1,
+ /obj/item/storage/box/donkpockets = 2,
/obj/item/reagent_containers/food/snacks/poppypretzel = 3,
/obj/item/reagent_containers/food/snacks/carbonnanotube_noodles = 4)
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index 823e77ec9..4ba28ee99 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi
index 66737bb9d..d9a3e0998 100644
Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 37d1c2388..bd4b429fc 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi
index 8b80a6fb5..e8c2bd0ce 100644
Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ
diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi
index 1b37d1b66..c46dea71f 100644
Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ