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