diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index f9b9850bd2d..c1cf5d53520 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -693,6 +693,9 @@ proc/dd_sortedObjectList(list/incoming)
// Lazying Episode 3
#define LAZYSET(L, K, V) LAZYINITLIST(L); L[K] = V;
+/// Returns whether a numerical index is within a given list's bounds. Faster than isnull(LAZYACCESS(L, I)).
+#define ISINDEXSAFE(L, I) (I >= 1 && I <= length(L))
+
//same, but returns nothing and acts on list in place
/proc/shuffle_inplace(list/L)
if(!L)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index 346b78e5b26..f179de1459a 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -1,51 +1,73 @@
-/* SmartFridge. Much todo
-*/
+#define SMART_FRIDGE_LOCK_SHORTED -1
+
+/**
+ * # Smart Fridge
+ *
+ * Stores items of a specified type.
+ */
/obj/machinery/smartfridge
name = "\improper SmartFridge"
icon = 'icons/obj/vending.dmi'
icon_state = "smartfridge"
layer = 2.9
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 100
+ /// The maximum number of items the fridge can hold. Multiplicated by the matter bin component's rating.
var/max_n_of_items = 1500
- var/item_quants = list()
+ /// Associative list (/text => /number) tracking the amounts of a specific item held by the fridge.
+ var/list/item_quants
+ /// How long in ticks the fridge is electrified for. Decrements every process.
var/seconds_electrified = 0
+ /// Whether the fridge should randomly shoot held items at a nearby living target or not.
var/shoot_inventory = FALSE
+ /// Whether the fridge is locked. Used for the secure variant of the fridge.
var/locked = FALSE
+ /// Whether the fridge requires ID scanning. Used for the secure variant of the fridge.
var/scan_id = TRUE
+ /// Whether the fridge is considered secure. Used for wiring and display.
var/is_secure = FALSE
+ /// Whether the fridge can dry its' contents. Used for display.
var/can_dry = FALSE
+ /// Whether the fridge is currently drying. Used by [drying racks][/obj/machinery/smartfridge/drying_rack].
var/drying = FALSE
+ /// Whether the fridge's contents are visible on the world icon.
var/visible_contents = TRUE
- var/datum/wires/smartfridge/wires = null
+ /// The wires controlling the fridge.
+ var/datum/wires/smartfridge/wires
+ /// Typecache of accepted item types, init it in [/obj/machinery/smartfridge/Initialize].
+ var/list/accepted_items_typecache
-/obj/machinery/smartfridge/New()
- ..()
+/obj/machinery/smartfridge/Initialize(mapload)
+ . = ..()
+ item_quants = list()
+ // Reagents
create_reagents()
reagents.set_reacting(FALSE)
+ // Components
component_parts = list()
var/obj/item/circuitboard/smartfridge/board = new(null)
board.set_type(type)
component_parts += board
component_parts += new /obj/item/stock_parts/matter_bin(null)
RefreshParts()
-
-/obj/machinery/smartfridge/RefreshParts()
- for(var/obj/item/stock_parts/matter_bin/B in component_parts)
- max_n_of_items = 1500 * B.rating
-
-/obj/machinery/smartfridge/secure
- is_secure = 1
-
-/obj/machinery/smartfridge/New()
- ..()
+ // Wires
if(is_secure)
wires = new/datum/wires/smartfridge/secure(src)
else
wires = new/datum/wires/smartfridge(src)
+ // Accepted items
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/food/snacks/grown,
+ /obj/item/seeds,
+ /obj/item/grown,
+ ))
+
+/obj/machinery/smartfridge/RefreshParts()
+ for(var/obj/item/stock_parts/matter_bin/B in component_parts)
+ max_n_of_items = 1500 * B.rating
/obj/machinery/smartfridge/Destroy()
QDEL_NULL(wires)
@@ -53,154 +75,6 @@
A.forceMove(loc)
return ..()
-/obj/machinery/smartfridge/proc/accept_check(obj/item/O)
- if(istype(O,/obj/item/reagent_containers/food/snacks/grown/) || istype(O,/obj/item/seeds/) || istype(O,/obj/item/grown/))
- return 1
- return 0
-
-/obj/machinery/smartfridge/seeds
- name = "\improper MegaSeed Servitor"
- desc = "When you need seeds fast!"
- icon = 'icons/obj/vending.dmi'
- icon_state = "seeds"
-
-/obj/machinery/smartfridge/seeds/accept_check(obj/item/O)
- if(istype(O,/obj/item/seeds/))
- return 1
- return 0
-
-/obj/machinery/smartfridge/medbay
- name = "\improper Refrigerated Medicine Storage"
- desc = "A refrigerated storage unit for storing medicine and chemicals."
- icon_state = "smartfridge" //To fix the icon in the map editor.
-
-/obj/machinery/smartfridge/medbay/accept_check(obj/item/O)
- if(istype(O,/obj/item/reagent_containers/glass))
- return 1
- if(istype(O,/obj/item/reagent_containers/iv_bag))
- return 1
- if(istype(O,/obj/item/storage/pill_bottle))
- return 1
- if(ispill(O))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/extract
- name = "\improper Slime Extract Storage"
- desc = "A refrigerated storage unit for slime extracts"
- req_access_txt = "47"
-
-/obj/machinery/smartfridge/secure/extract/accept_check(obj/item/O)
- if(istype(O,/obj/item/slime_extract))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/medbay
- name = "\improper Secure Refrigerated Medicine Storage"
- desc = "A refrigerated storage unit for storing medicine and chemicals."
- icon_state = "smartfridge" //To fix the icon in the map editor.
- req_one_access_txt = "5;33"
-
-/obj/machinery/smartfridge/secure/medbay/accept_check(obj/item/O)
- if(istype(O,/obj/item/reagent_containers/glass))
- return 1
- if(istype(O,/obj/item/reagent_containers/iv_bag))
- return 1
- if(istype(O,/obj/item/storage/pill_bottle))
- return 1
- if(ispill(O))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/chemistry
- name = "\improper Smart Chemical Storage"
- desc = "A refrigerated storage unit for medicine and chemical storage."
- icon_state = "smartfridge" //To fix the icon in the map editor.
- req_access_txt = "33"
- var/list/spawn_meds = list()
-
-/obj/machinery/smartfridge/secure/chemistry/New()
- ..()
- for(var/typekey in spawn_meds)
- var/amount = spawn_meds[typekey]
- if(isnull(amount)) amount = 1
- while(amount)
- var/obj/item/I = new typekey(src)
- if(item_quants[I.name])
- item_quants[I.name]++
- else
- item_quants[I.name] = 1
- SSnanoui.update_uis(src)
- amount--
- update_icon()
-
-/obj/machinery/smartfridge/secure/chemistry/accept_check(obj/item/O)
- if(istype(O,/obj/item/storage/pill_bottle) || istype(O,/obj/item/reagent_containers))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/chemistry/preloaded
- spawn_meds = list(
- /obj/item/reagent_containers/food/pill/epinephrine = 12,
- /obj/item/reagent_containers/food/pill/charcoal = 5,
- /obj/item/reagent_containers/glass/bottle/epinephrine = 1,
- /obj/item/reagent_containers/glass/bottle/charcoal = 1)
-
-/obj/machinery/smartfridge/secure/chemistry/preloaded/syndicate
- req_access_txt = null
- req_access = list(ACCESS_SYNDICATE)
-
-/obj/machinery/smartfridge/disks
- name = "disk compartmentalizer"
- desc = "A machine capable of storing a variety of disks. Denoted by most as the DSU (disk storage unit)."
- icon_state = "disktoaster"
- pass_flags = PASSTABLE
- visible_contents = FALSE
-
-/obj/machinery/smartfridge/disks/accept_check(obj/item/O)
- return istype(O, /obj/item/disk)
-
-// ----------------------------
-// Virology Medical Smartfridge
-// ----------------------------
-/obj/machinery/smartfridge/secure/chemistry/virology
- name = "Smart Virus Storage"
- desc = "A refrigerated storage unit for volatile sample storage."
- req_access_txt = "39"
- spawn_meds = list(/obj/item/reagent_containers/syringe/antiviral = 4,
- /obj/item/reagent_containers/glass/bottle/cold = 1,
- /obj/item/reagent_containers/glass/bottle/flu_virion = 1,
- /obj/item/reagent_containers/glass/bottle/mutagen = 1,
- /obj/item/reagent_containers/glass/bottle/plasma = 1,
- /obj/item/reagent_containers/glass/bottle/diphenhydramine = 1)
-
-/obj/machinery/smartfridge/secure/chemistry/virology/accept_check(obj/item/O)
- if(istype(O, /obj/item/reagent_containers/syringe) || istype(O, /obj/item/reagent_containers/glass/bottle) || istype(O, /obj/item/reagent_containers/glass/beaker))
- return 1
- return 0
-
-/obj/machinery/smartfridge/secure/chemistry/virology/preloaded
- spawn_meds = list(
- /obj/item/reagent_containers/syringe/antiviral = 4,
- /obj/item/reagent_containers/glass/bottle/cold = 1,
- /obj/item/reagent_containers/glass/bottle/flu_virion = 1,
- /obj/item/reagent_containers/glass/bottle/mutagen = 1,
- /obj/item/reagent_containers/glass/bottle/plasma = 1,
- /obj/item/reagent_containers/glass/bottle/reagent/synaptizine = 1,
- /obj/item/reagent_containers/glass/bottle/reagent/formaldehyde = 1)
-
-/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/syndicate
- req_access_txt = null
- req_access = list(ACCESS_SYNDICATE)
-
-/obj/machinery/smartfridge/drinks
- name = "\improper Drink Showcase"
- desc = "A refrigerated storage unit for tasty tasty alcohol."
-
-/obj/machinery/smartfridge/drinks/accept_check(obj/item/O)
- if(istype(O,/obj/item/reagent_containers/glass) || istype(O,/obj/item/reagent_containers/food/drinks) || istype(O,/obj/item/reagent_containers/food/condiment))
- return 1
-
/obj/machinery/smartfridge/process()
if(stat & (BROKEN|NOPOWER))
return
@@ -216,52 +90,57 @@
update_icon()
/obj/machinery/smartfridge/update_icon()
+ var/prefix = initial(icon_state)
if(stat & (BROKEN|NOPOWER))
- icon_state = "[initial(icon_state)]-off"
+ icon_state = "[prefix]-off"
else if(visible_contents)
- switch(contents.len)
+ switch(length(contents))
if(0)
- icon_state = "[initial(icon_state)]"
+ icon_state = "[prefix]"
if(1 to 25)
- icon_state = "[initial(icon_state)]1"
+ icon_state = "[prefix]1"
if(26 to 75)
- icon_state = "[initial(icon_state)]2"
+ icon_state = "[prefix]2"
if(76 to INFINITY)
- icon_state = "[initial(icon_state)]3"
+ icon_state = "[prefix]3"
else
- icon_state = "[initial(icon_state)]"
+ icon_state = "[prefix]"
-/*******************
-* Item Adding
-********************/
-
-/obj/machinery/smartfridge/default_deconstruction_screwdriver(mob/user, obj/item/screwdriver/S)
- . = ..(user, icon_state, icon_state, S)
+// Interactions
+/obj/machinery/smartfridge/screwdriver_act(mob/living/user, obj/item/I)
+ . = default_deconstruction_screwdriver(user, icon_state, icon_state, I)
+ if(!.)
+ return
overlays.Cut()
if(panel_open)
overlays += image(icon, "[initial(icon_state)]-panel")
-/obj/machinery/smartfridge/attackby(obj/item/O, var/mob/user)
- if(default_deconstruction_screwdriver(user, O))
- return
-
- if(exchange_parts(user, O))
- return
-
- if(default_unfasten_wrench(user, O))
+/obj/machinery/smartfridge/wrench_act(mob/living/user, obj/item/I)
+ . = default_unfasten_wrench(user, I)
+ if(.)
power_change()
- return
- if(default_deconstruction_crowbar(user, O))
- return
+/obj/machinery/smartfridge/crowbar_act(mob/living/user, obj/item/I)
+ . = default_deconstruction_crowbar(user, I)
- if(istype(O, /obj/item/multitool)||istype(O, /obj/item/wirecutters))
- if(panel_open)
- attack_hand(user)
- return
+/obj/machinery/smartfridge/wirecutter_act(mob/living/user, obj/item/I)
+ if(panel_open)
+ attack_hand(user)
+ return TRUE
+ return ..()
- if(stat & NOPOWER)
+/obj/machinery/smartfridge/multitool_act(mob/living/user, obj/item/I)
+ if(panel_open)
+ attack_hand(user)
+ return TRUE
+ return ..()
+
+/obj/machinery/smartfridge/attackby(obj/item/O, var/mob/user)
+ if(exchange_parts(user, O))
+ SSnanoui.update_uis(src)
+ return
+ if(stat & (BROKEN|NOPOWER))
to_chat(user, "\The [src] is unpowered and useless.")
return
@@ -269,92 +148,63 @@
user.visible_message("[user] has added \the [O] to \the [src].", "You add \the [O] to \the [src].")
SSnanoui.update_uis(src)
update_icon()
-
else if(istype(O, /obj/item/storage/bag))
var/obj/item/storage/bag/P = O
- var/plants_loaded = 0
+ var/items_loaded = 0
for(var/obj/G in P.contents)
if(load(G, user))
- plants_loaded++
- if(plants_loaded)
+ items_loaded++
+ if(items_loaded)
user.visible_message("[user] loads \the [src] with \the [P].", "You load \the [src] with \the [P].")
- if(P.contents.len > 0)
- to_chat(user, "Some items are refused.")
-
- SSnanoui.update_uis(src)
- update_icon()
-
+ SSnanoui.update_uis(src)
+ update_icon()
+ var/failed = length(P.contents)
+ if(failed)
+ to_chat(user, "[failed] item\s [failed == 1 ? "is" : "are"] refused.")
else if(!istype(O, /obj/item/card/emag))
to_chat(user, "\The [src] smartly refuses [O].")
- return 1
-
-/obj/machinery/smartfridge/proc/load(obj/I, mob/user)
- if(accept_check(I))
- if(contents.len >= max_n_of_items)
- to_chat(user, "\The [src] is full.")
- return 0
- else
- if(istype(I.loc, /obj/item/storage))
- var/obj/item/storage/S = I.loc
- S.remove_from_storage(I, src)
- else if(istype(I.loc, /mob))
- var/mob/M = I.loc
- if(M.get_active_hand() == I)
- if(!M.drop_item())
- to_chat(user, "\The [I] is stuck to you!")
- return 0
- else
- M.unEquip(I)
- I.forceMove(src)
- else
- I.forceMove(src)
-
- if(item_quants[I.name])
- item_quants[I.name]++
- else
- item_quants[I.name] = 1
- return 1
- return 0
+ return TRUE
/obj/machinery/smartfridge/attack_ai(mob/user)
- return 0
+ return FALSE
/obj/machinery/smartfridge/attack_ghost(mob/user)
return attack_hand(user)
/obj/machinery/smartfridge/attack_hand(mob/user)
- if(stat & (NOPOWER|BROKEN))
+ if(stat & (BROKEN|NOPOWER))
return
wires.Interact(user)
ui_interact(user)
+ return ..()
//Drag pill bottle to fridge to empty it into the fridge
/obj/machinery/smartfridge/MouseDrop_T(obj/over_object, mob/user)
if(!istype(over_object, /obj/item/storage/pill_bottle)) //Only pill bottles, please
return
-
- if(stat & NOPOWER)
+ if(stat & (BROKEN|NOPOWER))
to_chat(user, "\The [src] is unpowered and useless.")
return
var/obj/item/storage/box/pillbottles/P = over_object
+ if(!length(P.contents))
+ to_chat(user, "\The [P] is empty.")
+ return
+
var/items_loaded = 0
for(var/obj/G in P.contents)
if(load(G, user))
items_loaded++
if(items_loaded)
- user.visible_message( \
- "[user] empties \the [P] into \the [src].", \
- "You empty \the [P] into \the [src].")
- if(P.contents.len > 0)
- to_chat(user, "Some items are refused.")
- SSnanoui.update_uis(src)
+ user.visible_message("[user] empties \the [P] into \the [src].", "You empty \the [P] into \the [src].")
+ SSnanoui.update_uis(src)
+ update_icon()
+ var/failed = length(P.contents)
+ if(failed)
+ to_chat(user, "[failed] item\s [failed == 1 ? "is" : "are"] refused.")
-/*******************
-* SmartFridge Menu
-********************/
-
-/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
+// UI
+/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
@@ -374,13 +224,13 @@
data["drying"] = drying
var/list/items[0]
- for(var/i=1 to length(item_quants))
+ for(var/i in 1 to length(item_quants))
var/K = item_quants[i]
var/count = item_quants[K]
if(count > 0)
items.Add(list(list("display_name" = html_encode(capitalize(K)), "vend" = i, "quantity" = count)))
- if(items.len > 0)
+ if(length(items))
data["contents"] = items
return data
@@ -402,6 +252,8 @@
if(href_list["vend"])
var/index = text2num(href_list["vend"])
var/amount = text2num(href_list["amount"])
+ if(isnull(index) || !ISINDEXSAFE(item_quants, index) || isnull(amount))
+ return FALSE
var/K = item_quants[index]
var/count = item_quants[K]
@@ -429,36 +281,343 @@
if(i <= 0)
return TRUE
return TRUE
+
return FALSE
+/**
+ * Tries to load an item if it is accepted by [/obj/machinery/smartfridge/proc/accept_check].
+ *
+ * Arguments:
+ * * I - The item to load.
+ * * user - The user trying to load the item.
+ */
+/obj/machinery/smartfridge/proc/load(obj/I, mob/user)
+ if(accept_check(I))
+ if(length(contents) >= max_n_of_items)
+ to_chat(user, "\The [src] is full.")
+ return FALSE
+ else
+ if(istype(I.loc, /obj/item/storage))
+ var/obj/item/storage/S = I.loc
+ S.remove_from_storage(I, src)
+ else if(ismob(I.loc))
+ var/mob/M = I.loc
+ if(M.get_active_hand() == I)
+ if(!M.drop_item())
+ to_chat(user, "\The [I] is stuck to you!")
+ return FALSE
+ else
+ M.unEquip(I)
+ I.forceMove(src)
+ else
+ I.forceMove(src)
+
+ item_quants[I.name] += 1
+ return TRUE
+ return FALSE
+
+/**
+ * Tries to shoot a random at a nearby living mob.
+ */
/obj/machinery/smartfridge/proc/throw_item()
- var/obj/throw_item = null
- var/mob/living/target = locate() in view(7,src)
+ var/obj/item/throw_item = null
+ var/mob/living/target = locate() in view(7, src)
if(!target)
- return 0
+ return FALSE
for(var/O in item_quants)
if(item_quants[O] <= 0) //Try to use a record that actually has something to dump.
continue
-
item_quants[O]--
- for(var/obj/T in contents)
- if(T.name == O)
- T.forceMove(loc)
- throw_item = T
+ for(var/obj/I in contents)
+ if(I.name == O)
+ I.forceMove(loc)
+ throw_item = I
update_icon()
break
- break
if(!throw_item)
- return 0
- spawn(0)
- throw_item.throw_at(target,16,3,src)
- visible_message("[src] launches [throw_item.name] at [target.name]!")
- return 1
+ return FALSE
-// ----------------------------
-// Drying Rack 'smartfridge'
-// ----------------------------
+ INVOKE_ASYNC(throw_item, /atom/movable.proc/throw_at, target, 16, 3, src)
+ visible_message("[src] launches [throw_item.name] at [target.name]!")
+ return TRUE
+
+/**
+ * Returns whether the smart fridge can accept the given item.
+ *
+ * By default checks if the item is in [the typecache][/obj/machinery/smartfridge/var/accepted_items_typecache].
+ * Arguments:
+ * * O - The item to check.
+ */
+/obj/machinery/smartfridge/proc/accept_check(obj/item/O)
+ return is_type_in_typecache(O, accepted_items_typecache)
+
+/**
+ * # Secure Fridge
+ *
+ * Secure variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ * Can be emagged and EMP'd to short the lock.
+ */
+/obj/machinery/smartfridge/secure
+ is_secure = TRUE
+
+/obj/machinery/smartfridge/secure/emag_act(mob/user)
+ emagged = TRUE
+ locked = SMART_FRIDGE_LOCK_SHORTED
+ to_chat(user, "You short out the product lock on \the [src].")
+
+/obj/machinery/smartfridge/secure/emp_act(severity)
+ if(!emagged && locked != SMART_FRIDGE_LOCK_SHORTED && prob(40 / severity))
+ playsound(loc, 'sound/effects/sparks4.ogg', 60, TRUE)
+ emagged = TRUE
+ locked = SMART_FRIDGE_LOCK_SHORTED
+
+/obj/machinery/smartfridge/secure/Topic(href, href_list)
+ if(stat & (BROKEN|NOPOWER))
+ return FALSE
+
+ if(href_list["vend"] && (usr.contents.Find(src) || Adjacent(usr)))
+ if(!emagged && locked != SMART_FRIDGE_LOCK_SHORTED && scan_id && !allowed(usr))
+ to_chat(usr, "Access denied.")
+ SSnanoui.update_uis(src)
+ return FALSE
+
+ return ..()
+
+/**
+ * # Seed Storage
+ *
+ * Seeds variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ * Formerly known as MegaSeed Servitor, but renamed to avoid confusion with the [vending machine][/obj/machinery/vending/hydroseeds].
+ */
+/obj/machinery/smartfridge/seeds
+ name = "\improper Seed Storage"
+ desc = "When you need seeds fast!"
+ icon = 'icons/obj/vending.dmi'
+ icon_state = "seeds"
+
+/obj/machinery/smartfridge/seeds/Initialize(mapload)
+ . = ..()
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/seeds
+ ))
+
+/**
+ * # Refrigerated Medicine Storage
+ *
+ * Medical variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/medbay
+ name = "\improper Refrigerated Medicine Storage"
+ desc = "A refrigerated storage unit for storing medicine and chemicals."
+ icon_state = "smartfridge" //To fix the icon in the map editor.
+
+/obj/machinery/smartfridge/medbay/Initialize(mapload)
+ . = ..()
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/glass,
+ /obj/item/reagent_containers/iv_bag,
+ /obj/item/reagent_containers/applicator,
+ /obj/item/storage/pill_bottle,
+ /obj/item/reagent_containers/food/pill,
+ ))
+
+/**
+ * # Slime Extract Storage
+ *
+ * Secure, Xenobiology variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/secure/extract
+ name = "\improper Slime Extract Storage"
+ desc = "A refrigerated storage unit for slime extracts"
+
+/obj/machinery/smartfridge/secure/extract/Initialize(mapload)
+ . = ..()
+ req_access_txt = "[ACCESS_RESEARCH]"
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/slime_extract
+ ))
+
+/**
+ * # Secure Refrigerated Medicine Storage
+ *
+ * Secure, Medical variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/secure/medbay
+ name = "\improper Secure Refrigerated Medicine Storage"
+ desc = "A refrigerated storage unit for storing medicine and chemicals."
+ icon_state = "smartfridge" //To fix the icon in the map editor.
+ req_one_access_txt = "5;33"
+
+/obj/machinery/smartfridge/secure/medbay/Initialize(mapload)
+ . = ..()
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/glass,
+ /obj/item/reagent_containers/iv_bag,
+ /obj/item/reagent_containers/applicator,
+ /obj/item/storage/pill_bottle,
+ /obj/item/reagent_containers/food/pill,
+ ))
+
+/**
+ * # Smart Chemical Storage
+ *
+ * Secure, Chemistry variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/secure/chemistry
+ name = "\improper Smart Chemical Storage"
+ desc = "A refrigerated storage unit for medicine and chemical storage."
+ icon_state = "smartfridge" //To fix the icon in the map editor.
+ /// Associative list (/obj/item => /number) representing the items the fridge should initially contain.
+ var/list/spawn_meds
+
+/obj/machinery/smartfridge/secure/chemistry/Initialize(mapload)
+ . = ..()
+ req_access_txt = "[ACCESS_CHEMISTRY]"
+ // Spawn initial chemicals
+ if(mapload)
+ LAZYINITLIST(spawn_meds)
+ for(var/typekey in spawn_meds)
+ var/amount = spawn_meds[typekey] || 1
+ while(amount--)
+ var/obj/item/I = new typekey(src)
+ item_quants[I.name] += 1
+ update_icon()
+ // Accepted items
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/storage/pill_bottle,
+ /obj/item/reagent_containers,
+ ))
+
+/**
+ * # Smart Chemical Storage (Preloaded)
+ *
+ * A [Smart Chemical Storage][/obj/machinery/smartfridge/secure/chemistry] but with some items already in.
+ */
+/obj/machinery/smartfridge/secure/chemistry/preloaded
+ // I exist!
+
+/obj/machinery/smartfridge/secure/chemistry/preloaded/Initialize(mapload)
+ spawn_meds = list(
+ /obj/item/reagent_containers/food/pill/epinephrine = 12,
+ /obj/item/reagent_containers/food/pill/charcoal = 5,
+ /obj/item/reagent_containers/glass/bottle/epinephrine = 1,
+ /obj/item/reagent_containers/glass/bottle/charcoal = 1,
+ )
+ . = ..()
+
+/**
+ * # Smart Chemical Storage (Preloaded, Syndicate)
+ *
+ * A [Smart Chemical Storage (Preloaded)][/obj/machinery/smartfridge/secure/chemistry/preloaded] but with exclusive access to Syndicate.
+ */
+/obj/machinery/smartfridge/secure/chemistry/preloaded/syndicate
+ req_access_txt = null
+
+/obj/machinery/smartfridge/secure/chemistry/preloaded/syndicate/Initialize(mapload)
+ . = ..()
+ req_access = list(ACCESS_SYNDICATE)
+
+/**
+ * # Disk Compartmentalizer
+ *
+ * Disk variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/disks
+ name = "disk compartmentalizer"
+ desc = "A machine capable of storing a variety of disks. Denoted by most as the DSU (disk storage unit)."
+ icon_state = "disktoaster"
+ pass_flags = PASSTABLE
+ visible_contents = FALSE
+
+/obj/machinery/smartfridge/disks/Initialize(mapload)
+ . = ..()
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/disk,
+ ))
+
+/**
+ * # Smart Virus Storage
+ *
+ * Secure, Virology variant of the [Smart Chemical Storage][/obj/machinery/smartfridge/secure/chemistry].
+ * Comes with some items.
+ */
+/obj/machinery/smartfridge/secure/chemistry/virology
+ name = "\improper Smart Virus Storage"
+ desc = "A refrigerated storage unit for volatile sample storage."
+
+/obj/machinery/smartfridge/secure/chemistry/virology/Initialize(mapload)
+ spawn_meds = list(
+ /obj/item/reagent_containers/syringe/antiviral = 4,
+ /obj/item/reagent_containers/glass/bottle/cold = 1,
+ /obj/item/reagent_containers/glass/bottle/flu_virion = 1,
+ /obj/item/reagent_containers/glass/bottle/mutagen = 1,
+ /obj/item/reagent_containers/glass/bottle/plasma = 1,
+ /obj/item/reagent_containers/glass/bottle/diphenhydramine = 1
+ )
+ . = ..()
+ req_access_txt = "[ACCESS_VIROLOGY]"
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/syringe,
+ /obj/item/reagent_containers/glass/bottle,
+ /obj/item/reagent_containers/glass/beaker,
+ ))
+
+/**
+ * # Smart Virus Storage (Preloaded)
+ *
+ * A [Smart Virus Storage][/obj/machinery/smartfridge/secure/chemistry/virology] but with some additional items.
+ */
+/obj/machinery/smartfridge/secure/chemistry/virology/preloaded
+ // I exist!
+
+/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/Initialize(mapload)
+ spawn_meds = list(
+ /obj/item/reagent_containers/syringe/antiviral = 4,
+ /obj/item/reagent_containers/glass/bottle/cold = 1,
+ /obj/item/reagent_containers/glass/bottle/flu_virion = 1,
+ /obj/item/reagent_containers/glass/bottle/mutagen = 1,
+ /obj/item/reagent_containers/glass/bottle/plasma = 1,
+ /obj/item/reagent_containers/glass/bottle/reagent/synaptizine = 1,
+ /obj/item/reagent_containers/glass/bottle/reagent/formaldehyde = 1
+ )
+ . = ..()
+
+/**
+ * # Smart Virus Storage (Preloaded, Syndicate)
+ *
+ * A [Smart Virus Storage (Preloaded)][/obj/machinery/smartfridge/secure/chemistry/virology/preloaded] but with exclusive access to Syndicate.
+ */
+/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/syndicate
+ req_access_txt = null
+
+/obj/machinery/smartfridge/secure/chemistry/virology/preloaded/syndicate/Initialize(mapload)
+ . = ..()
+ req_access = list(ACCESS_SYNDICATE)
+
+/**
+ * # Drink Showcase
+ *
+ * Drink variant of the [Smart Fridge][/obj/machinery/smartfridge].
+ */
+/obj/machinery/smartfridge/drinks
+ name = "\improper Drink Showcase"
+ desc = "A refrigerated storage unit for tasty tasty alcohol."
+
+/obj/machinery/smartfridge/drinks/Initialize(mapload)
+ . = ..()
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/glass,
+ /obj/item/reagent_containers/food/drinks,
+ /obj/item/reagent_containers/food/condiment,
+ ))
+
+/**
+ * # Drying Rack
+ *
+ * Variant of the [Smart Fridge][/obj/machinery/smartfridge] for drying stuff.
+ * Doesn't have components.
+ */
/obj/machinery/smartfridge/drying_rack
name = "drying rack"
desc = "A wooden contraption, used to dry plant products, food and leather."
@@ -470,11 +629,16 @@
can_dry = TRUE
visible_contents = FALSE
-/obj/machinery/smartfridge/drying_rack/New()
- ..()
- if(component_parts && component_parts.len)
- component_parts.Cut()
+/obj/machinery/smartfridge/drying_rack/Initialize(mapload)
+ . = ..()
+ // Remove components, this is wood duh
+ QDEL_LIST(component_parts)
component_parts = null
+ // Accepted items
+ accepted_items_typecache = typecacheof(list(
+ /obj/item/reagent_containers/food/snacks,
+ /obj/item/stack/sheet/wetleather,
+ ))
/obj/machinery/smartfridge/drying_rack/on_deconstruction()
new /obj/item/stack/sheet/wood(loc, 10)
@@ -483,34 +647,6 @@
/obj/machinery/smartfridge/drying_rack/RefreshParts()
return
-/obj/machinery/smartfridge/drying_rack/default_deconstruction_screwdriver()
- return
-
-/obj/machinery/smartfridge/drying_rack/exchange_parts()
- return
-
-/obj/machinery/smartfridge/drying_rack/spawn_frame()
- return
-
-/obj/machinery/smartfridge/drying_rack/default_deconstruction_crowbar(user, obj/item/crowbar/C, ignore_panel = 1)
- ..()
-
-/obj/machinery/smartfridge/drying_rack/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["dryingOn"])
- drying = TRUE
- use_power = ACTIVE_POWER_USE
- update_icon()
- return 1
-
- if(href_list["dryingOff"])
- drying = FALSE
- use_power = IDLE_POWER_USE
- update_icon()
- return 1
- return 0
-
/obj/machinery/smartfridge/drying_rack/power_change()
if(powered() && anchored)
stat &= ~NOPOWER
@@ -519,35 +655,67 @@
toggle_drying(TRUE)
update_icon()
-/obj/machinery/smartfridge/drying_rack/load(obj/I, mob/user) //For updating the filled overlay
+/obj/machinery/smartfridge/drying_rack/screwdriver_act(mob/living/user, obj/item/I)
+ return
+
+/obj/machinery/smartfridge/drying_rack/exchange_parts()
+ return
+
+/obj/machinery/smartfridge/drying_rack/spawn_frame()
+ return
+
+/obj/machinery/smartfridge/drying_rack/crowbar_act(mob/living/user, obj/item/I)
+ . = default_deconstruction_crowbar(user, I, TRUE)
+
+/obj/machinery/smartfridge/drying_rack/emp_act(severity)
+ ..()
+ atmos_spawn_air(LINDA_SPAWN_HEAT)
+
+/obj/machinery/smartfridge/drying_rack/Topic(href, href_list)
if(..())
+ return TRUE
+
+ if(href_list["dryingOn"])
+ drying = TRUE
+ use_power = ACTIVE_POWER_USE
update_icon()
- return 1
+ return TRUE
+
+ if(href_list["dryingOff"])
+ drying = FALSE
+ use_power = IDLE_POWER_USE
+ update_icon()
+ return TRUE
+
+ return FALSE
/obj/machinery/smartfridge/drying_rack/update_icon()
..()
-
overlays.Cut()
if(drying)
overlays += "drying_rack_drying"
- if(contents.len)
+ if(length(contents))
overlays += "drying_rack_filled"
/obj/machinery/smartfridge/drying_rack/process()
..()
- if(drying)
- if(rack_dry())//no need to update unless something got dried
- update_icon()
+ if(drying && rack_dry())//no need to update unless something got dried
+ update_icon()
/obj/machinery/smartfridge/drying_rack/accept_check(obj/item/O)
+ . = ..()
+ // If it's a food, reject non driable ones
if(istype(O, /obj/item/reagent_containers/food/snacks))
var/obj/item/reagent_containers/food/snacks/S = O
- if(S.dried_type)
- return TRUE
- if(istype(O, /obj/item/stack/sheet/wetleather))
- return TRUE
- return FALSE
+ if(!S.dried_type)
+ return FALSE
+/**
+ * Toggles the drying process.
+ *
+ * Arguments:
+ * * forceoff - Whether to force turn off the drying rack.
+ */
/obj/machinery/smartfridge/drying_rack/proc/toggle_drying(forceoff)
if(drying || forceoff)
drying = FALSE
@@ -557,6 +725,9 @@
use_power = ACTIVE_POWER_USE
update_icon()
+/**
+ * Called in [/obj/machinery/smartfridge/drying_rack/process] to dry the contents.
+ */
/obj/machinery/smartfridge/drying_rack/proc/rack_dry()
for(var/obj/item/reagent_containers/food/snacks/S in contents)
if(S.dried_type == S.type)//if the dried type is the same as the object's type, don't bother creating a whole new item...
@@ -580,30 +751,4 @@
return TRUE
return FALSE
-/obj/machinery/smartfridge/drying_rack/emp_act(severity)
- ..()
- atmos_spawn_air(LINDA_SPAWN_HEAT)
-
-/************************
-* Secure SmartFridges
-*************************/
-/obj/machinery/smartfridge/secure/emag_act(mob/user)
- emagged = 1
- locked = -1
- to_chat(user, "You short out the product lock on [src].")
-
-/obj/machinery/smartfridge/secure/emp_act(severity)
- if(prob(40/severity) && (!emagged) && (locked != -1))
- playsound(loc, 'sound/effects/sparks4.ogg', 60, 1)
- emagged = 1
- locked = -1
-
-/obj/machinery/smartfridge/secure/Topic(href, href_list)
- if(stat & (NOPOWER|BROKEN))
- return 0
- if(usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf)))
- if(!allowed(usr) && !emagged && locked != -1 && scan_id && href_list["vend"])
- to_chat(usr, "Access denied.")
- SSnanoui.update_uis(src)
- return 0
- return ..()
+#undef SMART_FRIDGE_LOCK_SHORTED