diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index dfad101c273..cc6b09c72aa 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -1,84 +1,94 @@ -#define TRANSFER_MODE_DESTROY 0 -#define TRANSFER_MODE_MOVE 1 -#define TARGET_BEAKER "beaker" -#define TARGET_BUFFER "buffer" - /obj/machinery/chem_master name = "ChemMaster 3000" desc = "Used to separate chemicals and distribute them in a variety of forms." - density = TRUE - layer = BELOW_OBJ_LAYER icon = 'icons/obj/medical/chemical.dmi' icon_state = "chemmaster" base_icon_state = "chemmaster" + density = TRUE idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.2 + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.2 resistance_flags = FIRE_PROOF | ACID_PROOF circuit = /obj/item/circuitboard/machine/chem_master - /// Icons for different percentages of buffer reagents - var/fill_icon = 'icons/obj/medical/reagent_fillings.dmi' - var/fill_icon_state = "chemmaster" - var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) + /// Inserted reagent container var/obj/item/reagent_containers/beaker /// Whether separated reagents should be moved back to container or destroyed. - var/transfer_mode = TRANSFER_MODE_MOVE - /// Whether reagent analysis screen is active - var/reagent_analysis_mode = FALSE - /// Reagent being analyzed - var/datum/reagent/analyzed_reagent + var/is_transfering = TRUE /// List of printable container types - var/list/printable_containers = list() - /// Container used by default to reset to (REF) - var/default_container - /// Selected printable container type (REF) - var/selected_container - /// Whether the machine has an option to suggest container - var/has_container_suggestion = FALSE - /// Whether to suggest container or not - var/do_suggest_container = FALSE - /// The container suggested by main reagent in the buffer - var/suggested_container + var/list/printable_containers + /// Container used by default to reset to + var/obj/item/reagent_containers/default_container + /// Selected printable container type + var/obj/item/reagent_containers/selected_container /// Whether the machine is busy with printing containers var/is_printing = FALSE - /// Number of printed containers in the current printing cycle for UI progress bar + /// Number of containers printed so far var/printing_progress + /// Number of containers to be printed var/printing_total - /// Default duration of printing cycle - var/printing_speed = 0.75 SECONDS // Duration of animation - /// The amount of containers printed in one cycle + /// The amount of containers that can be printed in 1 cycle var/printing_amount = 1 /obj/machinery/chem_master/Initialize(mapload) create_reagents(100) - load_printable_containers() - default_container = REF(printable_containers[printable_containers[1]][1]) + + printable_containers = load_printable_containers() + default_container = printable_containers[printable_containers[1]][1] selected_container = default_container - return ..() + + register_context() + + . = ..() + + var/obj/item/circuitboard/machine/chem_master/board = circuit + board.build_path = type + board.name = name /obj/machinery/chem_master/Destroy() QDEL_NULL(beaker) return ..() -/obj/machinery/chem_master/on_deconstruction(disassembled) - replace_beaker() - return ..() +/obj/machinery/chem_master/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item) || (held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1)) + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_RMB] = "Remove beaker" + . = CONTEXTUAL_SCREENTIP_SET + return . -/obj/machinery/chem_master/Exited(atom/movable/gone, direction) - . = ..() - if(gone == beaker) - beaker = null - update_appearance(UPDATE_ICON) + if(is_reagent_container(held_item) && held_item.is_open_container()) + if(!QDELETED(beaker)) + context[SCREENTIP_CONTEXT_LMB] = "Replace beaker" + else + context[SCREENTIP_CONTEXT_LMB] = "Insert beaker" + return CONTEXTUAL_SCREENTIP_SET + + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] panel" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""] anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(panel_open && held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET -/obj/machinery/chem_master/RefreshParts() +/obj/machinery/chem_master/examine(mob/user) . = ..() - reagents.maximum_volume = 0 - for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) - reagents.maximum_volume += beaker.reagents.maximum_volume - printing_amount = 0 - for(var/datum/stock_part/servo/servo in component_parts) - printing_amount += servo.tier - -/obj/machinery/chem_master/update_appearance(updates=ALL) + if(in_range(user, src) || isobserver(user)) + . += span_notice("The status display reads:
Reagent buffer capacity: [reagents.maximum_volume] units.
Number of containers printed per cycle [printing_amount].") + if(!QDELETED(beaker)) + . += span_notice("[beaker] of [beaker.reagents.maximum_volume]u capacity inserted") + . += span_notice("Right click with empty hand to remove beaker") + else + . += span_warning("Missing input beaker") + + . += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"]") + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"]") + if(panel_open) + . += span_notice("The machine can be [EXAMINE_HINT("pried")] apart.") + +/obj/machinery/chem_master/update_appearance(updates) . = ..() if(panel_open || (machine_stat & (NOPOWER|BROKEN))) set_light(0) @@ -102,9 +112,7 @@ // Screen overlay if(!panel_open && !(machine_stat & (NOPOWER | BROKEN))) var/screen_overlay = base_icon_state + "_overlay_screen" - if(reagent_analysis_mode) - screen_overlay += "_analysis" - else if(is_printing) + if(is_printing) screen_overlay += "_active" else if(reagents.total_volume > 0) screen_overlay += "_main" @@ -114,46 +122,126 @@ // Buffer reagents overlay if(reagents.total_volume) var/threshold = null + var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) for(var/i in 1 to fill_icon_thresholds.len) - if(ROUND_UP(100 * reagents.total_volume / reagents.maximum_volume) >= fill_icon_thresholds[i]) + if(ROUND_UP(100 * (reagents.total_volume / reagents.maximum_volume)) >= fill_icon_thresholds[i]) threshold = i if(threshold) - var/fill_name = "[fill_icon_state][fill_icon_thresholds[threshold]]" - var/mutable_appearance/filling = mutable_appearance(fill_icon, fill_name) + var/fill_name = "chemmaster[fill_icon_thresholds[threshold]]" + var/mutable_appearance/filling = mutable_appearance('icons/obj/medical/reagent_fillings.dmi', fill_name) filling.color = mix_color_from_reagents(reagents.reagent_list) . += filling +/obj/machinery/chem_master/Exited(atom/movable/gone, direction) + . = ..() + if(gone == beaker) + beaker = null + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/chem_master/on_set_is_operational(old_value) + if(!is_operational) + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/chem_master/RefreshParts() + . = ..() + reagents.maximum_volume = 0 + for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts) + reagents.maximum_volume += beaker.reagents.maximum_volume + + printing_amount = 0 + for(var/datum/stock_part/servo/servo in component_parts) + printing_amount += servo.tier * 12.5 + printing_amount = min(50, ROUND_UP(printing_amount)) + +///Return a map of category->list of containers this machine can print +/obj/machinery/chem_master/proc/load_printable_containers() + PROTECTED_PROC(TRUE) + SHOULD_BE_PURE(TRUE) + + var/static/list/containers + if(!length(containers)) + containers = list( + CAT_TUBES = GLOB.reagent_containers[CAT_TUBES], + CAT_PILLS = GLOB.reagent_containers[CAT_PILLS], + CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES], + CAT_HYPOS = GLOB.reagent_containers[CAT_HYPOS], // NOVA EDIT ADDITION + CAT_DARTS = GLOB.reagent_containers[CAT_DARTS], // NOVA EDIT ADDITION + ) + return containers + +/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + if(user.combat_mode || (tool.item_flags & ABSTRACT) || (tool.flags_1 & HOLOGRAM_1) || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) + return ..() + + if(is_reagent_container(tool) && tool.is_open_container()) + replace_beaker(user, tool) + if(!panel_open) + ui_interact(user) + return ITEM_INTERACT_SUCCESS + else + return ITEM_INTERACT_BLOCKING + + return ..() /obj/machinery/chem_master/wrench_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING /obj/machinery/chem_master/screwdriver_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) - update_appearance(UPDATE_ICON) + update_appearance(UPDATE_OVERLAYS) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING /obj/machinery/chem_master/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(is_printing) + balloon_alert(user, "still printing!") + return . + if(default_deconstruction_crowbar(tool)) return ITEM_INTERACT_SUCCESS - return ITEM_INTERACT_BLOCKING -/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - if(is_reagent_container(tool) && !(tool.item_flags & ABSTRACT) && tool.is_open_container()) - replace_beaker(user, tool) - if(!panel_open) - ui_interact(user) - return ITEM_INTERACT_SUCCESS +/** + * Insert, remove, replace the existig beaker + * Arguments + * + * * mob/living/user - the player trying to replace the beaker + * * obj/item/reagent_containers/new_beaker - the beaker we are trying to insert, swap with existing or remove if null + */ +/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) + PRIVATE_PROC(TRUE) - return ..() + if(!QDELETED(beaker)) + try_put_in_hand(beaker, user) + if(!QDELETED(new_beaker) && user.transferItemToLoc(new_beaker, src)) + beaker = new_beaker + update_appearance(UPDATE_OVERLAYS) /obj/machinery/chem_master/attack_hand_secondary(mob/user, list/modifiers) . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return . - if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH)) + if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) return . replace_beaker(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN @@ -164,27 +252,6 @@ /obj/machinery/chem_master/attack_ai_secondary(mob/user, list/modifiers) return attack_hand_secondary(user, modifiers) -/// Insert new beaker and/or eject the inserted one -/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) - if(new_beaker && user && !user.transferItemToLoc(new_beaker, src)) - return FALSE - if(beaker) - try_put_in_hand(beaker, user) - beaker = null - if(new_beaker) - beaker = new_beaker - update_appearance(UPDATE_ICON) - return TRUE - -/obj/machinery/chem_master/proc/load_printable_containers() - printable_containers = list( - CAT_TUBES = GLOB.reagent_containers[CAT_TUBES], - CAT_PILLS = GLOB.reagent_containers[CAT_PILLS], - CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES], - CAT_HYPOS = GLOB.reagent_containers[CAT_HYPOS], // NOVA EDIT ADDITION - CAT_DARTS = GLOB.reagent_containers[CAT_DARTS], // NOVA EDIT ADDITION - ) - /obj/machinery/chem_master/ui_assets(mob/user) return list( get_asset_datum(/datum/asset/spritesheet/chemmaster) @@ -198,274 +265,286 @@ /obj/machinery/chem_master/ui_static_data(mob/user) var/list/data = list() + data["categories"] = list() for(var/category in printable_containers) - var/container_data = list() + //make the category + var/list/category_list = list( + "name" = category, + "containers" = list(), + ) + + //add containers to this category for(var/obj/item/reagent_containers/container as anything in printable_containers[category]) - container_data += list(list( + category_list["containers"] += list(list( "icon" = sanitize_css_class_name("[container]"), "ref" = REF(container), "name" = initial(container.name), "volume" = initial(container.volume), )) - data["categories"]+= list(list( - "name" = category, - "containers" = container_data, - )) + + //add the category + data["categories"] += list(category_list) return data /obj/machinery/chem_master/ui_data(mob/user) - var/list/data = list() + . = list() + + //printing statictics + .["isPrinting"] = is_printing + .["printingProgress"] = printing_progress + .["printingTotal"] = printing_total + .["maxPrintable"] = printing_amount + + //contents of source beaker + var/list/beaker_data = null + if(!QDELETED(beaker)) + beaker_data = list() + beaker_data["maxVolume"] = beaker.volume + beaker_data["currentVolume"] = round(beaker.reagents.total_volume, CHEMICAL_VOLUME_ROUNDING) + var/list/beakerContents = list() + if(length(beaker.reagents.reagent_list)) + for(var/datum/reagent/reagent as anything in beaker.reagents.reagent_list) + beakerContents += list(list( + "ref" = "[reagent.type]", + "name" = reagent.name, + "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING), + "pH" = reagent.ph, + "color" = reagent.color, + "description" = reagent.description, + "purity" = reagent.purity, + "metaRate" = reagent.metabolization_rate, + "overdose" = reagent.overdose_threshold, + "addictionTypes" = reagents.parse_addictions(reagent), + )) + beaker_data["contents"] = beakerContents + .["beaker"] = beaker_data + + //contents of buffer + beaker_data = list() + beaker_data["maxVolume"] = reagents.maximum_volume + beaker_data["currentVolume"] = round(reagents.total_volume, CHEMICAL_VOLUME_ROUNDING) + var/list/beakerContents = list() + if(length(reagents.reagent_list)) + for(var/datum/reagent/reagent as anything in reagents.reagent_list) + beakerContents += list(list( + "ref" = "[reagent.type]", + "name" = reagent.name, + "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING), + "pH" = reagent.ph, + "color" = reagent.color, + "description" = reagent.description, + "purity" = reagent.purity, + "metaRate" = reagent.metabolization_rate, + "overdose" = reagent.overdose_threshold, + "addictionTypes" = reagents.parse_addictions(reagent), + )) + beaker_data["contents"] = beakerContents + .["buffer"] = beaker_data + + //is transfering or destroying reagents. applied only for buffer + .["isTransfering"] = is_transfering + + //container along with the suggested type + var/obj/item/reagent_containers/suggested_container = default_container + if(reagents.total_volume > 0) + var/datum/reagent/master_reagent = reagents.get_master_reagent() + var/container_found = FALSE + suggested_container = master_reagent.default_container + for(var/category in printable_containers) + for(var/obj/item/reagent_containers/container as anything in printable_containers[category]) + if(container == suggested_container) + suggested_container = REF(container) + container_found = TRUE + break + if(!container_found) + suggested_container = REF(default_container) + .["suggestedContainerRef"] = suggested_container + + //selected container + .["selectedContainerRef"] = REF(selected_container) + .["selectedContainerVolume"] = initial(selected_container.volume) + +/** + * Transfers a single reagent between buffer & beaker + * Arguments + * + * * mob/user - the player who is attempting the transfer + * * datum/reagents/source - the holder we are transferring from + * * datum/reagents/target - the holder we are transferring to + * * datum/reagent/path - the reagent typepath we are transfering + * * amount - volume to transfer -1 means custom amount + * * do_transfer - transfer the reagents else destroy them + */ +/obj/machinery/chem_master/proc/transfer_reagent(mob/user, datum/reagents/source, datum/reagents/target, datum/reagent/path, amount, do_transfer) + PRIVATE_PROC(TRUE) + + //sanity checks for transfer amount + if(isnull(amount)) + return FALSE + amount = text2num(amount) + if(isnull(amount)) + return FALSE + if(amount == -1) + var/target_amount = tgui_input_number(user, "Enter amount to transfer", "Transfer amount") + if(!target_amount) + return FALSE + amount = text2num(target_amount) + if(isnull(amount)) + return FALSE + if(amount <= 0) + return FALSE - data["reagentAnalysisMode"] = reagent_analysis_mode - if(reagent_analysis_mode && analyzed_reagent) - var/state - switch(analyzed_reagent.reagent_state) - if(SOLID) - state = "Solid" - if(LIQUID) - state = "Liquid" - if(GAS) - state = "Gas" - else - state = "Unknown" - data["analysisData"] = list( - "name" = analyzed_reagent.name, - "state" = state, - "pH" = analyzed_reagent.ph, - "color" = analyzed_reagent.color, - "description" = analyzed_reagent.description, - "purity" = analyzed_reagent.purity, - "metaRate" = analyzed_reagent.metabolization_rate, - "overdose" = analyzed_reagent.overdose_threshold, - "addictionTypes" = reagents.parse_addictions(analyzed_reagent), - ) - else - data["isPrinting"] = is_printing - data["printingProgress"] = printing_progress - data["printingTotal"] = printing_total - data["hasBeaker"] = beaker ? TRUE : FALSE - data["beakerCurrentVolume"] = beaker ? round(beaker.reagents.total_volume, 0.01) : null - data["beakerMaxVolume"] = beaker ? beaker.volume : null - var/list/beaker_contents = list() - if(beaker) - for(var/datum/reagent/reagent in beaker.reagents.reagent_list) - beaker_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01)))) - data["beakerContents"] = beaker_contents - - var/list/buffer_contents = list() - if(reagents.total_volume) - for(var/datum/reagent/reagent in reagents.reagent_list) - buffer_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01)))) - data["bufferContents"] = buffer_contents - data["bufferCurrentVolume"] = round(reagents.total_volume, 0.01) - data["bufferMaxVolume"] = reagents.maximum_volume - - data["transferMode"] = transfer_mode - - data["hasContainerSuggestion"] = !!has_container_suggestion - if(has_container_suggestion) - data["doSuggestContainer"] = !!do_suggest_container - if(do_suggest_container) - if(reagents.total_volume > 0) - var/master_reagent = reagents.get_master_reagent() - suggested_container = get_suggested_container(master_reagent) - else - suggested_container = default_container - data["suggestedContainer"] = suggested_container - selected_container = suggested_container - else if (isnull(selected_container)) - selected_container = default_container - - data["selectedContainerRef"] = selected_container - var/obj/item/reagent_containers/container = locate(selected_container) - data["selectedContainerVolume"] = initial(container.volume) + //sanity checks for reagent path + var/datum/reagent/reagent = text2path(path) + if (!reagent) + return FALSE - return data + //use energy + if(!use_energy(active_power_usage)) + return FALSE -/obj/machinery/chem_master/ui_act(action, params) + //do the operation + . = FALSE + if(do_transfer) + if(target.is_reacting) + return FALSE + if(source.trans_to(target, amount, target_id = reagent)) + . = TRUE + else if(source.remove_reagent(reagent, amount)) + . = TRUE + if(. && !QDELETED(src)) //transferring volatile reagents can cause a explosion & destory us + update_appearance(UPDATE_OVERLAYS) + return . + +/obj/machinery/chem_master/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) . = ..() if(.) return - if(action == "eject") - replace_beaker(usr) - return TRUE - - if(action == "transfer") - var/reagent_ref = params["reagentRef"] - var/amount = text2num(params["amount"]) - var/target = params["target"] - return transfer_reagent(reagent_ref, amount, target) - - if(action == "toggleTransferMode") - transfer_mode = !transfer_mode - return TRUE - - if(action == "analyze") - analyzed_reagent = locate(params["reagentRef"]) - if(analyzed_reagent) - reagent_analysis_mode = TRUE - update_appearance(UPDATE_ICON) + switch(action) + if("eject") + replace_beaker(ui.user) return TRUE - if(action == "stopAnalysis") - reagent_analysis_mode = FALSE - analyzed_reagent = null - update_appearance(UPDATE_ICON) - return TRUE + if("transfer") + if(is_printing) + say("buffer locked while printing!") + return - if(action == "stopPrinting") - is_printing = FALSE - return TRUE + var/reagent_ref = params["reagentRef"] + var/amount = params["amount"] + var/target = params["target"] - if(action == "toggleContainerSuggestion") - do_suggest_container = !do_suggest_container - return TRUE + if(target == "buffer") + return transfer_reagent(ui.user, beaker.reagents, reagents, reagent_ref, amount, TRUE) + else if(target == "beaker") + return transfer_reagent(ui.user, reagents, beaker.reagents, reagent_ref, amount, is_transfering) + return FALSE - if(action == "selectContainer") - selected_container = params["ref"] - return TRUE + if("toggleTransferMode") + is_transfering = !is_transfering + return TRUE - if(action == "create") - if(reagents.total_volume == 0) - return FALSE - var/item_count = text2num(params["itemCount"]) - if(item_count <= 0) - return FALSE - create_containers(item_count) - return TRUE - -/// Create N selected containers with reagents from buffer split between them -/obj/machinery/chem_master/proc/create_containers(item_count = 1) - var/obj/item/reagent_containers/container_style = locate(selected_container) - var/is_pill_subtype = ispath(container_style, /obj/item/reagent_containers/pill) - var/volume_in_each = reagents.total_volume / item_count - var/printing_amount_current = is_pill_subtype ? printing_amount * 2 : printing_amount - - // Generate item name - var/item_name_default = initial(container_style.name) - var/datum/reagent/master_reagent = reagents.get_master_reagent() - if(selected_container == default_container) // Tubes and bottles gain reagent name - item_name_default = "[master_reagent.name] [item_name_default]" - if(!(initial(container_style.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name - item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)" - // NOVA EDIT ADDITION START - Autonamed hyposprays/smartdarts - if(ispath(container_style, /obj/item/reagent_containers/cup/vial) || ispath(container_style, /obj/item/reagent_containers/syringe/smartdart)) - item_name_default = "[master_reagent.name] [item_name_default]" - // NOVA EDIT ADDITION END - - var/item_name = tgui_input_text(usr, - "Container name", - "Name", - item_name_default, - MAX_NAME_LEN) - - if(!item_name || !reagents.total_volume || QDELETED(src) || !usr.can_perform_action(src, ALLOW_SILICON_REACH)) - return FALSE + if("stopPrinting") + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) + return TRUE - // Print and fill containers - is_printing = TRUE - update_appearance(UPDATE_ICON) - printing_progress = 0 - printing_total = item_count - while(item_count > 0) - if(!is_printing) - break - use_energy(active_power_usage) - stoplag(printing_speed) - for(var/i in 1 to printing_amount_current) - if(!item_count) - continue - var/obj/item/reagent_containers/item = new container_style(drop_location()) - adjust_item_drop_location(item) - item.name = item_name - item.reagents.clear_reagents() - reagents.trans_to(item, volume_in_each, transferred_by = src) - printing_progress++ - item_count-- - update_appearance(UPDATE_ICON) - is_printing = FALSE - update_appearance(UPDATE_ICON) - return TRUE - -/// Transfer reagents to specified target from the opposite source -/obj/machinery/chem_master/proc/transfer_reagent(reagent_ref, amount, target) - if (amount == -1) - amount = text2num(input("Enter the amount you want to transfer:", name, "")) - if (amount == null || amount <= 0) - return FALSE - if (!beaker && target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE) - return FALSE - var/datum/reagent/reagent = locate(reagent_ref) - if (!reagent) - return FALSE + if("selectContainer") + var/obj/item/reagent_containers/target = locate(params["ref"]) + if(!ispath(target)) + return FALSE - use_energy(active_power_usage) + selected_container = target + return TRUE - if (target == TARGET_BUFFER) - if(!check_reactions(reagent, beaker.reagents)) - return FALSE - beaker.reagents.trans_to(src, amount, target_id = reagent.type) - update_appearance(UPDATE_ICON) - return TRUE - - if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_DESTROY) - reagents.remove_reagent(reagent.type, amount) - update_appearance(UPDATE_ICON) - return TRUE - if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE) - if(!check_reactions(reagent, reagents)) - return FALSE - reagents.trans_to(beaker, amount, target_id = reagent.type) - update_appearance(UPDATE_ICON) - return TRUE + if("create") + if(!reagents.total_volume || is_printing) + return FALSE + + //validate print count + var/item_count = params["itemCount"] + if(isnull(item_count)) + return FALSE + item_count = text2num(item_count) + if(isnull(item_count) || item_count <= 0) + return FALSE + item_count = min(item_count, printing_amount) + var/volume_in_each = round(reagents.total_volume / item_count, CHEMICAL_VOLUME_ROUNDING) + + // Generate item name + var/item_name_default = initial(selected_container.name) + var/datum/reagent/master_reagent = reagents.get_master_reagent() + if(selected_container == default_container) // Tubes and bottles gain reagent name + item_name_default = "[master_reagent.name] [item_name_default]" + if(!(initial(selected_container.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name + item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)" + // NOVA EDIT ADDITION START - Autonamed hyposprays/smartdarts + if(ispath(selected_container, /obj/item/reagent_containers/cup/vial) || ispath(selected_container, /obj/item/reagent_containers/syringe/smartdart)) + item_name_default = "[master_reagent.name] [item_name_default]" + // NOVA EDIT ADDITION END + var/item_name = tgui_input_text(usr, + "Container name", + "Name", + item_name_default, + MAX_NAME_LEN) + if(!item_name) + return FALSE + + //start printing + is_printing = TRUE + printing_progress = 0 + printing_total = item_count + update_appearance(UPDATE_OVERLAYS) + create_containers(ui.user, item_count, item_name, volume_in_each) + return TRUE - return FALSE +/** + * Create N selected containers with reagents from buffer split between them + * Arguments + * + * * mob/user - the player printing these containers + * * item_count - number of containers to print + * * item_name - the name for each container printed + * * volume_in_each - volume in each container created + */ +/obj/machinery/chem_master/proc/create_containers(mob/user, item_count, item_name, volume_in_each) + PRIVATE_PROC(TRUE) + + //lost power or manually stopped + if(!is_printing) + return -/// Checks to see if the target reagent is being created (reacting) and if so prevents transfer -/// Only prevents reactant from being moved so that people can still manlipulate input reagents -/obj/machinery/chem_master/proc/check_reactions(datum/reagent/reagent, datum/reagents/holder) - if(!reagent) - return FALSE - var/canMove = TRUE - for(var/datum/equilibrium/equilibrium as anything in holder.reaction_list) - if(equilibrium.reaction.reaction_flags & REACTION_COMPETITIVE) - continue - for(var/datum/reagent/result as anything in equilibrium.reaction.required_reagents) - if(result == reagent.type) - canMove = FALSE - if(!canMove) - say("Cannot move reagent during reaction!") - return canMove - -/// Retrieve REF to the best container for provided reagent -/obj/machinery/chem_master/proc/get_suggested_container(datum/reagent/reagent) - var/preferred_container = reagent.default_container - for(var/category in printable_containers) - for(var/container in printable_containers[category]) - if(container == preferred_container) - return REF(container) - return default_container + //use power + if(!use_energy(active_power_usage)) + return -/obj/machinery/chem_master/examine(mob/user) - . = ..() - if(in_range(user, src) || isobserver(user)) - . += span_notice("The status display reads:
Reagent buffer capacity: [reagents.maximum_volume] units.
Number of containers printed at once increased by [100 * (printing_amount / initial(printing_amount)) - 100]%.") + //print the stuff + var/obj/item/reagent_containers/item = new selected_container(drop_location()) + adjust_item_drop_location(item) + item.name = item_name + item.reagents.clear_reagents() + reagents.trans_to(item, volume_in_each, transferred_by = user) + printing_progress++ + update_appearance(UPDATE_OVERLAYS) + + //print more items + item_count -- + if(item_count > 0) + addtimer(CALLBACK(src, PROC_REF(create_containers), user, item_count, item_name, volume_in_each), 0.75 SECONDS) + else + is_printing = FALSE + update_appearance(UPDATE_OVERLAYS) /obj/machinery/chem_master/condimaster name = "CondiMaster 3000" desc = "Used to create condiments and other cooking supplies." icon_state = "condimaster" - has_container_suggestion = TRUE /obj/machinery/chem_master/condimaster/load_printable_containers() - printable_containers = list( - CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS], - ) - -#undef TRANSFER_MODE_DESTROY -#undef TRANSFER_MODE_MOVE -#undef TARGET_BEAKER -#undef TARGET_BUFFER + var/static/list/containers + if(!length(containers)) + containers = list(CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS]) + return containers diff --git a/icons/obj/medical/chemical.dmi b/icons/obj/medical/chemical.dmi index b4b26e4f848..84dfd01d2d4 100644 Binary files a/icons/obj/medical/chemical.dmi and b/icons/obj/medical/chemical.dmi differ diff --git a/tgui/packages/tgui/interfaces/ChemMaster.tsx b/tgui/packages/tgui/interfaces/ChemMaster.tsx index 37b5db33f90..c23ca29f8d9 100644 --- a/tgui/packages/tgui/interfaces/ChemMaster.tsx +++ b/tgui/packages/tgui/interfaces/ChemMaster.tsx @@ -18,32 +18,22 @@ import { Tooltip, } from '../components'; import { Window } from '../layouts'; +import { Beaker, BeakerReagent } from './common/BeakerDisplay'; -type Data = { - reagentAnalysisMode: BooleanLike; - analysisData: Analysis; - isPrinting: BooleanLike; - printingProgress: number; - printingTotal: number; - transferMode: BooleanLike; - hasBeaker: BooleanLike; - beakerCurrentVolume: number; - beakerMaxVolume: number; - beakerContents: Reagent[]; - bufferContents: Reagent[]; - bufferCurrentVolume: number; - bufferMaxVolume: number; - categories: Category[]; - selectedContainerRef: string; - selectedContainerVolume: number; - hasContainerSuggestion: BooleanLike; - doSuggestContainer: BooleanLike; - suggestedContainer: string; +type Container = { + icon: string; + ref: string; + name: string; + volume: number; }; -type Analysis = { +type Category = { name: string; - state: string; + containers: Container[]; +}; + +type AnalyzableReagent = BeakerReagent & { + ref: string; pH: number; color: string; description: string; @@ -53,144 +43,162 @@ type Analysis = { addictionTypes: string[]; }; -type Category = { - name: string; - containers: Container[]; -}; - -type Reagent = { - ref: string; - name: string; - volume: number; -}; +type AnalyzableBeaker = { + contents: AnalyzableReagent[]; +} & Beaker; -type Container = { - icon: string; - ref: string; - name: string; - volume: number; +type Data = { + categories: Category[]; + isPrinting: BooleanLike; + printingProgress: number; + printingTotal: number; + maxPrintable: number; + beaker: AnalyzableBeaker; + buffer: AnalyzableBeaker; + isTransfering: BooleanLike; + suggestedContainerRef: string; + selectedContainerRef: string; + selectedContainerVolume: number; }; export const ChemMaster = (props) => { - const { data } = useBackend(); - const { reagentAnalysisMode } = data; + const [analyzedReagent, setAnalyzedReagent] = useState(); + return ( - + - {reagentAnalysisMode ? : } + {analyzedReagent ? ( + setAnalyzedReagent(undefined)} + /> + ) : ( + + setAnalyzedReagent(chemical) + } + /> + )} ); }; -const ChemMasterContent = (props) => { +const ChemMasterContent = (props: { + analyze: (chemical: AnalyzableReagent) => void; +}) => { const { act, data } = useBackend(); const { isPrinting, printingProgress, printingTotal, - transferMode, - hasBeaker, - beakerCurrentVolume, - beakerMaxVolume, - beakerContents, - bufferContents, - bufferCurrentVolume, - bufferMaxVolume, + maxPrintable, + isTransfering, + beaker, + buffer, categories, selectedContainerVolume, - hasContainerSuggestion, - doSuggestContainer, - suggestedContainer, } = data; - const [itemCount, setItemCount] = useState(1); + const [itemCount, setItemCount] = useState(1); + const [showPreferredContainer, setShowPreferredContainer] = + useState(false); + const buffer_contents = buffer.contents; return (
- - {` / ${beakerMaxVolume} units`} + + {` / ${beaker.maxVolume} units`} - ) } > - {!hasBeaker && ( + {!beaker ? ( No beaker loaded. - )} - {!!hasBeaker && beakerCurrentVolume === 0 && ( + ) : beaker.currentVolume === 0 ? ( Beaker is empty. + ) : ( + + {beaker.contents.map((chemical) => ( + + ))} +
)} - - {beakerContents.map((chemical) => ( - - ))} -
- - {` / ${bufferMaxVolume} units`} + + {` / ${buffer.maxVolume} units`} } > - {bufferContents.length === 0 && ( + {buffer_contents.length === 0 ? ( Buffer is empty. + ) : ( + + {buffer_contents.map((chemical) => ( + + ))} +
)} - - {bufferContents.map((chemical) => ( - - ))} -
{!isPrinting && (
+ + setShowPreferredContainer((currentValue) => !currentValue) + } + > + Suggest + { setItemCount(value); }} @@ -200,51 +208,36 @@ const ChemMasterContent = (props) => { Math.round( Math.min( selectedContainerVolume, - bufferCurrentVolume / itemCount, + buffer.currentVolume / itemCount, ) * 100, ) / 100 } u. each`} - ) : ( -
@@ -256,9 +249,10 @@ const ChemMasterContent = (props) => { } > { ); }; -const ReagentEntry = (props) => { +type ReagentProps = { + chemical: AnalyzableReagent; + transferTo: string; + analyze: (chemical: AnalyzableReagent) => void; +}; + +const ReagentEntry = (props: ReagentProps) => { const { data, act } = useBackend(); - const { chemical, transferTo } = props; + const { chemical, transferTo, analyze } = props; const { isPrinting } = data; return ( @@ -295,7 +295,6 @@ const ReagentEntry = (props) => { } > @@ -438,7 +454,6 @@ const AnalysisResults = (props) => {
{pH} - {state} {color} diff --git a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx index 6c2d3649325..3483c3ceede 100644 --- a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx +++ b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx @@ -8,7 +8,7 @@ import { Section, } from '../../components'; -type BeakerReagent = { +export type BeakerReagent = { name: string; volume: number; };