From 144a6ca62a4a8bbc81f7716e3834cbce5c3333c0 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Fri, 8 Mar 2024 14:50:09 -0800 Subject: [PATCH 01/29] No splitting medical items Refactoring --- code/game/objects/items/stacks/medical.dm | 1 + code/game/objects/items/stacks/stack.dm | 70 +++++++++++++---------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index c4a496a12366..cb5d88b4f7f3 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -8,6 +8,7 @@ throw_speed = SPEED_VERY_FAST throw_range = 20 attack_speed = 3 + can_split = FALSE var/heal_brute = 0 var/heal_burn = 0 var/alien = FALSE diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index f8a6af3cf24f..0b07ce92688d 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -15,10 +15,16 @@ var/list/datum/stack_recipe/recipes var/singular_name var/amount = 1 - var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount - var/stack_id //used to determine if two stacks are of the same kind. - var/amount_sprites = FALSE //does it have sprites for extra amount, like metal, plasteel, or wood - var/display_maptext = TRUE //does it show amount on top of the icon + ///also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount + var/max_amount + ///used to determine if two stacks are of the same kind. + var/stack_id + ///does it have sprites for extra amount, like metal, plasteel, or wood + var/amount_sprites = FALSE + ///does it show amount on top of the icon + var/display_maptext = TRUE + ///whether the stack can be split into two different items + var/can_split = TRUE //Coords for contents display, to make it play nice with inventory borders. maptext_x = 4 maptext_y = 3 @@ -325,53 +331,55 @@ Also change the icon to reflect the amount of sheets, if possible.*/ return if(amount <= 1) return + if(!can_split) + return var/desired = tgui_input_number(user, "How much would you like to split off from this stack?", "How much?", 1, amount-1, 1) if(!desired) return if(!use(desired)) return - var/obj/item/stack/newstack = new src.type(user, desired) + var/obj/item/stack/newstack = new type(user, desired) transfer_fingerprints_to(newstack) user.put_in_hands(newstack) - src.add_fingerprint(user) + add_fingerprint(user) newstack.add_fingerprint(user) - if(src && usr.interactee==src) - INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), usr) + if(!QDELETED(src) && user.interactee == src) + INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), user) return TRUE - else - return ..() + + return ..() /obj/item/stack/attack_hand(mob/user as mob) - if (user.get_inactive_hand() == src) - var/obj/item/stack/F = new src.type(user, 1) - transfer_fingerprints_to(F) - user.put_in_hands(F) - src.add_fingerprint(user) - F.add_fingerprint(user) + if(user.get_inactive_hand() == src && can_split) + var/obj/item/stack/new_stack = new type(user, 1) + transfer_fingerprints_to(new_stack) + user.put_in_hands(new_stack) + add_fingerprint(user) + new_stack.add_fingerprint(user) use(1) - if (src && usr.interactee==src) - INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), usr) - else - ..() - return + if(!QDELETED(src) && user.interactee == src) + INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), user) + return + + return ..() /obj/item/stack/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/stack)) - var/obj/item/stack/S = W - if(S.stack_id == stack_id) //same stack type - if(S.amount >= max_amount) + var/obj/item/stack/other_stack = W + if(other_stack.stack_id == stack_id) //same stack type + if(other_stack.amount >= max_amount) to_chat(user, SPAN_WARNING("The stack is full!")) return TRUE - var/to_transfer = min(src.amount, S.max_amount-S.amount) + var/to_transfer = min(amount, other_stack.max_amount - other_stack.amount) if(to_transfer <= 0) return to_chat(user, SPAN_INFO("You transfer [to_transfer] between the stacks.")) - S.add(to_transfer) - if (S && usr.interactee==S) - INVOKE_ASYNC(S, TYPE_PROC_REF(/obj/item/stack, interact), usr) - src.use(to_transfer) - if (src && usr.interactee==src) - INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), usr) + other_stack.add(to_transfer) + if(other_stack && user.interactee == other_stack) + INVOKE_ASYNC(other_stack, TYPE_PROC_REF(/obj/item/stack, interact), user) + use(to_transfer) + if(!QDELETED(src) && user.interactee == src) + INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/item/stack, interact), user) user.next_move = world.time + 0.3 SECONDS return TRUE From 2d633aaeae4634cefef8e68c3cb9ec2ff5feb157 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 7 Apr 2024 04:08:24 -0700 Subject: [PATCH 02/29] Vendor changes --- code/game/machinery/vending/cm_vending.dm | 42 ++-- .../machinery/vending/vendor_types/medical.dm | 208 +++++++++++++----- 2 files changed, 176 insertions(+), 74 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index c7443130b247..bb47b5de25e6 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -900,8 +900,14 @@ GLOBAL_LIST_EMPTY(vending_products) ///this here is made to provide ability to restock vendors with different subtypes of same object, like handmade and manually filled ammo boxes. var/list/corresponding_types_list - ///If using [VEND_STOCK_DYNAMIC], assoc list of product entry to list of (product multiplier, awarded objects) - as seen in [/obj/structure/machinery/cm_vending/sorted/proc/populate_product_list] - ///This allows us to backtrack and refill the stocks when new players latejoin + /** + * If using [VEND_STOCK_DYNAMIC], assoc list of product entry to list of (1.0 scale product multiplier, awarded objects) - as seen in [/obj/structure/machinery/cm_vending/sorted/proc/populate_product_list] + * This allows us to backtrack and refill the stocks when new players latejoin. + * + * If NOT using [VEND_STOCK_DYNAMIC], assoc list of product entry to list of (estimated 1.0 scale product multiplier, scaled product multiplier) - as seen in [/obj/structure/machinery/cm_vending/sorted/proc/populate_product_list] + * This allows us to know the original amounts to know if the vendor is full of an item. + * The 1.0 scale is estimated because it is a divided by the scale rather than repopulating the list at 1.0 scale - anything that is a fixed amount won't necessarily be correct. + */ var/list/list/dynamic_stock_multipliers /obj/structure/machinery/cm_vending/sorted/Initialize() @@ -917,22 +923,27 @@ GLOBAL_LIST_EMPTY(vending_products) ///this proc, well, populates product list based on roundstart amount of players /obj/structure/machinery/cm_vending/sorted/proc/populate_product_list_and_boxes(scale) + dynamic_stock_multipliers = list() if(vend_flags & VEND_STOCK_DYNAMIC) populate_product_list(1.0) - dynamic_stock_multipliers = list() for(var/list/vendspec in listed_products) var/multiplier = vendspec[2] if(multiplier > 0) - var/awarded = round(vendspec[2] * scale, 1) // Starting amount + var/awarded = round(multiplier * scale, 1) // Starting amount //Record the multiplier and how many have actually been given out - dynamic_stock_multipliers[vendspec] = list(vendspec[2], awarded) + dynamic_stock_multipliers[vendspec] = list(multiplier, awarded) vendspec[2] = awarded // Override starting amount else populate_product_list(scale) + for(var/list/vendspec in listed_products) + var/amount = vendspec[2] + if(amount > -1) + var/multiplier = Ceiling(amount / scale) + //Record the multiplier and how many have actually been given out + dynamic_stock_multipliers[vendspec] = list(multiplier, amount) if(vend_flags & VEND_LOAD_AMMO_BOXES) populate_ammo_boxes() - return ///Updates the vendor stock when the [/datum/game_mode/var/marine_tally] has changed and we're using [VEND_STOCK_DYNAMIC] ///Assumes the scale can only increase!!! Don't take their items away! @@ -994,10 +1005,9 @@ GLOBAL_LIST_EMPTY(vending_products) stock(I, user) /obj/structure/machinery/cm_vending/sorted/proc/stock(obj/item/item_to_stock, mob/user) - var/list/R var/list/stock_listed_products = get_listed_products(user) - for(R in (stock_listed_products)) - if(item_to_stock.type == R[3] && !istype(item_to_stock,/obj/item/storage)) + for(var/list/vendspec as anything in stock_listed_products) + if(item_to_stock.type == vendspec[3] && !istype(item_to_stock, /obj/item/storage)) if(istype(item_to_stock, /obj/item/device/defibrillator)) var/obj/item/device/defibrillator/D = item_to_stock @@ -1014,9 +1024,9 @@ GLOBAL_LIST_EMPTY(vending_products) to_chat(user, SPAN_WARNING("\The [item_to_stock] needs to be fully charged to restock it!")) return - else if(!additional_restock_checks(item_to_stock, user)) + else if(!additional_restock_checks(item_to_stock, user, vendspec)) // the error message needs to go in the proc - return FALSE + return if(item_to_stock.loc == user) //Inside the mob's inventory if(item_to_stock.flags_item & WIELDED) @@ -1028,15 +1038,15 @@ GLOBAL_LIST_EMPTY(vending_products) S.remove_from_storage(item_to_stock, user.loc) qdel(item_to_stock) - user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [R[1]]."), - SPAN_NOTICE("You stock [src] with \a [R[1]].")) - R[2]++ - update_derived_ammo_and_boxes_on_add(R) + user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [vendspec[1]]."), + SPAN_NOTICE("You stock [src] with \a [vendspec[1]].")) + vendspec[2]++ + update_derived_ammo_and_boxes_on_add(vendspec) updateUsrDialog() return //We found our item, no reason to go on. /// additional restocking checks for individual vendor subtypes. Parse in item, do checks, return FALSE to fail. Include error message. -/obj/structure/machinery/cm_vending/sorted/proc/additional_restock_checks(obj/item/item_to_stock, mob/user) +/obj/structure/machinery/cm_vending/sorted/proc/additional_restock_checks(obj/item/item_to_stock, mob/user, list/vendspec) return TRUE //sending an /empty ammo box type path here will return corresponding regular (full) type of this box diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index a867c9b61f29..8b5a6e9d6d9a 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -122,13 +122,13 @@ return FALSE return TRUE -/obj/structure/machinery/cm_vending/sorted/medical/additional_restock_checks(obj/item/item_to_stock, mob/user) +/obj/structure/machinery/cm_vending/sorted/medical/additional_restock_checks(obj/item/item_to_stock, mob/user, list/vendspec) if(istype(item_to_stock, /obj/item/reagent_container/hypospray/autoinjector) || istype(item_to_stock, /obj/item/reagent_container/glass/bottle)) if(requires_supply_link_port && !get_supply_link()) var/obj/item/reagent_container/container = item_to_stock if(container.reagents.total_volume < container.reagents.maximum_volume) if(user) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [container.name]. Looks like this vendor cannot refill these without a connected supply link.")) + to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [container]. Looks like this vendor cannot refill these without a connected supply link.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return FALSE @@ -141,10 +141,22 @@ to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [restock_stack]. Looks like this vendor cannot restock these without a connected supply link.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return FALSE + + var/dynamic_metadata = dynamic_stock_multipliers[vendspec] + if(dynamic_metadata) + if(requires_supply_link_port && !get_supply_link()) + if(vendspec[2] >= dynamic_metadata[2]) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE + else + stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") return TRUE /obj/structure/machinery/cm_vending/sorted/medical/attackby(obj/item/I, mob/user) - if(stat == WORKING && LAZYLEN(chem_refill) && (istype(I, /obj/item/reagent_container/hypospray/autoinjector) || istype(I, /obj/item/reagent_container/glass/bottle))) // only if we are completely fine and working + if(stat != WORKING) + return ..() + + if(istype(I, /obj/item/reagent_container/hypospray/autoinjector) || istype(I, /obj/item/reagent_container/glass/bottle)) if(!hacked) if(!allowed(user)) to_chat(user, SPAN_WARNING("Access denied.")) @@ -154,26 +166,28 @@ to_chat(user, SPAN_WARNING("This machine isn't for you.")) return - var/obj/item/reagent_container/C = I - if(!(C.type in chem_refill)) - to_chat(user, SPAN_WARNING("[src] cannot refill the [C.name].")) + var/obj/item/reagent_container/container = I + if(container.reagents.total_volume == container.reagents.maximum_volume) + stock(container, user) return - if(C.reagents.total_volume == C.reagents.maximum_volume) - to_chat(user, SPAN_WARNING("[src] makes a warning noise. The [C.name] is currently full.")) + if(!LAZYLEN(chem_refill) || !(container.type in chem_refill)) + to_chat(user, SPAN_WARNING("[src] cannot refill [container].")) return if(requires_supply_link_port && !get_supply_link()) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [C.name]. Looks like this vendor cannot refill these without a connected supply link.")) + to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [container]. Looks like this vendor cannot refill these without a connected supply link.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return - to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it refills your [C.name].")) + to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it refills your [container.name].")) // Since the reagent is deleted on use it's easier to make a new one instead of snowflake checking - var/obj/item/reagent_container/new_container = new C.type(src) - qdel(C) + var/obj/item/reagent_container/new_container = new container.type(src) + qdel(container) user.put_in_hands(new_container) - else if(stat == WORKING && LAZYLEN(stack_refill) && (istype(I, /obj/item/stack))) + return + + if((istype(I, /obj/item/stack))) if(!hacked) if(!allowed(user)) to_chat(user, SPAN_WARNING("Access denied.")) @@ -183,25 +197,26 @@ to_chat(user, SPAN_WARNING("This machine isn't for you.")) return - var/obj/item/stack/S = I - if(!(S.type in stack_refill)) - to_chat(user, SPAN_WARNING("[src] cannot restock the [S.name].")) + var/obj/item/stack/item_stack = I + if(item_stack.amount == item_stack.max_amount) + stock(item_stack, user) return - if(S.amount == S.max_amount) - to_chat(user, SPAN_WARNING("[src] makes a warning noise. The [S.name] is currently fully stacked.")) + if(!LAZYLEN(stack_refill) || !(item_stack.type in stack_refill)) + to_chat(user, SPAN_WARNING("[src] cannot restock [item_stack].")) return if(requires_supply_link_port && !get_supply_link()) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [S.name]. Looks like this vendor cannot restock these without a connected supply link.")) + to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [item_stack]. Looks like this vendor cannot restock these without a connected supply link.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return - to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it restocks your [S.name].")) - S.amount = S.max_amount - S.update_icon() - else - . = ..() + to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it restocks your [item_stack.name].")) + item_stack.amount = item_stack.max_amount + item_stack.update_icon() + return + + return ..() /obj/structure/machinery/cm_vending/sorted/medical/MouseDrop(obj/over_object as obj) if(stat == WORKING && over_object == usr && CAN_PICKUP(usr, src)) @@ -225,21 +240,21 @@ /obj/structure/machinery/cm_vending/sorted/medical/populate_product_list(scale) listed_products = list( list("FIELD SUPPLIES", -1, null, null), - list("Burn Kit", round(scale * 6), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), - list("Trauma Kit", round(scale * 6), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), - list("Ointment", round(scale * 6), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Roll of Gauze", round(scale * 6), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), - list("Splints", round(scale * 6), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("Burn Kit", round(scale * 8), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), + list("Trauma Kit", round(scale * 8), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), + list("Ointment", round(scale * 8), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), + list("Roll of Gauze", round(scale * 8), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), + list("Splints", round(scale * 8), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("AUTOINJECTORS", -1, null, null), - list("Autoinjector (Bicaridine)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/bicaridine, VENDOR_ITEM_REGULAR), - list("Autoinjector (Dexalin+)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/dexalinp, VENDOR_ITEM_REGULAR), - list("Autoinjector (Epinephrine)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/adrenaline, VENDOR_ITEM_REGULAR), - list("Autoinjector (Inaprovaline)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, VENDOR_ITEM_REGULAR), - list("Autoinjector (Kelotane)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/kelotane, VENDOR_ITEM_REGULAR), - list("Autoinjector (Oxycodone)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/oxycodone, VENDOR_ITEM_REGULAR), - list("Autoinjector (Tramadol)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/tramadol, VENDOR_ITEM_REGULAR), - list("Autoinjector (Tricord)", round(scale * 3), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), + list("Autoinjector (Bicaridine)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/bicaridine, VENDOR_ITEM_REGULAR), + list("Autoinjector (Dexalin+)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/dexalinp, VENDOR_ITEM_REGULAR), + list("Autoinjector (Epinephrine)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/adrenaline, VENDOR_ITEM_REGULAR), + list("Autoinjector (Inaprovaline)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, VENDOR_ITEM_REGULAR), + list("Autoinjector (Kelotane)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/kelotane, VENDOR_ITEM_REGULAR), + list("Autoinjector (Oxycodone)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/oxycodone, VENDOR_ITEM_REGULAR), + list("Autoinjector (Tramadol)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/tramadol, VENDOR_ITEM_REGULAR), + list("Autoinjector (Tricord)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), list("LIQUID BOTTLES", -1, null, null), list("Bottle (Bicaridine)", round(scale * 4), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), @@ -252,26 +267,103 @@ list("Bottle (Tramadol)", round(scale * 4), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), list("PILL BOTTLES", -1, null, null), - list("Pill Bottle (Bicaridine)", round(scale * 2), /obj/item/storage/pill_bottle/bicaridine, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Dexalin)", round(scale * 2), /obj/item/storage/pill_bottle/dexalin, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Dylovene)", round(scale * 2), /obj/item/storage/pill_bottle/antitox, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Inaprovaline)", round(scale * 2), /obj/item/storage/pill_bottle/inaprovaline, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Kelotane)", round(scale * 2), /obj/item/storage/pill_bottle/kelotane, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Peridaxon)", round(scale * 1), /obj/item/storage/pill_bottle/peridaxon, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Tramadol)", round(scale * 2), /obj/item/storage/pill_bottle/tramadol, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Bicaridine)", round(scale * 3), /obj/item/storage/pill_bottle/bicaridine, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Dexalin)", round(scale * 3), /obj/item/storage/pill_bottle/dexalin, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Dylovene)", round(scale * 3), /obj/item/storage/pill_bottle/antitox, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Inaprovaline)", round(scale * 3), /obj/item/storage/pill_bottle/inaprovaline, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Kelotane)", round(scale * 3), /obj/item/storage/pill_bottle/kelotane, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Peridaxon)", round(scale * 2), /obj/item/storage/pill_bottle/peridaxon, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Tramadol)", round(scale * 3), /obj/item/storage/pill_bottle/tramadol, VENDOR_ITEM_REGULAR), list("MEDICAL UTILITIES", -1, null, null), list("Emergency Defibrillator", round(scale * 3), /obj/item/device/defibrillator, VENDOR_ITEM_REGULAR), list("Surgical Line", round(scale * 2), /obj/item/tool/surgery/surgical_line, VENDOR_ITEM_REGULAR), list("Synth-Graft", round(scale * 2), /obj/item/tool/surgery/synthgraft, VENDOR_ITEM_REGULAR), - list("Hypospray", round(scale * 2), /obj/item/reagent_container/hypospray/tricordrazine, VENDOR_ITEM_REGULAR), + list("Hypospray", round(scale * 3), /obj/item/reagent_container/hypospray/tricordrazine, VENDOR_ITEM_REGULAR), list("Health Analyzer", round(scale * 5), /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), list("M276 Pattern Medical Storage Rig", round(scale * 2), /obj/item/storage/belt/medical, VENDOR_ITEM_REGULAR), list("Medical HUD Glasses", round(scale * 3), /obj/item/clothing/glasses/hud/health, VENDOR_ITEM_REGULAR), - list("Stasis Bag", round(scale * 2), /obj/item/bodybag/cryobag, VENDOR_ITEM_REGULAR), + list("Stasis Bag", round(scale * 4), /obj/item/bodybag/cryobag, VENDOR_ITEM_REGULAR), list("Syringe", round(scale * 7), /obj/item/reagent_container/syringe, VENDOR_ITEM_REGULAR) ) +/obj/structure/machinery/cm_vending/sorted/medical/populate_product_list_and_boxes(scale) + . = ..() + + // If this isn't a medlinked vendor (that needs a link) and isn't dynamically changing we will spawn with stock randomly removed from it + if(vend_flags & VEND_STOCK_DYNAMIC) + return + if(!requires_supply_link_port) + return + if(get_supply_link()) + return + var/turf/location = get_turf(src) + if(location && is_ground_level(location.z)) + random_unstock() + +/obj/structure/machinery/cm_vending/sorted/medical/Initialize() + . = ..() + + // If this is a medlinked vendor (that needs a link) and isn't dynamically changing it will periodically restock itself + if(vend_flags & VEND_STOCK_DYNAMIC) + return + if(!requires_supply_link_port) + return + if(!get_supply_link()) + return + START_PROCESSING(SSslowobj, src) + +/obj/structure/machinery/cm_vending/sorted/medical/toggle_anchored(obj/item/W, mob/user) + . = ..() + + // If the anchor state changed, this is a vendor that needs a link, and isn't dynamically changing, update whether we automatically restock + if(. && !(vend_flags & VEND_STOCK_DYNAMIC) && requires_supply_link_port) + if(get_supply_link()) + START_PROCESSING(SSslowobj, src) + else + STOP_PROCESSING(SSslowobj, src) + +/obj/structure/machinery/cm_vending/sorted/medical/process() + if(!get_supply_link()) + STOP_PROCESSING(SSslowobj, src) + return // Somehow we lost our link + automatic_restock() + +/// Randomly adjusts the amounts of listed_products towards their desired values +/obj/structure/machinery/cm_vending/sorted/medical/proc/automatic_restock() + for(var/list/vendspec as anything in listed_products) + if(vendspec[2] < 0) + continue // It's a section title, not an actual entry + var/dynamic_metadata = dynamic_stock_multipliers[vendspec] + if(!dynamic_metadata) + stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") + continue + if(vendspec[2] == dynamic_metadata[2]) + continue // Already at desired value + if(vendspec[2] > dynamic_metadata[2]) + vendspec[2]-- + update_derived_ammo_and_boxes(vendspec) + continue // Returned some items to the void + if(prob(80)) + continue // 20% chance to restock per entry + vendspec[2]++ + update_derived_ammo_and_boxes_on_add(vendspec) + +/// Randomly removes amounts of listed_products +/obj/structure/machinery/cm_vending/sorted/medical/proc/random_unstock() + for(var/list/vendspec as anything in listed_products) + var/amount = vendspec[2] + if(amount <= 0) + continue + + // Chance to just be empty + if(prob(25)) + vendspec[2] = 0 + continue + + // Otherwise its some amount between 1 and the original amount + vendspec[2] = rand(1, amount) + /obj/structure/machinery/cm_vending/sorted/medical/chemistry name = "\improper Wey-Chem Plus" desc = "Medical chemistry dispenser. Provided by Wey-Yu Pharmaceuticals Division(TM)." @@ -419,14 +511,14 @@ wrenchable = FALSE listed_products = list( list("SUPPLIES", -1, null, null), - list("First-Aid Autoinjector", 1, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), - list("Pain-Stop Autoinjector", 1, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), - list("Roll Of Gauze", 2, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), - list("Ointment", 2, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Medical Splints", 1, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("First-Aid Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), + list("Pain-Stop Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), + list("Roll Of Gauze", 4, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), + list("Ointment", 4, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), + list("Medical Splints", 2, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("UTILITY", -1, null, null), - list("HF2 Health Analyzer", 1, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR) + list("HF2 Health Analyzer", 2, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR) ) appearance_flags = TILE_BOUND @@ -498,14 +590,14 @@ icon = 'icons/obj/structures/souto_land.dmi' listed_products = list( list("FIRST AID SUPPLIES", -1, null, null), - list("First-Aid Autoinjector", 1, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), - list("Pain-Stop Autoinjector", 1, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), - list("Roll Of Gauze", 2, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), - list("Ointment", 2, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Medical Splints", 1, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("First-Aid Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), + list("Pain-Stop Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), + list("Roll Of Gauze", 4, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), + list("Ointment", 4, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), + list("Medical Splints", 2, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("UTILITY", -1, null, null), - list("HF2 Health Analyzer", 1, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), + list("HF2 Health Analyzer", 2, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), list("SOUTO", -1, null, null), list("Souto Classic", 1, /obj/item/reagent_container/food/drinks/cans/souto/classic, VENDOR_ITEM_REGULAR), From 0ffbdad8d4cf8503f350773d8d74fbcfec9e26e3 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 7 Apr 2024 04:10:54 -0700 Subject: [PATCH 03/29] Fix unused squad_prep vendors --- .../machinery/vending/vendor_types/squad_prep/squad_prep.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index d3662c785890..ce8499d1180f 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -207,6 +207,7 @@ req_one_access = list(ACCESS_MARINE_ALPHA, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/alpha/populate_product_list(scale) + ..() listed_products += list( list("HEADSET", -1, null, null), list("Marine Alpha Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/alpha, VENDOR_ITEM_REGULAR), @@ -217,6 +218,7 @@ req_one_access = list(ACCESS_MARINE_BRAVO, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/bravo/populate_product_list(scale) + ..() listed_products += list( list("HEADSET", -1, null, null), list("Marine Bravo Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/bravo, VENDOR_ITEM_REGULAR), @@ -227,6 +229,7 @@ req_one_access = list(ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/charlie/populate_product_list(scale) + ..() listed_products += list( list("HEADSET", -1, null, null), list("Marine Charlie Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/charlie, VENDOR_ITEM_REGULAR), @@ -237,6 +240,7 @@ req_one_access = list(ACCESS_MARINE_DELTA, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO) /obj/structure/machinery/cm_vending/sorted/uniform_supply/squad_prep/delta/populate_product_list(scale) + ..() listed_products += list( list("HEADSET", -1, null, null), list("Marine Delta Radio Headset", 10, /obj/item/device/radio/headset/almayer/marine/delta, VENDOR_ITEM_REGULAR), From fa8bb78eb456bb8e2be2e4b4b2ceb960f1839079 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 7 Apr 2024 06:25:28 -0700 Subject: [PATCH 04/29] Groundside nanomeds should also get their stock raided --- code/game/machinery/vending/vendor_types/medical.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 8b5a6e9d6d9a..e514246e162b 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -290,13 +290,9 @@ /obj/structure/machinery/cm_vending/sorted/medical/populate_product_list_and_boxes(scale) . = ..() - // If this isn't a medlinked vendor (that needs a link) and isn't dynamically changing we will spawn with stock randomly removed from it + // If this is groundside and isn't dynamically changing we will spawn with stock randomly removed from it if(vend_flags & VEND_STOCK_DYNAMIC) return - if(!requires_supply_link_port) - return - if(get_supply_link()) - return var/turf/location = get_turf(src) if(location && is_ground_level(location.z)) random_unstock() From 7ce7dd3bdec4d651ed1918c66e5c1082aefba5a6 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 7 Apr 2024 06:26:04 -0700 Subject: [PATCH 05/29] Anticheese for splints --- .../machinery/vending/vendor_types/medical.dm | 15 ++++ code/game/objects/items/stacks/medical.dm | 13 +++ code/modules/mob/living/carbon/human/human.dm | 79 ++++++++++--------- 3 files changed, 69 insertions(+), 38 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index e514246e162b..f451706062e2 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -134,6 +134,14 @@ //stacked items handling if the vendor cannot restock partial stacks else if(istype(item_to_stock, /obj/item/stack)) + if(istype(item_to_stock, /obj/item/stack/medical/splint)) + var/obj/item/stack/medical/splint/splint_item = item_to_stock + if(splint_item.contaminated) + if(user) + to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [splint_item]. Looks like this vendor cannot disinfect them.")) + playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) + return FALSE + if(requires_supply_link_port && !get_supply_link()) var/obj/item/stack/restock_stack = item_to_stock if(restock_stack.amount < restock_stack.max_amount) // if the stack is not full @@ -211,6 +219,13 @@ playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return + if(istype(item_stack, /obj/item/stack/medical/splint)) + var/obj/item/stack/medical/splint/splint_item = item_stack + if(splint_item.contaminated) + to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [splint_item]. Looks like this vendor cannot disinfect them.")) + playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) + return + to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it restocks your [item_stack.name].")) item_stack.amount = item_stack.max_amount item_stack.update_icon() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index cb5d88b4f7f3..22a246026704 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -271,6 +271,8 @@ stack_id = "splint" var/indestructible_splints = FALSE + /// Used to indicate when restocking this item cannot occur + var/contaminated = FALSE /obj/item/stack/medical/splint/attack(mob/living/carbon/M, mob/user) if(..()) return 1 @@ -318,3 +320,14 @@ if(affecting.apply_splints(src, user, M, indestructible_splints)) // Referenced in external organ helpers. use(1) playsound(user, 'sound/handling/splint1.ogg', 25, 1, 2) + +/obj/item/stack/medical/splint/attackby(obj/item/W, mob/user) + . = ..() + + // Whatever item isn't a full stack needs to be deemed contaminated if it was removed off a person + if(. && istype(W, /obj/item/stack/medical/splint)) + var/obj/item/stack/medical/splint/other_splint = W + if(!QDELETED(src) && other_splint.contaminated) + contaminated = TRUE + if(other_splint.amount == other_splint.max_amount) + other_splint.contaminated = FALSE diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0f52b75106a5..061ccb43f9ec 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1476,30 +1476,29 @@ remove_splints() // target = person whose splints are being removed -// source = person removing the splints -/mob/living/carbon/human/proc/remove_splints(mob/living/carbon/human/source) - var/mob/living/carbon/human/HT = src - var/mob/living/carbon/human/HS = source - - if(!istype(HS)) - HS = src - if(!istype(HS) || !istype(HT)) +// user = person removing the splints +/mob/living/carbon/human/proc/remove_splints(mob/living/carbon/human/user) + var/mob/living/carbon/human/target = src + + if(!istype(user)) + user = src + if(!istype(user) || !istype(target)) return var/cur_hand = "l_hand" - if(!HS.hand) + if(!user.hand) cur_hand = "r_hand" - if(!HS.action_busy) + if(!user.action_busy) var/list/obj/limb/to_splint = list() var/same_arm_side = FALSE // If you are trying to splint yourself, need opposite hand to splint an arm/hand - if(HS.get_limb(cur_hand).status & LIMB_DESTROYED) - to_chat(HS, SPAN_WARNING("You cannot remove splints without a hand.")) + if(user.get_limb(cur_hand).status & LIMB_DESTROYED) + to_chat(user, SPAN_WARNING("You cannot remove splints without a hand.")) return for(var/bodypart in list("l_leg","r_leg","l_arm","r_arm","r_hand","l_hand","r_foot","l_foot","chest","head","groin")) - var/obj/limb/l = HT.get_limb(bodypart) + var/obj/limb/l = target.get_limb(bodypart) if(l && (l.status & LIMB_SPLINTED)) - if(HS == HT) + if(user == target) if((bodypart in list("l_arm", "l_hand")) && (cur_hand == "l_hand")) same_arm_side = TRUE continue @@ -1510,43 +1509,47 @@ var/msg = "" // Have to use this because there are issues with the to_chat macros and text macros and quotation marks if(to_splint.len) - if(do_after(HS, HUMAN_STRIP_DELAY * HS.get_skill_duration_multiplier(SKILL_MEDICAL), INTERRUPT_ALL, BUSY_ICON_GENERIC, HT, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) + if(do_after(user, HUMAN_STRIP_DELAY * user.get_skill_duration_multiplier(SKILL_MEDICAL), INTERRUPT_ALL, BUSY_ICON_GENERIC, target, INTERRUPT_MOVED, BUSY_ICON_GENERIC)) var/can_reach_splints = TRUE var/amount_removed = 0 if(wear_suit && istype(wear_suit,/obj/item/clothing/suit/space)) - var/obj/item/clothing/suit/space/suit = HT.wear_suit + var/obj/item/clothing/suit/space/suit = target.wear_suit if(suit.supporting_limbs && suit.supporting_limbs.len) - msg = "[HS == HT ? "your":"\proper [HT]'s"]" - to_chat(HS, SPAN_WARNING("You cannot remove the splints, [msg] [suit] is supporting some of the breaks.")) + msg = "[user == target ? "your":"\proper [target]'s"]" + to_chat(user, SPAN_WARNING("You cannot remove the splints, [msg] [suit] is supporting some of the breaks.")) can_reach_splints = FALSE if(can_reach_splints) - var/obj/item/stack/W = new /obj/item/stack/medical/splint(HS.loc) - W.amount = 0 //we checked that we have at least one bodypart splinted, so we can create it no prob. Also we need amount to be 0 - W.add_fingerprint(HS) - for(var/obj/limb/l in to_splint) + var/obj/item/stack/medical/splint/new_splint = new(user.loc) + new_splint.amount = 0 //we checked that we have at least one bodypart splinted, so we can create it no prob. Also we need amount to be 0 + new_splint.add_fingerprint(user) + new_splint.contaminated = TRUE + for(var/obj/limb/cur_limb in to_splint) amount_removed++ - l.status &= ~LIMB_SPLINTED + cur_limb.status &= ~LIMB_SPLINTED pain.recalculate_pain() - if(l.status & LIMB_SPLINTED_INDESTRUCTIBLE) - new /obj/item/stack/medical/splint/nano(HS.loc, 1) - l.status &= ~LIMB_SPLINTED_INDESTRUCTIBLE - else if(!W.add(1)) - W = new /obj/item/stack/medical/splint(HS.loc)//old stack is dropped, time for new one - W.amount = 0 - W.add_fingerprint(HS) - W.add(1) - msg = "[HS == HT ? "their own":"\proper [HT]'s"]" - HT.visible_message(SPAN_NOTICE("[HS] removes [msg] [amount_removed>1 ? "splints":"splint"]."), \ + if(cur_limb.status & LIMB_SPLINTED_INDESTRUCTIBLE) + new /obj/item/stack/medical/splint/nano(user.loc, 1) + cur_limb.status &= ~LIMB_SPLINTED_INDESTRUCTIBLE + else if(!new_splint.add(1)) + new_splint = new(user.loc)//old stack is dropped, time for new one + new_splint.amount = 0 + new_splint.add_fingerprint(user) + new_splint.add(1) + new_splint.contaminated = TRUE + if(new_splint.amount == 0) + qdel(new_splint) //we only removed nano splints + msg = "[user == target ? "their own":"\proper [target]'s"]" + target.visible_message(SPAN_NOTICE("[user] removes [msg] [amount_removed>1 ? "splints":"splint"]."), \ SPAN_NOTICE("Your [amount_removed>1 ? "splints are":"splint is"] removed.")) - HT.update_med_icon() + target.update_med_icon() else - msg = "[HS == HT ? "your":"\proper [HT]'s"]" - to_chat(HS, SPAN_NOTICE("You stop trying to remove [msg] splints.")) + msg = "[user == target ? "your":"\proper [target]'s"]" + to_chat(user, SPAN_NOTICE("You stop trying to remove [msg] splints.")) else if(same_arm_side) - to_chat(HS, SPAN_WARNING("You need to use the opposite hand to remove the splints on your arm and hand!")) + to_chat(user, SPAN_WARNING("You need to use the opposite hand to remove the splints on your arm and hand!")) else - to_chat(HS, SPAN_WARNING("There are no splints to remove.")) + to_chat(user, SPAN_WARNING("There are no splints to remove.")) /mob/living/carbon/human/yautja/Initialize(mapload) . = ..(mapload, new_species = "Yautja") From 6fbf659e5e5e84d4387c222b92df04d422980069 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 7 Apr 2024 23:58:28 -0700 Subject: [PATCH 06/29] Restore medical stack splitting --- .../machinery/vending/vendor_types/medical.dm | 15 --------------- code/game/objects/items/stacks/medical.dm | 14 -------------- code/game/objects/items/stacks/stack.dm | 6 +----- code/modules/mob/living/carbon/human/human.dm | 2 -- 4 files changed, 1 insertion(+), 36 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index f451706062e2..e514246e162b 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -134,14 +134,6 @@ //stacked items handling if the vendor cannot restock partial stacks else if(istype(item_to_stock, /obj/item/stack)) - if(istype(item_to_stock, /obj/item/stack/medical/splint)) - var/obj/item/stack/medical/splint/splint_item = item_to_stock - if(splint_item.contaminated) - if(user) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [splint_item]. Looks like this vendor cannot disinfect them.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) - return FALSE - if(requires_supply_link_port && !get_supply_link()) var/obj/item/stack/restock_stack = item_to_stock if(restock_stack.amount < restock_stack.max_amount) // if the stack is not full @@ -219,13 +211,6 @@ playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return - if(istype(item_stack, /obj/item/stack/medical/splint)) - var/obj/item/stack/medical/splint/splint_item = item_stack - if(splint_item.contaminated) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [splint_item]. Looks like this vendor cannot disinfect them.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) - return - to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it restocks your [item_stack.name].")) item_stack.amount = item_stack.max_amount item_stack.update_icon() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 22a246026704..c4a496a12366 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -8,7 +8,6 @@ throw_speed = SPEED_VERY_FAST throw_range = 20 attack_speed = 3 - can_split = FALSE var/heal_brute = 0 var/heal_burn = 0 var/alien = FALSE @@ -271,8 +270,6 @@ stack_id = "splint" var/indestructible_splints = FALSE - /// Used to indicate when restocking this item cannot occur - var/contaminated = FALSE /obj/item/stack/medical/splint/attack(mob/living/carbon/M, mob/user) if(..()) return 1 @@ -320,14 +317,3 @@ if(affecting.apply_splints(src, user, M, indestructible_splints)) // Referenced in external organ helpers. use(1) playsound(user, 'sound/handling/splint1.ogg', 25, 1, 2) - -/obj/item/stack/medical/splint/attackby(obj/item/W, mob/user) - . = ..() - - // Whatever item isn't a full stack needs to be deemed contaminated if it was removed off a person - if(. && istype(W, /obj/item/stack/medical/splint)) - var/obj/item/stack/medical/splint/other_splint = W - if(!QDELETED(src) && other_splint.contaminated) - contaminated = TRUE - if(other_splint.amount == other_splint.max_amount) - other_splint.contaminated = FALSE diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 0b07ce92688d..bf23a82354b9 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -23,8 +23,6 @@ var/amount_sprites = FALSE ///does it show amount on top of the icon var/display_maptext = TRUE - ///whether the stack can be split into two different items - var/can_split = TRUE //Coords for contents display, to make it play nice with inventory borders. maptext_x = 4 maptext_y = 3 @@ -331,8 +329,6 @@ Also change the icon to reflect the amount of sheets, if possible.*/ return if(amount <= 1) return - if(!can_split) - return var/desired = tgui_input_number(user, "How much would you like to split off from this stack?", "How much?", 1, amount-1, 1) if(!desired) return @@ -350,7 +346,7 @@ Also change the icon to reflect the amount of sheets, if possible.*/ return ..() /obj/item/stack/attack_hand(mob/user as mob) - if(user.get_inactive_hand() == src && can_split) + if(user.get_inactive_hand() == src) var/obj/item/stack/new_stack = new type(user, 1) transfer_fingerprints_to(new_stack) user.put_in_hands(new_stack) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 061ccb43f9ec..c2852c6d4a2f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1522,7 +1522,6 @@ var/obj/item/stack/medical/splint/new_splint = new(user.loc) new_splint.amount = 0 //we checked that we have at least one bodypart splinted, so we can create it no prob. Also we need amount to be 0 new_splint.add_fingerprint(user) - new_splint.contaminated = TRUE for(var/obj/limb/cur_limb in to_splint) amount_removed++ cur_limb.status &= ~LIMB_SPLINTED @@ -1535,7 +1534,6 @@ new_splint.amount = 0 new_splint.add_fingerprint(user) new_splint.add(1) - new_splint.contaminated = TRUE if(new_splint.amount == 0) qdel(new_splint) //we only removed nano splints msg = "[user == target ? "their own":"\proper [target]'s"]" From 16f1ed53bca3ae77d1059edde799ea05520d6453 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 00:37:08 -0700 Subject: [PATCH 07/29] Disable medical stack refilling --- code/game/machinery/vending/cm_vending.dm | 26 +++++---- .../machinery/vending/vendor_types/medical.dm | 56 +------------------ .../vehicles/interior/interactable/vendors.dm | 12 ---- 3 files changed, 17 insertions(+), 77 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index bb47b5de25e6..bba8cf5d2f81 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -1010,18 +1010,24 @@ GLOBAL_LIST_EMPTY(vending_products) if(item_to_stock.type == vendspec[3] && !istype(item_to_stock, /obj/item/storage)) if(istype(item_to_stock, /obj/item/device/defibrillator)) - var/obj/item/device/defibrillator/D = item_to_stock - if(!D.dcell) - to_chat(user, SPAN_WARNING("\The [item_to_stock] needs a cell in it to be restocked!")) + var/obj/item/device/defibrillator/defib = item_to_stock + if(!defib.dcell) + to_chat(user, SPAN_WARNING("[item_to_stock] needs a cell in it to be restocked!")) return - if(D.dcell.charge < D.dcell.maxcharge) - to_chat(user, SPAN_WARNING("\The [item_to_stock] needs to be fully charged to restock it!")) + if(defib.dcell.charge < defib.dcell.maxcharge) + to_chat(user, SPAN_WARNING("[item_to_stock] needs to be fully charged to restock it!")) return else if(istype(item_to_stock, /obj/item/cell)) - var/obj/item/cell/C = item_to_stock - if(C.charge < C.maxcharge) - to_chat(user, SPAN_WARNING("\The [item_to_stock] needs to be fully charged to restock it!")) + var/obj/item/cell/cell = item_to_stock + if(cell.charge < cell.maxcharge) + to_chat(user, SPAN_WARNING("[item_to_stock] needs to be fully charged to restock it!")) + return + + else if(istype(item_to_stock, /obj/item/stack)) + var/obj/item/stack/item_stack = item_to_stock + if(item_stack.amount != item_stack.max_amount) + to_chat(user, SPAN_WARNING("[item_to_stock] needs to be a complete set to restock it!")) return else if(!additional_restock_checks(item_to_stock, user, vendspec)) @@ -1034,8 +1040,8 @@ GLOBAL_LIST_EMPTY(vending_products) user.temp_drop_inv_item(item_to_stock) if(isstorage(item_to_stock.loc)) //inside a storage item - var/obj/item/storage/S = item_to_stock.loc - S.remove_from_storage(item_to_stock, user.loc) + var/obj/item/storage/container = item_to_stock.loc + container.remove_from_storage(item_to_stock, user.loc) qdel(item_to_stock) user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [vendspec[1]]."), diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index e514246e162b..82d013a94015 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -96,13 +96,6 @@ /obj/item/reagent_container/glass/bottle/peridaxon, /obj/item/reagent_container/glass/bottle/tramadol, ) - var/list/stack_refill = list( - /obj/item/stack/medical/advanced/ointment, - /obj/item/stack/medical/advanced/bruise_pack, - /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint - ) /obj/structure/machinery/cm_vending/sorted/medical/Destroy() QDEL_NULL(last_health_display) @@ -132,16 +125,6 @@ playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return FALSE - //stacked items handling if the vendor cannot restock partial stacks - else if(istype(item_to_stock, /obj/item/stack)) - if(requires_supply_link_port && !get_supply_link()) - var/obj/item/stack/restock_stack = item_to_stock - if(restock_stack.amount < restock_stack.max_amount) // if the stack is not full - if(user) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [restock_stack]. Looks like this vendor cannot restock these without a connected supply link.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) - return FALSE - var/dynamic_metadata = dynamic_stock_multipliers[vendspec] if(dynamic_metadata) if(requires_supply_link_port && !get_supply_link()) @@ -197,23 +180,7 @@ to_chat(user, SPAN_WARNING("This machine isn't for you.")) return - var/obj/item/stack/item_stack = I - if(item_stack.amount == item_stack.max_amount) - stock(item_stack, user) - return - - if(!LAZYLEN(stack_refill) || !(item_stack.type in stack_refill)) - to_chat(user, SPAN_WARNING("[src] cannot restock [item_stack].")) - return - - if(requires_supply_link_port && !get_supply_link()) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [item_stack]. Looks like this vendor cannot restock these without a connected supply link.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) - return - - to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it restocks your [item_stack.name].")) - item_stack.amount = item_stack.max_amount - item_stack.update_icon() + stock(I, user) return return ..() @@ -377,7 +344,6 @@ /obj/item/reagent_container/glass/bottle/peridaxon, /obj/item/reagent_container/glass/bottle/tramadol, ) - stack_refill = null /obj/structure/machinery/cm_vending/sorted/medical/chemistry/populate_product_list(scale) listed_products = list( @@ -428,11 +394,6 @@ /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, ) - stack_refill = list( - /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint, - ) /obj/structure/machinery/cm_vending/sorted/medical/marinemed/populate_product_list(scale) listed_products = list( @@ -480,7 +441,6 @@ healthscan = FALSE chem_refill = null - stack_refill = null /obj/structure/machinery/cm_vending/sorted/medical/blood/bolted wrenchable = FALSE @@ -527,11 +487,6 @@ /obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless, /obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless, ) - stack_refill = list( - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint, - /obj/item/stack/medical/ointment, - ) /obj/structure/machinery/cm_vending/sorted/medical/wall_med/limited desc = "Wall-mounted Medical Equipment Dispenser. This version is more limited than standard USCM NanoMeds." @@ -540,10 +495,6 @@ /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, ) - stack_refill = list( - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/ointment, - ) /obj/structure/machinery/cm_vending/sorted/medical/wall_med/lifeboat name = "Lifeboat Medical Cabinet" @@ -565,11 +516,6 @@ list("Roll of Gauze", 8, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), list("Splints", 8, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR) ) - stack_refill = list( - /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint, - ) unacidable = TRUE unslashable = TRUE diff --git a/code/modules/vehicles/interior/interactable/vendors.dm b/code/modules/vehicles/interior/interactable/vendors.dm index d78764da4d73..d723f39407f6 100644 --- a/code/modules/vehicles/interior/interactable/vendors.dm +++ b/code/modules/vehicles/interior/interactable/vendors.dm @@ -17,10 +17,6 @@ /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, ) - stack_refill = list( - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/ointment, - ) //MED APC version of WY Med, provides resupply for basic stuff. Provides a decent amount of cryobags for evacuating hugged marines. /obj/structure/machinery/cm_vending/sorted/medical/vehicle @@ -57,14 +53,6 @@ /obj/item/reagent_container/hypospray/autoinjector/tricord/skillless, ) - stack_refill = list( - /obj/item/stack/medical/advanced/ointment, - /obj/item/stack/medical/advanced/bruise_pack, - /obj/item/stack/medical/ointment, - /obj/item/stack/medical/bruise_pack, - /obj/item/stack/medical/splint, - ) - /obj/structure/machinery/cm_vending/sorted/medical/vehicle/populate_product_list(scale) listed_products = list( list("FIELD SUPPLIES", -1, null, null), From 9db912b18212fbea31561c648846eb7c26576224 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 04:23:00 -0700 Subject: [PATCH 08/29] Rework restocking and chem refilling --- code/game/machinery/vending/cm_vending.dm | 28 ++++-- .../machinery/vending/vendor_types/medical.dm | 97 ++++++++++++------- 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index bba8cf5d2f81..a10900b3001b 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -1005,34 +1005,37 @@ GLOBAL_LIST_EMPTY(vending_products) stock(I, user) /obj/structure/machinery/cm_vending/sorted/proc/stock(obj/item/item_to_stock, mob/user) + if(istype(item_to_stock, /obj/item/storage)) + return FALSE + var/list/stock_listed_products = get_listed_products(user) for(var/list/vendspec as anything in stock_listed_products) - if(item_to_stock.type == vendspec[3] && !istype(item_to_stock, /obj/item/storage)) + if(item_to_stock.type == vendspec[3]) if(istype(item_to_stock, /obj/item/device/defibrillator)) var/obj/item/device/defibrillator/defib = item_to_stock if(!defib.dcell) to_chat(user, SPAN_WARNING("[item_to_stock] needs a cell in it to be restocked!")) - return + return FALSE if(defib.dcell.charge < defib.dcell.maxcharge) to_chat(user, SPAN_WARNING("[item_to_stock] needs to be fully charged to restock it!")) - return + return FALSE else if(istype(item_to_stock, /obj/item/cell)) var/obj/item/cell/cell = item_to_stock if(cell.charge < cell.maxcharge) to_chat(user, SPAN_WARNING("[item_to_stock] needs to be fully charged to restock it!")) - return + return FALSE else if(istype(item_to_stock, /obj/item/stack)) var/obj/item/stack/item_stack = item_to_stock if(item_stack.amount != item_stack.max_amount) to_chat(user, SPAN_WARNING("[item_to_stock] needs to be a complete set to restock it!")) - return + return FALSE - else if(!additional_restock_checks(item_to_stock, user, vendspec)) + if(!additional_restock_checks(item_to_stock, user, vendspec)) // the error message needs to go in the proc - return + return FALSE if(item_to_stock.loc == user) //Inside the mob's inventory if(item_to_stock.flags_item & WIELDED) @@ -1049,10 +1052,19 @@ GLOBAL_LIST_EMPTY(vending_products) vendspec[2]++ update_derived_ammo_and_boxes_on_add(vendspec) updateUsrDialog() - return //We found our item, no reason to go on. + return TRUE //We found our item, no reason to go on. + + return FALSE /// additional restocking checks for individual vendor subtypes. Parse in item, do checks, return FALSE to fail. Include error message. /obj/structure/machinery/cm_vending/sorted/proc/additional_restock_checks(obj/item/item_to_stock, mob/user, list/vendspec) + var/dynamic_metadata = dynamic_stock_multipliers[vendspec] + if(dynamic_metadata) + if(vendspec[2] >= dynamic_metadata[2]) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE + else + stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") return TRUE //sending an /empty ammo box type path here will return corresponding regular (full) type of this box diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 82d013a94015..bd51eca41557 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -70,6 +70,8 @@ var/datum/health_scan/last_health_display var/healthscan = TRUE + var/chem_refill_volume = 600 + var/chem_refill_volume_max = 600 var/list/chem_refill = list( /obj/item/reagent_container/hypospray/autoinjector/bicaridine, /obj/item/reagent_container/hypospray/autoinjector/dexalinp, @@ -104,7 +106,7 @@ /obj/structure/machinery/cm_vending/sorted/medical/get_examine_text(mob/living/carbon/human/user) . = ..() if(healthscan) - . += SPAN_NOTICE("The [src.name] offers assisted medical scan, for ease of usage with minimal training. Present the target in front of the scanner to scan.") + . += SPAN_NOTICE("[src] offers assisted medical scans, for ease of use with minimal training. Present the target in front of the scanner to scan.") /// checks if there is a supply link in our location and we are anchored to it /obj/structure/machinery/cm_vending/sorted/medical/proc/get_supply_link() @@ -116,30 +118,52 @@ return TRUE /obj/structure/machinery/cm_vending/sorted/medical/additional_restock_checks(obj/item/item_to_stock, mob/user, list/vendspec) - if(istype(item_to_stock, /obj/item/reagent_container/hypospray/autoinjector) || istype(item_to_stock, /obj/item/reagent_container/glass/bottle)) - if(requires_supply_link_port && !get_supply_link()) - var/obj/item/reagent_container/container = item_to_stock - if(container.reagents.total_volume < container.reagents.maximum_volume) - if(user) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [container]. Looks like this vendor cannot refill these without a connected supply link.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) - return FALSE - var/dynamic_metadata = dynamic_stock_multipliers[vendspec] if(dynamic_metadata) - if(requires_supply_link_port && !get_supply_link()) - if(vendspec[2] >= dynamic_metadata[2]) - to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) - return FALSE + if(vendspec[2] >= dynamic_metadata[2] && (!requires_supply_link_port || !get_supply_link())) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE else stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") + + if(istype(item_to_stock, /obj/item/reagent_container)) + if(istype(item_to_stock, /obj/item/reagent_container/syringe) || istype(item_to_stock, /obj/item/reagent_container/dropper)) + var/obj/item/reagent_container/container = item_to_stock + if(container.reagents.total_volume != 0) + to_chat(user, SPAN_WARNING("[item_to_stock] needs to be empty to restock it!")) + return FALSE + else + return try_deduct_chem(item_to_stock, user) + + return TRUE + +/// Attempts to consume our reagents needed for the container (doesn't actually change the container) +/// Will return TRUE if reagents were deducated or no reagents were needed +/obj/structure/machinery/cm_vending/sorted/medical/proc/try_deduct_chem(obj/item/reagent_container/container, mob/user) + var/missing_reagents = container.reagents.maximum_volume - container.reagents.total_volume + if(missing_reagents <= 0) + return TRUE + if(!LAZYLEN(chem_refill) || !(container.type in chem_refill)) + if(container.reagents.total_volume == initial(container.reagents.total_volume)) + return TRUE + to_chat(user, SPAN_WARNING("[src] cannot refill [container].")) + return FALSE + if(chem_refill_volume < missing_reagents) + var/auto_refill = requires_supply_link_port && get_supply_link() + to_chat(user, SPAN_WARNING("[src] blinks red and makes a buzzing noise as it rejects [container]. Looks like it doesn't have enough reagents [auto_refill ? "yet" : "left"].")) + playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) + return FALSE + + chem_refill_volume -= missing_reagents + to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it refills your [container.name].")) + playsound(src, 'sound/effects/refill.ogg', 25, 1, 3) return TRUE /obj/structure/machinery/cm_vending/sorted/medical/attackby(obj/item/I, mob/user) if(stat != WORKING) return ..() - if(istype(I, /obj/item/reagent_container/hypospray/autoinjector) || istype(I, /obj/item/reagent_container/glass/bottle)) + if(istype(I, /obj/item/reagent_container)) if(!hacked) if(!allowed(user)) to_chat(user, SPAN_WARNING("Access denied.")) @@ -150,38 +174,26 @@ return var/obj/item/reagent_container/container = I - if(container.reagents.total_volume == container.reagents.maximum_volume) + if(istype(I, /obj/item/reagent_container/syringe) || istype(I, /obj/item/reagent_container/dropper)) stock(container, user) return - if(!LAZYLEN(chem_refill) || !(container.type in chem_refill)) - to_chat(user, SPAN_WARNING("[src] cannot refill [container].")) + if(container.reagents.total_volume == container.reagents.maximum_volume) + stock(container, user) return - if(requires_supply_link_port && !get_supply_link()) - to_chat(user, SPAN_WARNING("[src] makes a buzzing noise as it rejects [container]. Looks like this vendor cannot refill these without a connected supply link.")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) + if(!try_deduct_chem(container, user)) return - to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it refills your [container.name].")) // Since the reagent is deleted on use it's easier to make a new one instead of snowflake checking var/obj/item/reagent_container/new_container = new container.type(src) qdel(container) user.put_in_hands(new_container) return - if((istype(I, /obj/item/stack))) - if(!hacked) - if(!allowed(user)) - to_chat(user, SPAN_WARNING("Access denied.")) - return - - if(LAZYLEN(vendor_role) && !vendor_role.Find(user.job)) - to_chat(user, SPAN_WARNING("This machine isn't for you.")) - return - - stock(I, user) - return + else if(hacked || (allowed(user) && (!LAZYLEN(vendor_role) || vendor_role.Find(user.job)))) + if(stock(I, user)) + return return ..() @@ -193,7 +205,7 @@ return if(!healthscan) - to_chat(user, SPAN_WARNING("\The [src] does not have health scanning function.")) + to_chat(user, SPAN_WARNING("[src] does not have health scanning function.")) return if (!last_health_display) @@ -293,7 +305,10 @@ automatic_restock() /// Randomly adjusts the amounts of listed_products towards their desired values +/// Reagents refill at a constant rate towards chem_refill_volume_max /obj/structure/machinery/cm_vending/sorted/medical/proc/automatic_restock() + chem_refill_volume = min(chem_refill_volume + 25, chem_refill_volume_max) + for(var/list/vendspec as anything in listed_products) if(vendspec[2] < 0) continue // It's a section title, not an actual entry @@ -312,8 +327,11 @@ vendspec[2]++ update_derived_ammo_and_boxes_on_add(vendspec) -/// Randomly removes amounts of listed_products +/// Randomly removes amounts of listed_products and reagents /obj/structure/machinery/cm_vending/sorted/medical/proc/random_unstock() + // Random interval of 25 for reagents + chem_refill_volume = rand(0, chem_refill_volume_max * 0.04) * 25 + for(var/list/vendspec as anything in listed_products) var/amount = vendspec[2] if(amount <= 0) @@ -479,6 +497,8 @@ appearance_flags = TILE_BOUND + chem_refill_volume = 250 + chem_refill_volume_max = 250 chem_refill = list( /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, @@ -491,6 +511,8 @@ /obj/structure/machinery/cm_vending/sorted/medical/wall_med/limited desc = "Wall-mounted Medical Equipment Dispenser. This version is more limited than standard USCM NanoMeds." + chem_refill_volume = 150 + chem_refill_volume_max = 150 chem_refill = list( /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, @@ -501,6 +523,7 @@ icon = 'icons/obj/structures/machinery/lifeboat.dmi' icon_state = "medcab" desc = "A wall-mounted cabinet containing medical supplies vital to survival. While better equipped, it can only refill basic supplies." + listed_products = list( list("AUTOINJECTORS", -1, null, null), list("First-Aid Autoinjector", 8, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), @@ -521,6 +544,8 @@ unslashable = TRUE wrenchable = FALSE hackable = FALSE + chem_refill_volume = 500 + chem_refill_volume_max = 500 /obj/structure/machinery/cm_vending/sorted/medical/wall_med/populate_product_list(scale) return From 98d74c66a29e5cc3723cb89c140620401dd99e05 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 04:53:23 -0700 Subject: [PATCH 09/29] Fix xenos being able to restock vendors --- code/game/machinery/vending/cm_vending.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index a10900b3001b..624a54b1f49c 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -990,15 +990,14 @@ GLOBAL_LIST_EMPTY(vending_products) .["displayed_categories"] = vendor_user_inventory_list(user, null, 4) /obj/structure/machinery/cm_vending/sorted/MouseDrop_T(atom/movable/A, mob/user) - if(inoperable()) return - if(user.stat || user.is_mob_restrained()) return - if(get_dist(user, src) > 1 || get_dist(src, A) > 1) return + if(!ishuman(user)) + return if(istype(A, /obj/item)) var/obj/item/I = A From 80e9df3fc5262663e2d860fbe9d1cacd506421e6 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 05:30:14 -0700 Subject: [PATCH 10/29] Bulk restocking from inventories --- code/game/machinery/vending/cm_vending.dm | 38 +++++++++++++++++-- .../vehicles/interior/interactable/vendors.dm | 1 - 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index 624a54b1f49c..c30d8a14869d 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -909,6 +909,8 @@ GLOBAL_LIST_EMPTY(vending_products) * The 1.0 scale is estimated because it is a divided by the scale rather than repopulating the list at 1.0 scale - anything that is a fixed amount won't necessarily be correct. */ var/list/list/dynamic_stock_multipliers + ///indicates someone is performing a restock that isn't instant + var/being_restocked = FALSE /obj/structure/machinery/cm_vending/sorted/Initialize() . = ..() @@ -999,9 +1001,39 @@ GLOBAL_LIST_EMPTY(vending_products) if(!ishuman(user)) return + // Try to bulk restock using a container + if(istype(A, /obj/item/storage)) + var/obj/item/storage/container = A + if(!length(container.contents)) + return + if(being_restocked) + to_chat(user, SPAN_WARNING("[src] is already being restocked, you will get in the way!")) + return + + user.visible_message(SPAN_NOTICE("[user] starts stocking a bunch of supplies into [src]."), \ + SPAN_NOTICE("You start stocking a bunch of supplies into [src].")) + being_restocked = TRUE + + for(var/obj/item/item in container.contents) + if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + if(QDELETED(item) || item.loc != container) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + stock(item, user) + + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with supplies."), \ + SPAN_NOTICE("You finish stocking [src] with supplies.")) + return + if(istype(A, /obj/item)) - var/obj/item/I = A - stock(I, user) + stock(A, user) /obj/structure/machinery/cm_vending/sorted/proc/stock(obj/item/item_to_stock, mob/user) if(istype(item_to_stock, /obj/item/storage)) @@ -1046,7 +1078,7 @@ GLOBAL_LIST_EMPTY(vending_products) container.remove_from_storage(item_to_stock, user.loc) qdel(item_to_stock) - user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [vendspec[1]]."), + user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [vendspec[1]]."), \ SPAN_NOTICE("You stock [src] with \a [vendspec[1]].")) vendspec[2]++ update_derived_ammo_and_boxes_on_add(vendspec) diff --git a/code/modules/vehicles/interior/interactable/vendors.dm b/code/modules/vehicles/interior/interactable/vendors.dm index d723f39407f6..b5a61a7edc9c 100644 --- a/code/modules/vehicles/interior/interactable/vendors.dm +++ b/code/modules/vehicles/interior/interactable/vendors.dm @@ -113,7 +113,6 @@ wrenchable = FALSE hackable = FALSE density = FALSE - var/being_restocked = FALSE vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND | VEND_LOAD_AMMO_BOXES From 910d5086f42b328112a096f38e7af54bea697f3c Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 14:46:06 -0700 Subject: [PATCH 11/29] Buff WeyChem reagents and chemical dispenser energy --- code/game/machinery/vending/vendor_types/medical.dm | 2 ++ code/modules/reagents/chemical_research/Chemical-Research.dm | 4 ++-- code/modules/reagents/chemistry_machinery/chem_storage.dm | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index bd51eca41557..7b8351c356bc 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -352,6 +352,8 @@ req_access = list(ACCESS_MARINE_CHEMISTRY) healthscan = FALSE + chem_refill_volume = 800 + chem_refill_volume_max = 800 chem_refill = list( /obj/item/reagent_container/glass/bottle/bicaridine, /obj/item/reagent_container/glass/bottle/antitoxin, diff --git a/code/modules/reagents/chemical_research/Chemical-Research.dm b/code/modules/reagents/chemical_research/Chemical-Research.dm index e66cb474df50..2050e7e8e607 100644 --- a/code/modules/reagents/chemical_research/Chemical-Research.dm +++ b/code/modules/reagents/chemical_research/Chemical-Research.dm @@ -115,7 +115,7 @@ GLOBAL_DATUM_INIT(chemical_data, /datum/chemical_data, new) return FALSE //Make the chem storage scale with number of dispensers storage.recharge_rate += 5 - storage.max_energy += 50 + storage.max_energy += 100 storage.energy = storage.max_energy return storage @@ -125,7 +125,7 @@ GLOBAL_DATUM_INIT(chemical_data, /datum/chemical_data, new) return FALSE //Make the chem storage scale with number of dispensers storage.recharge_rate -= 5 - storage.max_energy -= 50 + storage.max_energy -= 100 storage.energy = storage.max_energy return TRUE diff --git a/code/modules/reagents/chemistry_machinery/chem_storage.dm b/code/modules/reagents/chemistry_machinery/chem_storage.dm index 3df417741d82..1dc7022ced94 100644 --- a/code/modules/reagents/chemistry_machinery/chem_storage.dm +++ b/code/modules/reagents/chemistry_machinery/chem_storage.dm @@ -12,7 +12,7 @@ var/recharge_cooldown = 15 var/recharge_rate = 10 var/energy = 50 - var/max_energy = 50 + var/max_energy = 100 unslashable = TRUE unacidable = TRUE From 4aef0625493cd4d537d9ce129cab3a885d0a7ae9 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 15:18:17 -0700 Subject: [PATCH 12/29] Add reagent bars to vendor UI and tweak image alignment --- .../machinery/vending/vendor_types/medical.dm | 6 +++++ .../tgui/interfaces/VendingSorted.tsx | 27 ++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 7b8351c356bc..8f404c083d0e 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -108,6 +108,12 @@ if(healthscan) . += SPAN_NOTICE("[src] offers assisted medical scans, for ease of use with minimal training. Present the target in front of the scanner to scan.") +/obj/structure/machinery/cm_vending/sorted/medical/ui_data(mob/user) + . = ..() + if(LAZYLEN(chem_refill)) + .["reagents"] = chem_refill_volume + .["reagents_max"] = chem_refill_volume_max + /// checks if there is a supply link in our location and we are anchored to it /obj/structure/machinery/cm_vending/sorted/medical/proc/get_supply_link() if(!anchored) diff --git a/tgui/packages/tgui/interfaces/VendingSorted.tsx b/tgui/packages/tgui/interfaces/VendingSorted.tsx index f72ddb2c0a31..cabf13f48c14 100644 --- a/tgui/packages/tgui/interfaces/VendingSorted.tsx +++ b/tgui/packages/tgui/interfaces/VendingSorted.tsx @@ -1,10 +1,11 @@ import { KEY_ESCAPE } from 'common/keycodes'; import { useBackend, useLocalState } from '../backend'; -import { Button, Section, Flex, Box, Tooltip, Input, NoticeBox, Icon } from '../components'; +import { Button, Section, Flex, Box, Tooltip, Input, NoticeBox, Icon, ProgressBar } from '../components'; import { Window } from '../layouts'; import { classes } from 'common/react'; import { BoxProps } from '../components/Box'; import { Table, TableCell, TableRow } from '../components/Table'; +import { toFixed } from 'common/math'; const THEME_COMP = 0; const THEME_USCM = 1; @@ -37,6 +38,8 @@ interface VendingData { stock_listing: Array; show_points?: boolean; current_m_points?: number; + reagents?: number; + reagents_max?: number; } interface VenableItem { @@ -118,7 +121,7 @@ const VendableItemRow = (props: VenableItem) => { return ( <> - + @@ -164,7 +167,7 @@ const VendableClothingItemRow = (props: { return ( <> - + @@ -256,6 +259,7 @@ export const ViewVendingCategory = (props: VendingCategoryProps) => { return ( { const isEmpty = categories.length === 0; const show_points = data.show_points ?? false; const points = data.current_m_points ?? 0; + const reagents = data.reagents ?? 0; + const reagents_max = data.reagents_max ?? 0; return ( { /> + {reagents_max > 0 && ( + + + Reagents + + + + {toFixed(reagents) + ' units'} + + + + )} )} From 37a6bdbfa1c4ae6f1a5766574da78045a6494a0e Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 15:21:07 -0700 Subject: [PATCH 13/29] Discount all medical crates --- code/datums/supply_packs/medical.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/datums/supply_packs/medical.dm b/code/datums/supply_packs/medical.dm index 097642eb163f..f12097fc58c5 100644 --- a/code/datums/supply_packs/medical.dm +++ b/code/datums/supply_packs/medical.dm @@ -17,7 +17,7 @@ /obj/item/storage/pill_bottle/peridaxon, /obj/item/storage/box/pillbottles, ) - cost = 20 + cost = 15 containertype = /obj/structure/closet/crate/medical containername = "medical crate" group = "Medical" @@ -42,7 +42,7 @@ /obj/item/storage/box/pillbottles, /obj/item/storage/box/pillbottles, ) - cost = 20 + cost = 15 containertype = /obj/structure/closet/crate/medical containername = "medical crate" group = "Medical" @@ -61,7 +61,7 @@ /obj/item/storage/firstaid/adv, /obj/item/storage/firstaid/adv, ) - cost = 16 + cost = 11 containertype = /obj/structure/closet/crate/medical containername = "medical crate" group = "Medical" @@ -74,7 +74,7 @@ /obj/item/storage/box/bodybags, /obj/item/storage/box/bodybags, ) - cost = 12 + cost = 7 containertype = /obj/structure/closet/crate/medical containername = "body bag crate" group = "Medical" @@ -86,7 +86,7 @@ /obj/item/bodybag/cryobag, /obj/item/bodybag/cryobag, ) - cost = 20 + cost = 15 containertype = /obj/structure/closet/crate/medical containername = "stasis bag crate" group = "Medical" @@ -101,7 +101,7 @@ /obj/item/storage/box/masks, /obj/item/storage/box/gloves, ) - cost = 30 + cost = 25 containertype = /obj/structure/closet/crate/secure/surgery containername = "surgery crate" access = ACCESS_MARINE_MEDBAY From f19984eee1bd3a0f21c684b61425bf4658c1ceb7 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Mon, 8 Apr 2024 15:31:10 -0700 Subject: [PATCH 14/29] Add restocking carts orderable by req --- code/datums/supply_packs/medical.dm | 20 ++ .../machinery/vending/vendor_types/medical.dm | 227 +++++++++++++++++- 2 files changed, 234 insertions(+), 13 deletions(-) diff --git a/code/datums/supply_packs/medical.dm b/code/datums/supply_packs/medical.dm index f12097fc58c5..acfb9fe1793d 100644 --- a/code/datums/supply_packs/medical.dm +++ b/code/datums/supply_packs/medical.dm @@ -22,6 +22,26 @@ containername = "medical crate" group = "Medical" +/datum/supply_packs/medical_restock_cart + name = "medical restock cart" + contains = list( + /obj/structure/restock_cart/medical, + ) + cost = 20 + containertype = null + containername = "medical restock cart" + group = "Medical" + +/datum/supply_packs/medical_reagent_cart + name = "medical reagent restock cart" + contains = list( + /obj/structure/restock_cart/medical/reagent, + ) + cost = 20 + containertype = null + containername = "medical reagent restock cart" + group = "Medical" + /datum/supply_packs/pillbottle name = "pill bottle crate (x2 each)" contains = list( diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 8f404c083d0e..ae7b7342a595 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -1,4 +1,4 @@ -//------------SUPPLY LINK FOR MEDICAL VENDORS--------------- +//------------SUPPLY LINK FOR MEDICAL VENDORS------------ /obj/structure/medical_supply_link name = "medilink supply port" @@ -43,12 +43,147 @@ else icon_state = "[base_state]_unclamped" -// --- Green /obj/structure/medical_supply_link/green icon_state = "medlink_green_unclamped" base_state = "medlink_green" -//------------SORTED MEDICAL VENDORS--------------- + +//------------RESTOCK CARTS FOR MEDICAL VENDORS------------ + +/obj/structure/restock_cart + name = "restock cart" + desc = "A rather heavy cart filled with various supplies to restock a vendor with." + icon = 'icons/obj/objects.dmi' + icon_state = "tank_normal" // Temporary + var/overlay_color = rgb(252, 186, 3) // Temporary + density = TRUE + anchored = FALSE + drag_delay = 2 + health = 100 // Can be destroyed in 2-4 slashes. + unslashable = FALSE + ///The quantity of things this can restock + var/supplies_remaining = 20 + ///The max quantity of things this can restock + var/supplies_max = 20 + ///The descriptor for the kind of things being restocked + var/supply_descriptor = "supplies" + ///The sound to play when attacked + var/attacked_sound = 'sound/effects/metalhit.ogg' + ///The sound to play when destroyed + var/destroyed_sound = 'sound/effects/metalhit.ogg' + ///Random loot to spawn if destroyed as assoc list of type_path = max_quantity + var/list/destroyed_loot = list( + /obj/item/stack/sheet/metal = 2 + ) + +/obj/structure/restock_cart/medical + name = "\improper Wey-Yu restock cart" + desc = "A rather heavy cart filled with various supplies to restock a vendor with. Provided by Wey-Yu Pharmaceuticals Division(TM)." + icon = 'icons/obj/objects.dmi' + icon_state = "tank_normal" // Temporary + supplies_remaining = 20 + supplies_max = 20 + supply_descriptor = "sets of medical supplies" + destroyed_loot = list( + /obj/item/stack/medical/advanced/ointment = 3, + /obj/item/stack/medical/advanced/bruise_pack = 2, + /obj/item/stack/medical/ointment = 3, + /obj/item/stack/medical/bruise_pack = 2, + /obj/item/stack/medical/splint = 2, + /obj/item/device/healthanalyzer = 1, + ) + +/obj/structure/restock_cart/medical/reagent + name = "\improper Wey-Yu reagent restock cart" + desc = "A rather heavy cart filled with various reagents to restock a vendor with. Provided by Wey-Yu Pharmaceuticals Division(TM)." + icon_state = "tank_normal" // Temporary + overlay_color = rgb(252, 115, 3) // Temporary + supplies_remaining = 1200 + supplies_max = 1200 + supply_descriptor = "units of medical reagents" + destroyed_sound = 'sound/effects/slosh.ogg' + destroyed_loot = list() + +/obj/structure/restock_cart/Initialize(mapload, ...) + . = ..() + supplies_remaining = min(supplies_remaining, supplies_max) + update_icon() + +/obj/structure/restock_cart/update_icon() + . = ..() + var/image/overlay_image = image(icon, icon_state = "tn_color") // Temporary + overlay_image.color = overlay_color + overlays += overlay_image + +/obj/structure/restock_cart/get_examine_text(mob/user) + . = ..() + if(get_dist(user, src) > 2 && user != loc) + return + . += SPAN_NOTICE("It contains:") + if(supplies_remaining) + . += SPAN_NOTICE(" [supplies_remaining] [supply_descriptor].") + else + . += SPAN_NOTICE(" Nothing.") + +/obj/structure/restock_cart/deconstruct(disassembled) + playsound(loc, destroyed_sound, 35, 1) + visible_message(SPAN_NOTICE("[src] falls apart as its contents spill everywhere!")) + + // Assumption: supplies_max is > 0 + if(supplies_remaining > 0 && length(destroyed_loot)) + var/spawned_any = FALSE + var/probability = supplies_remaining / supplies_max + for(var/type_path in destroyed_loot) + if(prob(probability * 100)) + for(var/amount in 1 to rand(1, destroyed_loot[type_path])) + new type_path(loc) + spawned_any = TRUE + if(!spawned_any) // It wasn't empty so atleast drop something + var/type_path = pick(destroyed_loot) + for(var/amount in 1 to rand(1, destroyed_loot[type_path])) + new type_path(loc) + + return ..() + +/obj/structure/restock_cart/proc/healthcheck() + if(health <= 0) + deconstruct(FALSE) + +/obj/structure/restock_cart/bullet_act(obj/projectile/Proj) + health -= Proj.damage + playsound(src, attacked_sound, 25, 1) + healthcheck() + return TRUE + +/obj/structure/restock_cart/attack_alien(mob/living/carbon/xenomorph/user) + if(unslashable) + return XENO_NO_DELAY_ACTION + user.animation_attack_on(src) + health -= (rand(user.melee_damage_lower, user.melee_damage_upper)) + playsound(src, attacked_sound, 25, 1) + user.visible_message(SPAN_DANGER("[user] slashes [src]!"), \ + SPAN_DANGER("You slash [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT) + healthcheck() + return XENO_ATTACK_ACTION + +/obj/structure/restock_cart/ex_act(severity) + if(indestructible) + return + + switch(severity) + if(0 to EXPLOSION_THRESHOLD_LOW) + if(prob(5)) + deconstruct(FALSE) + return + if(EXPLOSION_THRESHOLD_LOW to EXPLOSION_THRESHOLD_MEDIUM) + if(prob(50)) + deconstruct(FALSE) + return + if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY) + deconstruct(FALSE) + return + +//------------SORTED MEDICAL VENDORS------------ /obj/structure/machinery/cm_vending/sorted/medical name = "\improper Wey-Med Plus" @@ -222,6 +357,63 @@ last_health_display.look_at(user, DETAIL_LEVEL_HEALTHANALYSER, bypass_checks = TRUE) return +/obj/structure/machinery/cm_vending/sorted/medical/MouseDrop_T(atom/movable/A, mob/user) + if(inoperable()) + return + if(user.stat || user.is_mob_restrained()) + return + if(get_dist(user, src) > 1 || get_dist(user, A) > 1) + return + if(!ishuman(user)) + return + + if(istype(A, /obj/structure/restock_cart/medical)) + var/obj/structure/restock_cart/medical/cart = A + if(cart.supplies_remaining <= 0) + to_chat(user, SPAN_WARNING("[cart] is empty!")) + return + if(being_restocked) + to_chat(user, SPAN_WARNING("[src] is already being restocked, you will get in the way!")) + return + + var/restocking_reagents = istype(cart, /obj/structure/restock_cart/medical/reagent) + if(restocking_reagents && !LAZYLEN(chem_refill)) + to_chat(user, SPAN_WARNING("[src] doesn't use reagent canisters!")) + return + + user.visible_message(SPAN_NOTICE("[user] starts stocking a bunch of supplies into [src]."), \ + SPAN_NOTICE("You start stocking a bunch of supplies into [src].")) + being_restocked = TRUE + + while(cart.supplies_remaining > 0) + if(!do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + if(QDELETED(cart) || get_dist(user, cart) > 1) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + + if(restocking_reagents) + var/reagent_added = restock_reagents(min(cart.supplies_remaining, 100)) + if(reagent_added <= 0 || chem_refill_volume == chem_refill_volume_max) + break // All done + cart.supplies_remaining -= reagent_added + else + if(!restock_supplies(prob_to_skip = 0, can_remove = FALSE)) + break // All done + cart.supplies_remaining-- + + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with supplies."), \ + SPAN_NOTICE("You finish stocking [src] with supplies.")) + return + + return ..() + /obj/structure/machinery/cm_vending/sorted/medical/populate_product_list(scale) listed_products = list( list("FIELD SUPPLIES", -1, null, null), @@ -308,13 +500,13 @@ if(!get_supply_link()) STOP_PROCESSING(SSslowobj, src) return // Somehow we lost our link - automatic_restock() - -/// Randomly adjusts the amounts of listed_products towards their desired values -/// Reagents refill at a constant rate towards chem_refill_volume_max -/obj/structure/machinery/cm_vending/sorted/medical/proc/automatic_restock() - chem_refill_volume = min(chem_refill_volume + 25, chem_refill_volume_max) + restock_supplies() + restock_reagents() +/// Randomly (based on prob_to_skip) adjusts all amounts of listed_products towards their desired values by 1 +/// Returns the quantity of items added +/obj/structure/machinery/cm_vending/sorted/medical/proc/restock_supplies(prob_to_skip = 80, can_remove = TRUE) + . = 0 for(var/list/vendspec as anything in listed_products) if(vendspec[2] < 0) continue // It's a section title, not an actual entry @@ -325,13 +517,22 @@ if(vendspec[2] == dynamic_metadata[2]) continue // Already at desired value if(vendspec[2] > dynamic_metadata[2]) - vendspec[2]-- - update_derived_ammo_and_boxes(vendspec) + if(can_remove) + vendspec[2]-- + update_derived_ammo_and_boxes(vendspec) continue // Returned some items to the void - if(prob(80)) - continue // 20% chance to restock per entry + if(prob(prob_to_skip)) + continue // 20% chance to restock per entry by default vendspec[2]++ update_derived_ammo_and_boxes_on_add(vendspec) + .++ + +/// Refills reagents towards chem_refill_volume_max +/// Returns the quantity of reagents added +/obj/structure/machinery/cm_vending/sorted/medical/proc/restock_reagents(additional_volume = 100) + var/old_value = chem_refill_volume + chem_refill_volume = min(chem_refill_volume + additional_volume, chem_refill_volume_max) + return chem_refill_volume - old_value /// Randomly removes amounts of listed_products and reagents /obj/structure/machinery/cm_vending/sorted/medical/proc/random_unstock() From 657b7634535984befdc734e1e02341f023c3ffdb Mon Sep 17 00:00:00 2001 From: Drulikar Date: Tue, 9 Apr 2024 21:40:08 -0700 Subject: [PATCH 15/29] Reduce refill sfx volume --- code/game/machinery/vending/vendor_types/medical.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index ae7b7342a595..c2ed8bbe7fb2 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -297,7 +297,7 @@ chem_refill_volume -= missing_reagents to_chat(user, SPAN_NOTICE("[src] makes a whirring noise as it refills your [container.name].")) - playsound(src, 'sound/effects/refill.ogg', 25, 1, 3) + playsound(src, 'sound/effects/refill.ogg', 10, 1, 3) return TRUE /obj/structure/machinery/cm_vending/sorted/medical/attackby(obj/item/I, mob/user) From 5d580cb490668a6f713e19d2c514909267c3b2fe Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 10 Apr 2024 04:59:24 -0700 Subject: [PATCH 16/29] Disable automatic restocking for blood vendors Enable round start scaling for blood vendors Refactoring --- .../machinery/vending/vendor_types/medical.dm | 100 ++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index c2ed8bbe7fb2..6b8645a3f3b2 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -6,12 +6,13 @@ icon = 'icons/effects/warning_stripes.dmi' icon_state = "medlink_unclamped" var/base_state = "medlink" + plane = FLOOR_PLANE + layer = ABOVE_TURF_LAYER //It's the floor, man + anchored = TRUE density = FALSE unslashable = TRUE unacidable = TRUE - plane = FLOOR_PLANE - layer = ABOVE_TURF_LAYER //It's the floor, man /obj/structure/medical_supply_link/ex_act(severity, direction) return FALSE @@ -56,11 +57,13 @@ icon = 'icons/obj/objects.dmi' icon_state = "tank_normal" // Temporary var/overlay_color = rgb(252, 186, 3) // Temporary + density = TRUE anchored = FALSE drag_delay = 2 health = 100 // Can be destroyed in 2-4 slashes. unslashable = FALSE + ///The quantity of things this can restock var/supplies_remaining = 20 ///The max quantity of things this can restock @@ -81,6 +84,7 @@ desc = "A rather heavy cart filled with various supplies to restock a vendor with. Provided by Wey-Yu Pharmaceuticals Division(TM)." icon = 'icons/obj/objects.dmi' icon_state = "tank_normal" // Temporary + supplies_remaining = 20 supplies_max = 20 supply_descriptor = "sets of medical supplies" @@ -98,6 +102,7 @@ desc = "A rather heavy cart filled with various reagents to restock a vendor with. Provided by Wey-Yu Pharmaceuticals Division(TM)." icon_state = "tank_normal" // Temporary overlay_color = rgb(252, 115, 3) // Temporary + supplies_remaining = 1200 supplies_max = 1200 supply_descriptor = "units of medical reagents" @@ -199,14 +204,18 @@ vendor_theme = VENDOR_THEME_COMPANY vend_delay = 0.5 SECONDS - /// sets vendor to require a medlink to be able to resupply - var/requires_supply_link_port = TRUE + /// Whether the vendor can use a medlink to be able to resupply automatically + var/allow_supply_link_restock = TRUE + /// Whether this vendor supports health scanning the user via mouse drop + var/healthscan = TRUE var/datum/health_scan/last_health_display - var/healthscan = TRUE + /// The starting volume of the chem refill tank var/chem_refill_volume = 600 + /// The maximum volume of the chem refill tank var/chem_refill_volume_max = 600 + /// A list of item types that allow reagent refilling var/list/chem_refill = list( /obj/item/reagent_container/hypospray/autoinjector/bicaridine, /obj/item/reagent_container/hypospray/autoinjector/dexalinp, @@ -216,6 +225,7 @@ /obj/item/reagent_container/hypospray/autoinjector/oxycodone, /obj/item/reagent_container/hypospray/autoinjector/tramadol, /obj/item/reagent_container/hypospray/autoinjector/tricord, + /obj/item/reagent_container/hypospray/autoinjector/skillless, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, @@ -232,7 +242,7 @@ /obj/item/reagent_container/glass/bottle/oxycodone, /obj/item/reagent_container/glass/bottle/peridaxon, /obj/item/reagent_container/glass/bottle/tramadol, - ) + ) /obj/structure/machinery/cm_vending/sorted/medical/Destroy() QDEL_NULL(last_health_display) @@ -261,7 +271,7 @@ /obj/structure/machinery/cm_vending/sorted/medical/additional_restock_checks(obj/item/item_to_stock, mob/user, list/vendspec) var/dynamic_metadata = dynamic_stock_multipliers[vendspec] if(dynamic_metadata) - if(vendspec[2] >= dynamic_metadata[2] && (!requires_supply_link_port || !get_supply_link())) + if(vendspec[2] >= dynamic_metadata[2] && (!allow_supply_link_restock || !get_supply_link())) to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) return FALSE else @@ -290,7 +300,7 @@ to_chat(user, SPAN_WARNING("[src] cannot refill [container].")) return FALSE if(chem_refill_volume < missing_reagents) - var/auto_refill = requires_supply_link_port && get_supply_link() + var/auto_refill = allow_supply_link_restock && get_supply_link() to_chat(user, SPAN_WARNING("[src] blinks red and makes a buzzing noise as it rejects [container]. Looks like it doesn't have enough reagents [auto_refill ? "yet" : "left"].")) playsound(src, 'sound/machines/buzz-sigh.ogg', 15, TRUE) return FALSE @@ -316,15 +326,17 @@ var/obj/item/reagent_container/container = I if(istype(I, /obj/item/reagent_container/syringe) || istype(I, /obj/item/reagent_container/dropper)) - stock(container, user) + if(!stock(container, user)) + return ..() return if(container.reagents.total_volume == container.reagents.maximum_volume) - stock(container, user) + if(!stock(container, user)) + return ..() return if(!try_deduct_chem(container, user)) - return + return ..() // Since the reagent is deleted on use it's easier to make a new one instead of snowflake checking var/obj/item/reagent_container/new_container = new container.type(src) @@ -362,7 +374,7 @@ return if(user.stat || user.is_mob_restrained()) return - if(get_dist(user, src) > 1 || get_dist(user, A) > 1) + if(get_dist(user, src) > 1 || get_dist(user, A) > 1) // More lenient return if(!ishuman(user)) return @@ -480,7 +492,7 @@ // If this is a medlinked vendor (that needs a link) and isn't dynamically changing it will periodically restock itself if(vend_flags & VEND_STOCK_DYNAMIC) return - if(!requires_supply_link_port) + if(!allow_supply_link_restock) return if(!get_supply_link()) return @@ -490,7 +502,7 @@ . = ..() // If the anchor state changed, this is a vendor that needs a link, and isn't dynamically changing, update whether we automatically restock - if(. && !(vend_flags & VEND_STOCK_DYNAMIC) && requires_supply_link_port) + if(. && !(vend_flags & VEND_STOCK_DYNAMIC) && allow_supply_link_restock) if(get_supply_link()) START_PROCESSING(SSslowobj, src) else @@ -557,8 +569,8 @@ desc = "Medical chemistry dispenser. Provided by Wey-Yu Pharmaceuticals Division(TM)." icon_state = "chem" req_access = list(ACCESS_MARINE_CHEMISTRY) - healthscan = FALSE + chem_refill_volume = 800 chem_refill_volume_max = 800 chem_refill = list( @@ -605,9 +617,9 @@ name = "\improper Medical Equipment Vendor" desc = "A vending machine dispensing various pieces of medical equipment." req_one_access = list(ACCESS_ILLEGAL_PIRATE, ACCESS_UPP_GENERAL, ACCESS_CLF_GENERAL) - requires_supply_link_port = FALSE req_access = null vendor_theme = VENDOR_THEME_CLF + allow_supply_link_restock = FALSE /obj/structure/machinery/cm_vending/sorted/medical/marinemed name = "\improper ColMarTech MarineMed" @@ -642,9 +654,9 @@ name = "\improper Basic Medical Supplies Vendor" desc = "A vending machine dispensing basic medical supplies." req_one_access = list(ACCESS_ILLEGAL_PIRATE, ACCESS_UPP_GENERAL, ACCESS_CLF_GENERAL) - requires_supply_link_port = FALSE req_access = null vendor_theme = VENDOR_THEME_CLF + allow_supply_link_restock = FALSE /obj/structure/machinery/cm_vending/sorted/medical/blood name = "\improper MM Blood Dispenser" @@ -652,46 +664,47 @@ icon_state = "blood" wrenchable = TRUE hackable = TRUE - - listed_products = list( - list("BLOOD PACKS", -1, null, null), - list("A+ Blood Pack", 5, /obj/item/reagent_container/blood/APlus, VENDOR_ITEM_REGULAR), - list("A- Blood Pack", 5, /obj/item/reagent_container/blood/AMinus, VENDOR_ITEM_REGULAR), - list("B+ Blood Pack", 5, /obj/item/reagent_container/blood/BPlus, VENDOR_ITEM_REGULAR), - list("B- Blood Pack", 5, /obj/item/reagent_container/blood/BMinus, VENDOR_ITEM_REGULAR), - list("O+ Blood Pack", 5, /obj/item/reagent_container/blood/OPlus, VENDOR_ITEM_REGULAR), - list("O- Blood Pack", 5, /obj/item/reagent_container/blood/OMinus, VENDOR_ITEM_REGULAR), - - list("MISCELLANEOUS", -1, null, null), - list("Empty Blood Pack", 5, /obj/item/reagent_container/blood, VENDOR_ITEM_REGULAR) - ) - healthscan = FALSE + allow_supply_link_restock = FALSE chem_refill = null /obj/structure/machinery/cm_vending/sorted/medical/blood/bolted wrenchable = FALSE /obj/structure/machinery/cm_vending/sorted/medical/blood/populate_product_list(scale) - return + listed_products = list( + list("BLOOD PACKS", -1, null, null), + list("A+ Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/APlus, VENDOR_ITEM_REGULAR), + list("A- Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/AMinus, VENDOR_ITEM_REGULAR), + list("B+ Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/BPlus, VENDOR_ITEM_REGULAR), + list("B- Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/BMinus, VENDOR_ITEM_REGULAR), + list("O+ Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/OPlus, VENDOR_ITEM_REGULAR), + list("O- Blood Pack", round(scale * 5), /obj/item/reagent_container/blood/OMinus, VENDOR_ITEM_REGULAR), + + list("MISCELLANEOUS", -1, null, null), + list("Empty Blood Pack", round(scale * 5), /obj/item/reagent_container/blood, VENDOR_ITEM_REGULAR) + ) /obj/structure/machinery/cm_vending/sorted/medical/blood/antag req_one_access = list(ACCESS_ILLEGAL_PIRATE, ACCESS_UPP_GENERAL, ACCESS_CLF_GENERAL) - requires_supply_link_port = FALSE req_access = null vendor_theme = VENDOR_THEME_CLF + allow_supply_link_restock = FALSE + + +//------------WALL MED VENDORS------------ /obj/structure/machinery/cm_vending/sorted/medical/wall_med name = "\improper NanoMed" desc = "Wall-mounted Medical Equipment Dispenser." icon_state = "wallmed" - vend_delay = 0.7 SECONDS - requires_supply_link_port = FALSE - + appearance_flags = TILE_BOUND req_access = list() - density = FALSE wrenchable = FALSE + vend_delay = 0.7 SECONDS + allow_supply_link_restock = FALSE + listed_products = list( list("SUPPLIES", -1, null, null), list("First-Aid Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), @@ -704,8 +717,6 @@ list("HF2 Health Analyzer", 2, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR) ) - appearance_flags = TILE_BOUND - chem_refill_volume = 250 chem_refill_volume_max = 250 chem_refill = list( @@ -732,6 +743,10 @@ icon = 'icons/obj/structures/machinery/lifeboat.dmi' icon_state = "medcab" desc = "A wall-mounted cabinet containing medical supplies vital to survival. While better equipped, it can only refill basic supplies." + unacidable = TRUE + unslashable = TRUE + wrenchable = FALSE + hackable = FALSE listed_products = list( list("AUTOINJECTORS", -1, null, null), @@ -749,10 +764,6 @@ list("Splints", 8, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR) ) - unacidable = TRUE - unslashable = TRUE - wrenchable = FALSE - hackable = FALSE chem_refill_volume = 500 chem_refill_volume_max = 500 @@ -762,8 +773,9 @@ /obj/structure/machinery/cm_vending/sorted/medical/wall_med/souto name = "\improper SoutoMed" desc = "In Soutoland (Trademark pending), one is never more than 6ft away from canned Havana goodness. Drink a Souto today! For a full selection of Souto products please visit a licensed retailer or vending machine. Also doubles as basic first aid station." - icon_state = "soutomed" icon = 'icons/obj/structures/souto_land.dmi' + icon_state = "soutomed" + listed_products = list( list("FIRST AID SUPPLIES", -1, null, null), list("First-Aid Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless, VENDOR_ITEM_REGULAR), From cce72ea18bda1d941687a336014f06f8c24274ee Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 10 Apr 2024 04:59:49 -0700 Subject: [PATCH 17/29] Shift 1 scale of bottles from med vendors to chem vendors --- .../machinery/vending/vendor_types/medical.dm | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 6b8645a3f3b2..352fcbc6b599 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -446,14 +446,14 @@ list("Autoinjector (Tricord)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), list("LIQUID BOTTLES", -1, null, null), - list("Bottle (Bicaridine)", round(scale * 4), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), - list("Bottle (Dylovene)", round(scale * 4), /obj/item/reagent_container/glass/bottle/antitoxin, VENDOR_ITEM_REGULAR), - list("Bottle (Dexalin)", round(scale * 4), /obj/item/reagent_container/glass/bottle/dexalin, VENDOR_ITEM_REGULAR), - list("Bottle (Inaprovaline)", round(scale * 4), /obj/item/reagent_container/glass/bottle/inaprovaline, VENDOR_ITEM_REGULAR), - list("Bottle (Kelotane)", round(scale * 4), /obj/item/reagent_container/glass/bottle/kelotane, VENDOR_ITEM_REGULAR), - list("Bottle (Oxycodone)", round(scale * 4), /obj/item/reagent_container/glass/bottle/oxycodone, VENDOR_ITEM_REGULAR), - list("Bottle (Peridaxon)", round(scale * 4), /obj/item/reagent_container/glass/bottle/peridaxon, VENDOR_ITEM_REGULAR), - list("Bottle (Tramadol)", round(scale * 4), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), + list("Bottle (Bicaridine)", round(scale * 3), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), + list("Bottle (Dylovene)", round(scale * 3), /obj/item/reagent_container/glass/bottle/antitoxin, VENDOR_ITEM_REGULAR), + list("Bottle (Dexalin)", round(scale * 3), /obj/item/reagent_container/glass/bottle/dexalin, VENDOR_ITEM_REGULAR), + list("Bottle (Inaprovaline)", round(scale * 3), /obj/item/reagent_container/glass/bottle/inaprovaline, VENDOR_ITEM_REGULAR), + list("Bottle (Kelotane)", round(scale * 3), /obj/item/reagent_container/glass/bottle/kelotane, VENDOR_ITEM_REGULAR), + list("Bottle (Oxycodone)", round(scale * 3), /obj/item/reagent_container/glass/bottle/oxycodone, VENDOR_ITEM_REGULAR), + list("Bottle (Peridaxon)", round(scale * 3), /obj/item/reagent_container/glass/bottle/peridaxon, VENDOR_ITEM_REGULAR), + list("Bottle (Tramadol)", round(scale * 3), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), list("PILL BOTTLES", -1, null, null), list("Pill Bottle (Bicaridine)", round(scale * 3), /obj/item/storage/pill_bottle/bicaridine, VENDOR_ITEM_REGULAR), @@ -587,14 +587,14 @@ /obj/structure/machinery/cm_vending/sorted/medical/chemistry/populate_product_list(scale) listed_products = list( list("LIQUID BOTTLES", -1, null, null), - list("Bicaridine Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), - list("Dylovene Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/antitoxin, VENDOR_ITEM_REGULAR), - list("Dexalin Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/dexalin, VENDOR_ITEM_REGULAR), - list("Inaprovaline Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/inaprovaline, VENDOR_ITEM_REGULAR), - list("Kelotane Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/kelotane, VENDOR_ITEM_REGULAR), - list("Oxycodone Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/oxycodone, VENDOR_ITEM_REGULAR), - list("Peridaxon Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/peridaxon, VENDOR_ITEM_REGULAR), - list("Tramadol Bottle", round(scale * 5), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), + list("Bicaridine Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), + list("Dylovene Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/antitoxin, VENDOR_ITEM_REGULAR), + list("Dexalin Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/dexalin, VENDOR_ITEM_REGULAR), + list("Inaprovaline Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/inaprovaline, VENDOR_ITEM_REGULAR), + list("Kelotane Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/kelotane, VENDOR_ITEM_REGULAR), + list("Oxycodone Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/oxycodone, VENDOR_ITEM_REGULAR), + list("Peridaxon Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/peridaxon, VENDOR_ITEM_REGULAR), + list("Tramadol Bottle", round(scale * 6), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), list("MISCELLANEOUS", -1, null, null), list("Beaker (60 Units)", round(scale * 3), /obj/item/reagent_container/glass/beaker, VENDOR_ITEM_REGULAR), From 25ff22563426b9b179924a193537d6487c3e900c Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 10 Apr 2024 06:54:01 -0700 Subject: [PATCH 18/29] Grabbed restock cart restocking --- .../machinery/vending/vendor_types/medical.dm | 95 ++++++++++--------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 352fcbc6b599..8f1bc8c58239 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -310,6 +310,50 @@ playsound(src, 'sound/effects/refill.ogg', 10, 1, 3) return TRUE +/// Performs automatic restocking via medical cart - will set being_restocked true during the action +/obj/structure/machinery/cm_vending/sorted/medical/proc/cart_restock(obj/structure/restock_cart/medical/cart, mob/user) + if(cart.supplies_remaining <= 0) + to_chat(user, SPAN_WARNING("[cart] is empty!")) + return + if(being_restocked) + to_chat(user, SPAN_WARNING("[src] is already being restocked, you will get in the way!")) + return + + var/restocking_reagents = istype(cart, /obj/structure/restock_cart/medical/reagent) + if(restocking_reagents && !LAZYLEN(chem_refill)) + to_chat(user, SPAN_WARNING("[src] doesn't use reagent canisters!")) + return + + user.visible_message(SPAN_NOTICE("[user] starts stocking a bunch of supplies into [src]."), \ + SPAN_NOTICE("You start stocking a bunch of supplies into [src].")) + being_restocked = TRUE + + while(cart.supplies_remaining > 0) + if(!do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + if(QDELETED(cart) || get_dist(user, cart) > 1) + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ + SPAN_NOTICE("You stop stocking [src] with supplies.")) + return + + if(restocking_reagents) + var/reagent_added = restock_reagents(min(cart.supplies_remaining, 100)) + if(reagent_added <= 0 || chem_refill_volume == chem_refill_volume_max) + break // All done + cart.supplies_remaining -= reagent_added + else + if(!restock_supplies(prob_to_skip = 0, can_remove = FALSE)) + break // All done + cart.supplies_remaining-- + + being_restocked = FALSE + user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with supplies."), \ + SPAN_NOTICE("You finish stocking [src] with supplies.")) + /obj/structure/machinery/cm_vending/sorted/medical/attackby(obj/item/I, mob/user) if(stat != WORKING) return ..() @@ -344,7 +388,13 @@ user.put_in_hands(new_container) return - else if(hacked || (allowed(user) && (!LAZYLEN(vendor_role) || vendor_role.Find(user.job)))) + if(ishuman(user) && istype(I, /obj/item/grab)) + var/obj/item/grab/grabbed = I + if(istype(grabbed.grabbed_thing, /obj/structure/restock_cart/medical)) + cart_restock(grabbed.grabbed_thing, user) + return + + if(hacked || (allowed(user) && (!LAZYLEN(vendor_role) || vendor_role.Find(user.job)))) if(stock(I, user)) return @@ -380,48 +430,7 @@ return if(istype(A, /obj/structure/restock_cart/medical)) - var/obj/structure/restock_cart/medical/cart = A - if(cart.supplies_remaining <= 0) - to_chat(user, SPAN_WARNING("[cart] is empty!")) - return - if(being_restocked) - to_chat(user, SPAN_WARNING("[src] is already being restocked, you will get in the way!")) - return - - var/restocking_reagents = istype(cart, /obj/structure/restock_cart/medical/reagent) - if(restocking_reagents && !LAZYLEN(chem_refill)) - to_chat(user, SPAN_WARNING("[src] doesn't use reagent canisters!")) - return - - user.visible_message(SPAN_NOTICE("[user] starts stocking a bunch of supplies into [src]."), \ - SPAN_NOTICE("You start stocking a bunch of supplies into [src].")) - being_restocked = TRUE - - while(cart.supplies_remaining > 0) - if(!do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) - being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ - SPAN_NOTICE("You stop stocking [src] with supplies.")) - return - if(QDELETED(cart) || get_dist(user, cart) > 1) - being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ - SPAN_NOTICE("You stop stocking [src] with supplies.")) - return - - if(restocking_reagents) - var/reagent_added = restock_reagents(min(cart.supplies_remaining, 100)) - if(reagent_added <= 0 || chem_refill_volume == chem_refill_volume_max) - break // All done - cart.supplies_remaining -= reagent_added - else - if(!restock_supplies(prob_to_skip = 0, can_remove = FALSE)) - break // All done - cart.supplies_remaining-- - - being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with supplies."), \ - SPAN_NOTICE("You finish stocking [src] with supplies.")) + cart_restock(A, user) return return ..() From 9a5664e9db9d20bfc77f5bb595721acca462dd94 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 10 Apr 2024 23:56:35 -0700 Subject: [PATCH 19/29] Cart disassembly --- .../machinery/vending/vendor_types/medical.dm | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 8f1bc8c58239..10e4b1f1f8db 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -131,8 +131,9 @@ . += SPAN_NOTICE(" Nothing.") /obj/structure/restock_cart/deconstruct(disassembled) - playsound(loc, destroyed_sound, 35, 1) - visible_message(SPAN_NOTICE("[src] falls apart as its contents spill everywhere!")) + if(!disassembled) + playsound(loc, destroyed_sound, 35, 1) + visible_message(SPAN_NOTICE("[src] falls apart as its contents spill everywhere!")) // Assumption: supplies_max is > 0 if(supplies_remaining > 0 && length(destroyed_loot)) @@ -150,6 +151,24 @@ return ..() +/obj/structure/restock_cart/attackby(obj/item/W, mob/user) + if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(user.action_busy) + return + playsound(src, 'sound/items/Ratchet.ogg', 25, 1) + user.visible_message(SPAN_NOTICE("[user] starts to deconstruct [src]."), \ + SPAN_NOTICE("You start deconstructing [src].")) + if(!do_after(user, 5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, src)) + return + user.visible_message(SPAN_NOTICE("[user] deconstructs [src]."), \ + SPAN_NOTICE("You deconstruct [src].")) + playsound(src, 'sound/items/Crowbar.ogg', 25, 1) + var/obj/item/stack/sheet/metal/parts = new(loc) + deconstruct(TRUE) + return + + return ..() + /obj/structure/restock_cart/proc/healthcheck() if(health <= 0) deconstruct(FALSE) From 6d0073cc0743c4b99a4e90e8b4dec206310ca87a Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 11 Apr 2024 00:07:15 -0700 Subject: [PATCH 20/29] Minor refactor --- code/game/machinery/vending/vendor_types/medical.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 10e4b1f1f8db..a8574b8e418c 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -138,9 +138,9 @@ // Assumption: supplies_max is > 0 if(supplies_remaining > 0 && length(destroyed_loot)) var/spawned_any = FALSE - var/probability = supplies_remaining / supplies_max + var/probability = (supplies_remaining / supplies_max) * 100 for(var/type_path in destroyed_loot) - if(prob(probability * 100)) + if(prob(probability)) for(var/amount in 1 to rand(1, destroyed_loot[type_path])) new type_path(loc) spawned_any = TRUE From bb7590f96da45050120a42d3a10ca0de4993ce2a Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 11 Apr 2024 00:28:55 -0700 Subject: [PATCH 21/29] Fix linter warning --- code/game/machinery/vending/vendor_types/medical.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index a8574b8e418c..1621752c84c9 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -163,7 +163,7 @@ user.visible_message(SPAN_NOTICE("[user] deconstructs [src]."), \ SPAN_NOTICE("You deconstruct [src].")) playsound(src, 'sound/items/Crowbar.ogg', 25, 1) - var/obj/item/stack/sheet/metal/parts = new(loc) + new /obj/item/stack/sheet/metal(loc) deconstruct(TRUE) return From bc95c5d0ce7a30f5523b032409766d8c6a6e39fe Mon Sep 17 00:00:00 2001 From: Drulikar Date: Thu, 11 Apr 2024 02:57:31 -0700 Subject: [PATCH 22/29] Add 20 min timer for auto restocking supplies, increase reagent restock rate by 25, increase weychem reagents to 1200, increase some weymed and wall_med supply scaling, lower weymed stasis bag scaling --- .../machinery/vending/vendor_types/medical.dm | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 1621752c84c9..70689efc1079 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -457,21 +457,21 @@ /obj/structure/machinery/cm_vending/sorted/medical/populate_product_list(scale) listed_products = list( list("FIELD SUPPLIES", -1, null, null), - list("Burn Kit", round(scale * 8), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), - list("Trauma Kit", round(scale * 8), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), - list("Ointment", round(scale * 8), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Roll of Gauze", round(scale * 8), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), - list("Splints", round(scale * 8), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("Burn Kit", round(scale * 10), /obj/item/stack/medical/advanced/ointment, VENDOR_ITEM_REGULAR), + list("Trauma Kit", round(scale * 10), /obj/item/stack/medical/advanced/bruise_pack, VENDOR_ITEM_REGULAR), + list("Ointment", round(scale * 10), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), + list("Roll of Gauze", round(scale * 10), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), + list("Splints", round(scale * 10), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("AUTOINJECTORS", -1, null, null), - list("Autoinjector (Bicaridine)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/bicaridine, VENDOR_ITEM_REGULAR), - list("Autoinjector (Dexalin+)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/dexalinp, VENDOR_ITEM_REGULAR), - list("Autoinjector (Epinephrine)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/adrenaline, VENDOR_ITEM_REGULAR), - list("Autoinjector (Inaprovaline)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, VENDOR_ITEM_REGULAR), - list("Autoinjector (Kelotane)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/kelotane, VENDOR_ITEM_REGULAR), - list("Autoinjector (Oxycodone)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/oxycodone, VENDOR_ITEM_REGULAR), - list("Autoinjector (Tramadol)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/tramadol, VENDOR_ITEM_REGULAR), - list("Autoinjector (Tricord)", round(scale * 4), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), + list("Autoinjector (Bicaridine)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/bicaridine, VENDOR_ITEM_REGULAR), + list("Autoinjector (Dexalin+)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/dexalinp, VENDOR_ITEM_REGULAR), + list("Autoinjector (Epinephrine)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/adrenaline, VENDOR_ITEM_REGULAR), + list("Autoinjector (Inaprovaline)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/inaprovaline, VENDOR_ITEM_REGULAR), + list("Autoinjector (Kelotane)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/kelotane, VENDOR_ITEM_REGULAR), + list("Autoinjector (Oxycodone)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/oxycodone, VENDOR_ITEM_REGULAR), + list("Autoinjector (Tramadol)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/tramadol, VENDOR_ITEM_REGULAR), + list("Autoinjector (Tricord)", round(scale * 5), /obj/item/reagent_container/hypospray/autoinjector/tricord, VENDOR_ITEM_REGULAR), list("LIQUID BOTTLES", -1, null, null), list("Bottle (Bicaridine)", round(scale * 3), /obj/item/reagent_container/glass/bottle/bicaridine, VENDOR_ITEM_REGULAR), @@ -484,13 +484,13 @@ list("Bottle (Tramadol)", round(scale * 3), /obj/item/reagent_container/glass/bottle/tramadol, VENDOR_ITEM_REGULAR), list("PILL BOTTLES", -1, null, null), - list("Pill Bottle (Bicaridine)", round(scale * 3), /obj/item/storage/pill_bottle/bicaridine, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Dexalin)", round(scale * 3), /obj/item/storage/pill_bottle/dexalin, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Dylovene)", round(scale * 3), /obj/item/storage/pill_bottle/antitox, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Inaprovaline)", round(scale * 3), /obj/item/storage/pill_bottle/inaprovaline, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Kelotane)", round(scale * 3), /obj/item/storage/pill_bottle/kelotane, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Peridaxon)", round(scale * 2), /obj/item/storage/pill_bottle/peridaxon, VENDOR_ITEM_REGULAR), - list("Pill Bottle (Tramadol)", round(scale * 3), /obj/item/storage/pill_bottle/tramadol, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Bicaridine)", round(scale * 4), /obj/item/storage/pill_bottle/bicaridine, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Dexalin)", round(scale * 4), /obj/item/storage/pill_bottle/dexalin, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Dylovene)", round(scale * 4), /obj/item/storage/pill_bottle/antitox, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Inaprovaline)", round(scale * 4), /obj/item/storage/pill_bottle/inaprovaline, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Kelotane)", round(scale * 4), /obj/item/storage/pill_bottle/kelotane, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Peridaxon)", round(scale * 3), /obj/item/storage/pill_bottle/peridaxon, VENDOR_ITEM_REGULAR), + list("Pill Bottle (Tramadol)", round(scale * 4), /obj/item/storage/pill_bottle/tramadol, VENDOR_ITEM_REGULAR), list("MEDICAL UTILITIES", -1, null, null), list("Emergency Defibrillator", round(scale * 3), /obj/item/device/defibrillator, VENDOR_ITEM_REGULAR), @@ -500,7 +500,7 @@ list("Health Analyzer", round(scale * 5), /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), list("M276 Pattern Medical Storage Rig", round(scale * 2), /obj/item/storage/belt/medical, VENDOR_ITEM_REGULAR), list("Medical HUD Glasses", round(scale * 3), /obj/item/clothing/glasses/hud/health, VENDOR_ITEM_REGULAR), - list("Stasis Bag", round(scale * 4), /obj/item/bodybag/cryobag, VENDOR_ITEM_REGULAR), + list("Stasis Bag", round(scale * 3), /obj/item/bodybag/cryobag, VENDOR_ITEM_REGULAR), list("Syringe", round(scale * 7), /obj/item/reagent_container/syringe, VENDOR_ITEM_REGULAR) ) @@ -540,7 +540,8 @@ if(!get_supply_link()) STOP_PROCESSING(SSslowobj, src) return // Somehow we lost our link - restock_supplies() + if(world.time - SSticker.mode.round_time_lobby > 20 MINUTES) + restock_supplies() restock_reagents() /// Randomly (based on prob_to_skip) adjusts all amounts of listed_products towards their desired values by 1 @@ -569,7 +570,7 @@ /// Refills reagents towards chem_refill_volume_max /// Returns the quantity of reagents added -/obj/structure/machinery/cm_vending/sorted/medical/proc/restock_reagents(additional_volume = 100) +/obj/structure/machinery/cm_vending/sorted/medical/proc/restock_reagents(additional_volume = 125) var/old_value = chem_refill_volume chem_refill_volume = min(chem_refill_volume + additional_volume, chem_refill_volume_max) return chem_refill_volume - old_value @@ -599,8 +600,8 @@ req_access = list(ACCESS_MARINE_CHEMISTRY) healthscan = FALSE - chem_refill_volume = 800 - chem_refill_volume_max = 800 + chem_refill_volume = 1200 + chem_refill_volume_max = 1200 chem_refill = list( /obj/item/reagent_container/glass/bottle/bicaridine, /obj/item/reagent_container/glass/bottle/antitoxin, @@ -673,9 +674,9 @@ list("FIELD SUPPLIES", -1, null, null), list("Fire Extinguisher (portable)", 5, /obj/item/tool/extinguisher/mini, VENDOR_ITEM_REGULAR), - list("Ointment", round(scale * 7), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Roll of Gauze", round(scale * 7), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), - list("Splints", round(scale * 7), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR) + list("Ointment", round(scale * 8), /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), + list("Roll of Gauze", round(scale * 8), /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), + list("Splints", round(scale * 8), /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR) ) /obj/structure/machinery/cm_vending/sorted/medical/marinemed/antag @@ -739,7 +740,7 @@ list("Pain-Stop Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), list("Roll Of Gauze", 4, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), list("Ointment", 4, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Medical Splints", 2, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("Medical Splints", 4, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("UTILITY", -1, null, null), list("HF2 Health Analyzer", 2, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR) @@ -810,7 +811,7 @@ list("Pain-Stop Autoinjector", 2, /obj/item/reagent_container/hypospray/autoinjector/skillless/tramadol, VENDOR_ITEM_REGULAR), list("Roll Of Gauze", 4, /obj/item/stack/medical/bruise_pack, VENDOR_ITEM_REGULAR), list("Ointment", 4, /obj/item/stack/medical/ointment, VENDOR_ITEM_REGULAR), - list("Medical Splints", 2, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), + list("Medical Splints", 4, /obj/item/stack/medical/splint, VENDOR_ITEM_REGULAR), list("UTILITY", -1, null, null), list("HF2 Health Analyzer", 2, /obj/item/device/healthanalyzer, VENDOR_ITEM_REGULAR), From bfdc7f3309019d30a077d2803952c187a4d66efd Mon Sep 17 00:00:00 2001 From: Drulikar Date: Fri, 12 Apr 2024 00:04:40 -0700 Subject: [PATCH 23/29] Niche logging when a human destroys/deconstructs a restock cart with supplies. Tweak restocking messages to use the descriptor instead. Faster restocking from carts. --- .../machinery/vending/vendor_types/medical.dm | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 70689efc1079..6426313ea7ca 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -164,19 +164,23 @@ SPAN_NOTICE("You deconstruct [src].")) playsound(src, 'sound/items/Crowbar.ogg', 25, 1) new /obj/item/stack/sheet/metal(loc) + if(supplies_remaining) + msg_admin_niche("[key_name(user)] deconstructed [src] with [supplies_remaining] [supply_descriptor] remaining in [get_area(src)] [ADMIN_JMP(loc)]", loc.x, loc.y, loc.z) deconstruct(TRUE) return return ..() -/obj/structure/restock_cart/proc/healthcheck() +/obj/structure/restock_cart/proc/healthcheck(mob/user) if(health <= 0) + if(supplies_remaining && ishuman(user)) + msg_admin_niche("[key_name(user)] destroyed [src] with [supplies_remaining] [supply_descriptor] remaining in [get_area(src)] [ADMIN_JMP(loc)]", loc.x, loc.y, loc.z) deconstruct(FALSE) /obj/structure/restock_cart/bullet_act(obj/projectile/Proj) health -= Proj.damage playsound(src, attacked_sound, 25, 1) - healthcheck() + healthcheck(Proj.firer) return TRUE /obj/structure/restock_cart/attack_alien(mob/living/carbon/xenomorph/user) @@ -187,7 +191,7 @@ playsound(src, attacked_sound, 25, 1) user.visible_message(SPAN_DANGER("[user] slashes [src]!"), \ SPAN_DANGER("You slash [src]!"), null, 5, CHAT_TYPE_XENO_COMBAT) - healthcheck() + healthcheck(user) return XENO_ATTACK_ACTION /obj/structure/restock_cart/ex_act(severity) @@ -340,23 +344,23 @@ var/restocking_reagents = istype(cart, /obj/structure/restock_cart/medical/reagent) if(restocking_reagents && !LAZYLEN(chem_refill)) - to_chat(user, SPAN_WARNING("[src] doesn't use reagent canisters!")) + to_chat(user, SPAN_WARNING("[src] doesn't use [cart.supply_descriptor]!")) return - user.visible_message(SPAN_NOTICE("[user] starts stocking a bunch of supplies into [src]."), \ - SPAN_NOTICE("You start stocking a bunch of supplies into [src].")) + user.visible_message(SPAN_NOTICE("[user] starts stocking [cart.supply_descriptor] supplies into [src]."), \ + SPAN_NOTICE("You start stocking [cart.supply_descriptor] into [src].")) being_restocked = TRUE while(cart.supplies_remaining > 0) - if(!do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) + if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC, src)) being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ - SPAN_NOTICE("You stop stocking [src] with supplies.")) + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with [cart.supply_descriptor]."), \ + SPAN_NOTICE("You stop stocking [src] with [cart.supply_descriptor].")) return if(QDELETED(cart) || get_dist(user, cart) > 1) being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with supplies."), \ - SPAN_NOTICE("You stop stocking [src] with supplies.")) + user.visible_message(SPAN_NOTICE("[user] stopped stocking [src] with [cart.supply_descriptor]."), \ + SPAN_NOTICE("You stop stocking [src] with [cart.supply_descriptor].")) return if(restocking_reagents) @@ -370,8 +374,8 @@ cart.supplies_remaining-- being_restocked = FALSE - user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with supplies."), \ - SPAN_NOTICE("You finish stocking [src] with supplies.")) + user.visible_message(SPAN_NOTICE("[user] finishes stocking [src] with [cart.supply_descriptor]."), \ + SPAN_NOTICE("You finish stocking [src] with [cart.supply_descriptor].")) /obj/structure/machinery/cm_vending/sorted/medical/attackby(obj/item/I, mob/user) if(stat != WORKING) From 06cf054efb9cb546c6ff73f7e1ceaaf3d10d2b8e Mon Sep 17 00:00:00 2001 From: Drulikar Date: Sun, 21 Apr 2024 18:57:58 -0700 Subject: [PATCH 24/29] Medlink restocking requires the machine to be operable. --- code/game/machinery/vending/vendor_types/medical.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 6426313ea7ca..dd261f17a7bb 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -544,6 +544,8 @@ if(!get_supply_link()) STOP_PROCESSING(SSslowobj, src) return // Somehow we lost our link + if(inoperable()) + return if(world.time - SSticker.mode.round_time_lobby > 20 MINUTES) restock_supplies() restock_reagents() From 667609673937858f2282603dd0965ab1688230e7 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 24 Apr 2024 15:14:40 -0700 Subject: [PATCH 25/29] Require vend flags for ammo boxes logic (vendor code seems to very inconsistently check this, but shouldn't actually change anything for any current medical vendors) --- code/game/machinery/vending/vendor_types/medical.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index dd261f17a7bb..e6f5b469b661 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -566,12 +566,14 @@ if(vendspec[2] > dynamic_metadata[2]) if(can_remove) vendspec[2]-- - update_derived_ammo_and_boxes(vendspec) + if(vend_flags & VEND_LOAD_AMMO_BOXES) + update_derived_ammo_and_boxes(vendspec) continue // Returned some items to the void if(prob(prob_to_skip)) continue // 20% chance to restock per entry by default vendspec[2]++ - update_derived_ammo_and_boxes_on_add(vendspec) + if(vend_flags & VEND_LOAD_AMMO_BOXES) + update_derived_ammo_and_boxes_on_add(vendspec) .++ /// Refills reagents towards chem_refill_volume_max From e36b0d172e6de2c079eceb054b6a7417017adce9 Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 24 Apr 2024 20:12:09 -0700 Subject: [PATCH 26/29] Partial stack restocking --- code/game/machinery/vending/cm_vending.dm | 102 +++++++++++++----- .../machinery/vending/vendor_types/medical.dm | 18 +++- .../tgui/interfaces/VendingSorted.tsx | 5 + 3 files changed, 94 insertions(+), 31 deletions(-) diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index c30d8a14869d..a2d5a22e0ba5 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -46,7 +46,11 @@ /// Direction to adjacent user from which we're allowed to do offset vending var/list/vend_dir_whitelist + /// The actual inventory for this vendor as a list of lists + /// 1: name 2: amount 3: type 4: flag var/list/listed_products = list() + /// Partial stacks to hold on to as an associated list of type : amount + var/list/partial_product_stacks = list() // Are points associated with this vendor tied to its instance? var/instanced_vendor_points = FALSE @@ -947,6 +951,12 @@ GLOBAL_LIST_EMPTY(vending_products) if(vend_flags & VEND_LOAD_AMMO_BOXES) populate_ammo_boxes() + partial_product_stacks = list() + for(var/list/vendspec in listed_products) + var/current_type = vendspec[3] + if(ispath(current_type, /obj/item/stack)) + partial_product_stacks[current_type] = 0 + ///Updates the vendor stock when the [/datum/game_mode/var/marine_tally] has changed and we're using [VEND_STOCK_DYNAMIC] ///Assumes the scale can only increase!!! Don't take their items away! /obj/structure/machinery/cm_vending/sorted/proc/update_dynamic_stock(new_scale) @@ -1043,6 +1053,7 @@ GLOBAL_LIST_EMPTY(vending_products) for(var/list/vendspec as anything in stock_listed_products) if(item_to_stock.type == vendspec[3]) + var/partial_stacks = 0 if(istype(item_to_stock, /obj/item/device/defibrillator)) var/obj/item/device/defibrillator/defib = item_to_stock if(!defib.dcell) @@ -1060,9 +1071,7 @@ GLOBAL_LIST_EMPTY(vending_products) else if(istype(item_to_stock, /obj/item/stack)) var/obj/item/stack/item_stack = item_to_stock - if(item_stack.amount != item_stack.max_amount) - to_chat(user, SPAN_WARNING("[item_to_stock] needs to be a complete set to restock it!")) - return FALSE + partial_stacks = item_stack.amount % item_stack.max_amount if(!additional_restock_checks(item_to_stock, user, vendspec)) // the error message needs to go in the proc @@ -1080,7 +1089,15 @@ GLOBAL_LIST_EMPTY(vending_products) qdel(item_to_stock) user.visible_message(SPAN_NOTICE("[user] stocks [src] with \a [vendspec[1]]."), \ SPAN_NOTICE("You stock [src] with \a [vendspec[1]].")) - vendspec[2]++ + if(partial_stacks) + var/obj/item/stack/item_stack = item_to_stock + var/existing_stacks = partial_product_stacks[item_to_stock.type] + var/combined_stacks = existing_stacks + partial_stacks + if(existing_stacks == 0 || combined_stacks > item_stack.max_amount) + vendspec[2]++ + partial_product_stacks[item_to_stock.type] = combined_stacks % item_stack.max_amount + else + vendspec[2]++ update_derived_ammo_and_boxes_on_add(vendspec) updateUsrDialog() return TRUE //We found our item, no reason to go on. @@ -1092,8 +1109,16 @@ GLOBAL_LIST_EMPTY(vending_products) var/dynamic_metadata = dynamic_stock_multipliers[vendspec] if(dynamic_metadata) if(vendspec[2] >= dynamic_metadata[2]) - to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) - return FALSE + if(!istype(item_to_stock, /obj/item/stack)) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE + var/obj/item/stack/item_stack = item_to_stock + if(partial_product_stacks[item_to_stock.type] == 0) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE // No partial stack to fill + if((partial_product_stacks[item_to_stock.type] + item_stack.amount) > item_stack.max_amount) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE // Exceeds partial stack to fill else stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") return TRUE @@ -1302,14 +1327,20 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( /obj/structure/machinery/cm_vending/proc/vendor_inventory_ui_data(mob/user) . = list() - var/list/ui_listed_products = get_listed_products(user) - var/list/ui_categories = list() - - for (var/i in 1 to length(ui_listed_products)) - var/list/myprod = ui_listed_products[i] //we take one list from listed_products - var/p_amount = myprod[2] //amount left - ui_categories += list(p_amount) - .["stock_listing"] = ui_categories + var/list/products = get_listed_products(user) + var/list/product_amounts = list() + var/list/product_partials = list() + + for(var/i in 1 to length(products)) + var/list/cur_prod = products[i] //we take one list from listed_products + product_amounts += list(cur_prod[2]) //amount left + var/cur_type = cur_prod[3] + var/cur_amount_partial = 0 + if(cur_type in partial_product_stacks) + cur_amount_partial = partial_product_stacks[cur_type] + product_partials += list(cur_amount_partial) + .["stock_listing"] = product_amounts + .["stock_listing_partials"] = product_partials /obj/structure/machinery/cm_vending/proc/vendor_successful_vend(list/itemspec, mob/living/carbon/human/user) if(stat & IN_USE) @@ -1326,19 +1357,23 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( sleep(vend_delay) var/prod_type = itemspec[3] + var/stack_amount = 0 + if(vend_flags & VEND_LIMITED_INVENTORY) + itemspec[2]-- + if(itemspec[2] == 0) + stack_amount = partial_product_stacks[prod_type] + partial_product_stacks[prod_type] = 0 + if(vend_flags & VEND_LOAD_AMMO_BOXES) + update_derived_ammo_and_boxes(itemspec) + if(islist(prod_type)) for(var/each_type in prod_type) - vendor_successful_vend_one(each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + vendor_successful_vend_one(each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM, stack_amount) SEND_SIGNAL(src, COMSIG_VENDOR_SUCCESSFUL_VEND, src, itemspec, user) else - vendor_successful_vend_one(prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + vendor_successful_vend_one(prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM, stack_amount) SEND_SIGNAL(src, COMSIG_VENDOR_SUCCESSFUL_VEND, src, itemspec, user) - if(vend_flags & VEND_LIMITED_INVENTORY) - itemspec[2]-- - if(vend_flags & VEND_LOAD_AMMO_BOXES) - update_derived_ammo_and_boxes(itemspec) - else to_chat(user, SPAN_WARNING("ERROR: itemspec is missing. Please report this to admins.")) sleep(15) @@ -1347,7 +1382,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( icon_state = initial(icon_state) update_icon() -/obj/structure/machinery/cm_vending/proc/vendor_successful_vend_one(prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override) +/obj/structure/machinery/cm_vending/proc/vendor_successful_vend_one(prod_type, mob/living/carbon/human/user, turf/target_turf, insignas_override, stack_amount) var/obj/item/new_item if(ispath(prod_type, /obj/item)) if(ispath(prod_type, /obj/item/weapon/gun)) @@ -1357,7 +1392,11 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( prod_type = headset_type else if(prod_type == /obj/item/clothing/gloves/marine) prod_type = gloves_type - new_item = new prod_type(target_turf) + if(stack_amount > 0 && ispath(prod_type, /obj/item/stack)) + new_item = new prod_type(target_turf, stack_amount) + else + new_item = new prod_type(target_turf) + new_item.add_fingerprint(user) else new_item = new prod_type(target_turf) @@ -1413,17 +1452,22 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( while(i <= length(products)) sleep(0.5) var/list/itemspec = products[i] + var/itemspec_item = itemspec[3] if(!itemspec[2] || itemspec[2] <= 0) i++ continue - itemspec[2] -= 1 + itemspec[2]-- var/list/spawned = list() - if(islist(itemspec[3])) - for(var/path in itemspec[3]) + if(islist(itemspec_item)) + for(var/path in itemspec_item) spawned += new path(loc) - else if(itemspec[3]) - var/path = itemspec[3] - spawned += new path(loc) + else if(itemspec_item) + if(itemspec[2] == 0 && partial_product_stacks[itemspec_item] > 0 && ispath(itemspec_item, /obj/item/stack)) + var/stack_amount = partial_product_stacks[itemspec_item] + partial_product_stacks[itemspec_item] = 0 + spawned += new itemspec_item(loc, stack_amount) + else + spawned += new itemspec_item(loc) if(throw_objects) for(var/atom/movable/spawned_atom in spawned) INVOKE_ASYNC(spawned_atom, TYPE_PROC_REF(/atom/movable, throw_atom), pick(orange(src, 4)), 4, SPEED_FAST) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index e6f5b469b661..aeaa85def0bb 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -295,8 +295,16 @@ var/dynamic_metadata = dynamic_stock_multipliers[vendspec] if(dynamic_metadata) if(vendspec[2] >= dynamic_metadata[2] && (!allow_supply_link_restock || !get_supply_link())) - to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) - return FALSE + if(!istype(item_to_stock, /obj/item/stack)) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE + var/obj/item/stack/item_stack = item_to_stock + if(partial_product_stacks[item_to_stock.type] == 0) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE // No partial stack to fill + if((partial_product_stacks[item_to_stock.type] + item_stack.amount) > item_stack.max_amount) + to_chat(user, SPAN_WARNING("[src] is already full of [vendspec[1]]!")) + return FALSE // Exceeds partial stack to fill else stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") @@ -561,11 +569,17 @@ if(!dynamic_metadata) stack_trace("[src] could not find dynamic_stock_multipliers for [vendspec[1]]!") continue + var/cur_type = vendspec[3] if(vendspec[2] == dynamic_metadata[2]) + if((cur_type in partial_product_stacks) && partial_product_stacks[cur_type] > 0) + partial_product_stacks[cur_type] = 0 + .++ continue // Already at desired value if(vendspec[2] > dynamic_metadata[2]) if(can_remove) vendspec[2]-- + if(cur_type in partial_product_stacks) + partial_product_stacks[cur_type] = 0 if(vend_flags & VEND_LOAD_AMMO_BOXES) update_derived_ammo_and_boxes(vendspec) continue // Returned some items to the void diff --git a/tgui/packages/tgui/interfaces/VendingSorted.tsx b/tgui/packages/tgui/interfaces/VendingSorted.tsx index cabf13f48c14..c479c33104c7 100644 --- a/tgui/packages/tgui/interfaces/VendingSorted.tsx +++ b/tgui/packages/tgui/interfaces/VendingSorted.tsx @@ -36,6 +36,7 @@ interface VendingData { theme: string; displayed_categories: VendingCategory[]; stock_listing: Array; + stock_listing_partials?: Array; show_points?: boolean; current_m_points?: number; reagents?: number; @@ -116,6 +117,9 @@ const VendableItemRow = (props: VenableItem) => { const quantity = data.stock_listing[record.prod_index - 1]; const available = quantity > 0; + const partial_quantity = + data.stock_listing_partials?.[record.prod_index - 1] ?? 0; + const partialDesignation = partial_quantity > 0 ? '*' : ''; const isMandatory = record.prod_color === VENDOR_ITEM_MANDATORY; const isRecommended = record.prod_color === VENDOR_ITEM_RECOMMENDED; @@ -130,6 +134,7 @@ const VendableItemRow = (props: VenableItem) => { {quantity} + {partialDesignation} From caa1a677921da5aa42ee0ea29077f2d51b7f8adf Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 24 Apr 2024 20:12:29 -0700 Subject: [PATCH 27/29] UI Polish --- tgui/packages/tgui/interfaces/VendingSorted.tsx | 13 ++++++++----- .../tgui/styles/interfaces/VendingSorted.scss | 9 +++++---- tgui/packages/tgui/styles/themes/uscm.scss | 3 +++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tgui/packages/tgui/interfaces/VendingSorted.tsx b/tgui/packages/tgui/interfaces/VendingSorted.tsx index c479c33104c7..76f32cfa6fae 100644 --- a/tgui/packages/tgui/interfaces/VendingSorted.tsx +++ b/tgui/packages/tgui/interfaces/VendingSorted.tsx @@ -131,7 +131,7 @@ const VendableItemRow = (props: VenableItem) => { /> - + {quantity} {partialDesignation} @@ -150,7 +150,10 @@ const VendableItemRow = (props: VenableItem) => { - + @@ -200,7 +203,7 @@ const VendableClothingItemRow = (props: { @@ -301,7 +304,7 @@ export const VendingSorted = () => { const { data, act } = useBackend(); if (data === undefined) { return ( - + no data! ); @@ -314,7 +317,7 @@ export const VendingSorted = () => { const reagents = data.reagents ?? 0; const reagents_max = data.reagents_max ?? 0; return ( - + Date: Wed, 24 Apr 2024 20:59:45 -0700 Subject: [PATCH 28/29] Correct scss theme --- tgui/packages/tgui/styles/themes/uscm.scss | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui/styles/themes/uscm.scss b/tgui/packages/tgui/styles/themes/uscm.scss index 8196abffd523..edfd444ff4fe 100644 --- a/tgui/packages/tgui/styles/themes/uscm.scss +++ b/tgui/packages/tgui/styles/themes/uscm.scss @@ -26,7 +26,9 @@ background-position: right 40px top 50%; background-repeat: no-repeat; } - .Vendor .VendingFlexAlt { - background-color: rgba(#0c0e1e, 1); + .Vendor { + .VendingFlexAlt { + background-color: rgba(#0c0e1e, 1); + } } } From 219a08fc20b385577345f4243906996f2452150f Mon Sep 17 00:00:00 2001 From: Drulikar Date: Wed, 1 May 2024 20:10:04 -0700 Subject: [PATCH 29/29] Add WO check to prevent unstocking groundside vendors. --- code/game/machinery/vending/vendor_types/medical.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index aeaa85def0bb..a3fd94eef768 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -522,6 +522,8 @@ // If this is groundside and isn't dynamically changing we will spawn with stock randomly removed from it if(vend_flags & VEND_STOCK_DYNAMIC) return + if(Check_WO()) + return var/turf/location = get_turf(src) if(location && is_ground_level(location.z)) random_unstock()