From 3086f4c862fc68d3a10da00479580d48f67bc17f Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Thu, 28 Mar 2024 01:24:17 -0400 Subject: [PATCH 1/2] [MIRROR] General maintenance for reagent grinder (#1642) General maintenance for reagent grinder Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- .../SpaceRuins/nova/port_tarkon.dmm | 4 +- _maps/shuttles/pirate_ex_interdyne.dmm | 4 +- code/__DEFINES/traits/declarations.dm | 3 - code/_globalvars/traits/_traits.dm | 3 - .../machines/machine_circuitboards.dm | 6 +- .../chemistry/machinery/reagentgrinder.dm | 681 +++++++++++------- icons/obj/machines/kitchen.dmi | Bin 16326 -> 15911 bytes 7 files changed, 418 insertions(+), 283 deletions(-) diff --git a/_maps/RandomRuins/SpaceRuins/nova/port_tarkon.dmm b/_maps/RandomRuins/SpaceRuins/nova/port_tarkon.dmm index be2c41b1eb8..fed8e5b80ca 100644 --- a/_maps/RandomRuins/SpaceRuins/nova/port_tarkon.dmm +++ b/_maps/RandomRuins/SpaceRuins/nova/port_tarkon.dmm @@ -4396,7 +4396,7 @@ /area/ruin/space/has_grav/port_tarkon/secoff) "DG" = ( /obj/structure/table/reinforced, -/obj/machinery/reagentgrinder/constructed, +/obj/machinery/reagentgrinder, /obj/machinery/light/small/directional/west, /turf/open/floor/iron/cafeteria, /area/ruin/space/has_grav/port_tarkon/kitchen) @@ -7204,7 +7204,7 @@ dir = 1 }, /obj/structure/table/reinforced, -/obj/machinery/reagentgrinder/constructed, +/obj/machinery/reagentgrinder, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/port_tarkon/developement) "Wy" = ( diff --git a/_maps/shuttles/pirate_ex_interdyne.dmm b/_maps/shuttles/pirate_ex_interdyne.dmm index c84250b13d9..94fdb5be35e 100644 --- a/_maps/shuttles/pirate_ex_interdyne.dmm +++ b/_maps/shuttles/pirate_ex_interdyne.dmm @@ -67,7 +67,7 @@ dir = 8 }, /obj/structure/table/reinforced/plastitaniumglass, -/obj/machinery/reagentgrinder/constructed, +/obj/machinery/reagentgrinder, /turf/open/floor/iron/dark, /area/shuttle/pirate) "al" = ( @@ -625,7 +625,7 @@ /obj/item/stack/sheet/mineral/plasma, /obj/item/stack/sheet/mineral/plasma, /obj/item/stack/sheet/mineral/plasma, -/obj/machinery/reagentgrinder/constructed, +/obj/machinery/reagentgrinder, /obj/item/storage/box/monkeycubes/syndicate, /obj/item/storage/box/monkeycubes/syndicate, /obj/item/reagent_containers/cup/bottle, diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index bfec16eb732..19d9a6ac045 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -803,9 +803,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_VENTCRAWLER_ALWAYS "ventcrawler_always" #define TRAIT_VENTCRAWLER_NUDE "ventcrawler_nude" -/// Minor trait used for beakers, or beaker-ishes. [/obj/item/reagent_containers], to show that they've been used in a reagent grinder. -#define TRAIT_MAY_CONTAIN_BLENDED_DUST "may_contain_blended_dust" - /// Trait put on [/mob/living/carbon/human]. If that mob has a crystal core, also known as an ethereal heart, it will not try to revive them if the mob dies. #define TRAIT_CANNOT_CRYSTALIZE "cannot_crystalize" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index f002703942a..c3d5751188e 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -582,9 +582,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( /obj/item/organ/internal/lungs = list( "TRAIT_SPACEBREATHING" = TRAIT_SPACEBREATHING, ), - /obj/item/reagent_containers = list( - "TRAIT_MAY_CONTAIN_BLENDED_DUST" = TRAIT_MAY_CONTAIN_BLENDED_DUST, - ), /obj/machinery/modular_computer = list( "TRAIT_MODPC_INTERACTING_WITH_FRAME" = TRAIT_MODPC_INTERACTING_WITH_FRAME, ), diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 1480ac23c5a..1f8b01f41da 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -525,9 +525,11 @@ /obj/item/circuitboard/machine/reagentgrinder name = "All-In-One Grinder" greyscale_colors = CIRCUIT_COLOR_GENERIC - build_path = /obj/machinery/reagentgrinder/constructed + build_path = /obj/machinery/reagentgrinder req_components = list( - /datum/stock_part/servo = 1) + /datum/stock_part/servo = 1, + /datum/stock_part/matter_bin = 1, + ) needs_anchored = FALSE /obj/item/circuitboard/machine/smartfridge diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 358ac29719c..f7e48a6fbfe 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -3,57 +3,41 @@ name = "\improper All-In-One Grinder" desc = "From BlenderTech. Will It Blend? Let's test it out!" icon = 'icons/obj/machines/kitchen.dmi' - icon_state = "juicer1" + icon_state = "juicer" base_icon_state = "juicer" - layer = BELOW_OBJ_LAYER + active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.0025 circuit = /obj/item/circuitboard/machine/reagentgrinder pass_flags = PASSTABLE resistance_flags = ACID_PROOF + interaction_flags_machine = parent_type::interaction_flags_machine | INTERACT_MACHINE_OFFLINE anchored_tabletop_offset = 8 + + /// The maximum weight of items this grinder can hold + var/maximum_weight = WEIGHT_CLASS_BULKY + /// Is the grinder currently performing work var/operating = FALSE + /// The beaker to hold the final products var/obj/item/reagent_containers/beaker = null - var/limit = 10 + /// How fast operations take place var/speed = 1 - var/list/holdingitems - - var/static/radial_examine = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_examine") - var/static/radial_eject = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_eject") - var/static/radial_grind = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_grind") - var/static/radial_juice = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_juice") - var/static/radial_mix = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_mix") /obj/machinery/reagentgrinder/Initialize(mapload) . = ..() - holdingitems = list() - beaker = new /obj/item/reagent_containers/cup/beaker/large(src) - warn_of_dust() - RegisterSignal(src, COMSIG_STORAGE_DUMP_CONTENT, PROC_REF(on_storage_dump)) -/// Add a description to the current beaker warning of blended dust, if it doesn't already have that warning. -/obj/machinery/reagentgrinder/proc/warn_of_dust() - if(HAS_TRAIT(beaker, TRAIT_MAY_CONTAIN_BLENDED_DUST)) - return - - beaker.desc += " May contain blended dust. Don't breathe this!" - ADD_TRAIT(beaker, TRAIT_MAY_CONTAIN_BLENDED_DUST, TRAIT_GENERIC) + if(mapload) + beaker = new /obj/item/reagent_containers/cup/beaker/large(src) -/obj/machinery/reagentgrinder/constructed/Initialize(mapload) - . = ..() - holdingitems = list() - QDEL_NULL(beaker) - update_appearance() + register_context() + update_appearance(UPDATE_OVERLAYS) -/obj/machinery/reagentgrinder/on_deconstruction(disassmbled) - drop_all_items() - beaker?.forceMove(drop_location()) - beaker = null + RegisterSignal(src, COMSIG_STORAGE_DUMP_CONTENT, PROC_REF(on_storage_dump)) /obj/machinery/reagentgrinder/Destroy() QDEL_NULL(beaker) return ..() /obj/machinery/reagentgrinder/contents_explosion(severity, target) - if(!beaker) + if(!QDELETED(beaker)) return switch(severity) @@ -64,11 +48,36 @@ if(EXPLODE_LIGHT) SSexplosions.low_mov_atom += beaker -/obj/machinery/reagentgrinder/RefreshParts() - . = ..() - speed = 1 - for(var/datum/stock_part/servo/servo in component_parts) - speed = servo.tier +/obj/machinery/reagentgrinder/add_context(atom/source, list/context, obj/item/held_item, mob/user) + var/result = NONE + if(isnull(held_item)) + if(!QDELETED(beaker) && !operating) + context[SCREENTIP_CONTEXT_RMB] = "Remove beaker" + result = CONTEXTUAL_SCREENTIP_SET + return result + + if(is_reagent_container(held_item) && held_item.is_open_container() && !operating) + if(QDELETED(beaker)) + context[SCREENTIP_CONTEXT_LMB] = "Insert beaker" + else + context[SCREENTIP_CONTEXT_LMB] = "Replace 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_CROWBAR && panel_open) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Una" : "A"]nchor" + return CONTEXTUAL_SCREENTIP_SET + + if(istype(held_item, /obj/item/storage/bag)) + context[SCREENTIP_CONTEXT_LMB] = "Transfer contents" + else + context[SCREENTIP_CONTEXT_LMB] = "Insert item" + return CONTEXTUAL_SCREENTIP_SET /obj/machinery/reagentgrinder/examine(mob/user) . = ..() @@ -76,240 +85,341 @@ . += span_warning("You're too far away to examine [src]'s contents and display!") return - if(operating) - . += span_warning("\The [src] is operating.") - return + var/total_weight = 0 + var/list/obj/item/to_process = list() + for(var/obj/item/target in src) + if((target in component_parts) || target == beaker) + continue + to_process["[target.name]"] += 1 + total_weight += target.w_class + if(to_process.len) + . += span_notice("Currently holding.") + for(var/target_name as anything in to_process) + . += span_notice("[to_process[target_name]] [target_name]") + . += span_notice("Filled to [round((total_weight / maximum_weight) * 100)]% capacity.") + + if(!QDELETED(beaker)) + . += span_notice("A beaker of [beaker.reagents.maximum_volume]u capacity is present.") + . += span_notice("[EXAMINE_HINT("Right click")] with empty hand to remove beaker.") + else + . += span_warning("It's missing a beaker.") - if(beaker || length(holdingitems)) - . += span_notice("\The [src] contains:") - if(beaker) - . += span_notice("- \A [beaker].") - for(var/i in holdingitems) - var/obj/item/O = i - . += span_notice("- \A [O.name].") - - if(!(machine_stat & (NOPOWER|BROKEN))) - . += "[span_notice("The status display reads:")]\n"+\ - span_notice("- Grinding reagents at [speed*100]%.") - if(beaker) - for(var/datum/reagent/R in beaker.reagents.reagent_list) - . += span_notice("- [R.volume] units of [R.name].") + . += span_notice("You can drag a storage item to dump its contents in the grinder.") + if(anchored) + . += span_notice("It can be [EXAMINE_HINT("wrenched")] loose.") + else + . += span_warning("Needs to be [EXAMINE_HINT("wrenched")] in place to work.") + . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "closed" : "open"].") + if(panel_open) + . += span_notice("It can be [EXAMINE_HINT("pried")] apart.") -/obj/machinery/reagentgrinder/attack_hand_secondary(mob/user, list/modifiers) +/obj/machinery/reagentgrinder/update_overlays() . = ..() - if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) - return - if(operating || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) - return - eject(user) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/machinery/reagentgrinder/attack_robot_secondary(mob/user, list/modifiers) - return attack_hand_secondary(user, modifiers) + if(!QDELETED(beaker)) + . += "[base_icon_state]-beaker" -/obj/machinery/reagentgrinder/attack_ai_secondary(mob/user, list/modifiers) - return attack_hand_secondary(user, modifiers) + if(anchored && !panel_open && is_operational) + . += "[base_icon_state]-on" /obj/machinery/reagentgrinder/Exited(atom/movable/gone, direction) . = ..() if(gone == beaker) beaker = null - update_appearance() - if(holdingitems[gone]) - holdingitems -= gone - -/obj/machinery/reagentgrinder/proc/drop_all_items() - for(var/i in holdingitems) - var/atom/movable/AM = i - AM.forceMove(drop_location()) - holdingitems = list() - -/obj/machinery/reagentgrinder/update_icon_state() - icon_state = "[base_icon_state][beaker ? 1 : 0]" - return ..() + update_appearance(UPDATE_OVERLAYS) +/obj/machinery/reagentgrinder/RefreshParts() + . = ..() + + for(var/datum/stock_part/part in component_parts) + if(istype(part, /datum/stock_part/servo)) + speed = part.tier + else if(istype(part, /datum/stock_part/matter_bin)) + maximum_weight = WEIGHT_CLASS_GIGANTIC * part.tier +/** + * Inserts, removes or replaces the beaker present + * Arguments + * + * * mob/living/user - the player performing the action + * * obj/item/reagent_containers/new_beaker - the new beaker to replace the old, null to do nothing + */ /obj/machinery/reagentgrinder/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker) - if(!user) - return FALSE - if(beaker) + PRIVATE_PROC(TRUE) + + if(!QDELETED(beaker)) try_put_in_hand(beaker, user) - beaker = null - if(new_beaker) + + if(!QDELETED(new_beaker)) + if(!user.transferItemToLoc(new_beaker, src)) + return beaker = new_beaker - update_appearance() - return TRUE + + update_appearance(UPDATE_OVERLAYS) + +/** + * Transfer this item or items inside if its a bag into the grinder + * Arguments + * + * * mob/user - the player who is inserting these items + * * list/obj/item/to_add - list of items to add + */ +/obj/machinery/reagentgrinder/proc/load_items(mob/user, list/obj/item/to_add) + PRIVATE_PROC(TRUE) + + //surface level checks to filter out items that can be grinded/juice + var/list/obj/item/filtered_list = list() + for(var/obj/item/ingredient as anything in to_add) + //what are we trying to grind exactly? + if((ingredient.item_flags & ABSTRACT) || (ingredient.flags_1 & HOLOGRAM_1)) + continue + + //Nothing would come from grinding or juicing + if(!length(ingredient.grind_results) && !ingredient.juice_typepath) + to_chat(user, span_warning("You cannot grind/juice [ingredient] into reagents!")) + continue + + //Error messages should be in the objects' definitions + if(!ingredient.grind_requirements(src)) + continue + + filtered_list += ingredient + if(!filtered_list.len) + return FALSE + + //find total weight of all items already in grinder + var/total_weight + for(var/obj/item/to_process in src) + if((to_process in component_parts) || to_process == beaker) + continue + total_weight += to_process.w_class + + //Now transfer the items 1 at a time while ensuring we don't go above the maximum allowed weight + var/items_transfered = 0 + for(var/obj/item/weapon as anything in filtered_list) + if(weapon.w_class + total_weight > maximum_weight) + to_chat(user, span_warning("[weapon] is too big to fit into [src].")) + continue + weapon.forceMove(src) + total_weight += weapon.w_class + items_transfered += 1 + to_chat(user, span_notice("[weapon] was loaded into [src].")) + + return items_transfered + +/obj/machinery/reagentgrinder/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)) + return ..() + + //add the beaker + if (is_reagent_container(tool) && tool.is_open_container()) + replace_beaker(user, tool) + to_chat(user, span_notice("You add [tool] to [src].")) + return ITEM_INTERACT_SUCCESS + + //add items from bag + else if(istype(tool, /obj/item/storage/bag)) + var/list/obj/item/to_add = list() + //list of acceptable items from the bag + var/static/list/accepted_items = list( + /obj/item/grown, + /obj/item/food/grown, + /obj/item/food/honeycomb, + ) + + //add to list of items to check for + for(var/obj/item/ingredient in tool) + if(!is_type_in_list(ingredient, accepted_items)) + continue + to_add += ingredient + + //add the items + var/items_added = load_items(user, to_add) + if(!items_added) + to_chat(user, span_warning("No items were added.")) + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("[items_added] items were added from [tool] to [src].")) + return ITEM_INTERACT_SUCCESS + + //add item directly + else if(tool.grind_results || tool.juice_typepath) + if(tool.atom_storage) //anything that has internal storage would be too much recursion for us to handle + to_chat(user, span_notice("Drag this item onto [src] to dump its contents.")) + return ITEM_INTERACT_BLOCKING + + //add the items + if(!load_items(user, list(tool))) + return ITEM_INTERACT_BLOCKING + to_chat(user, span_notice("[tool] was added to [src].")) + return ITEM_INTERACT_SUCCESS + + //ask player to drag stuff into grinder + else if(tool.atom_storage) + to_chat(user, span_warning("You must drag & dump contents of [tool] into [src].")) + return ITEM_INTERACT_BLOCKING + + return ..() /obj/machinery/reagentgrinder/wrench_act(mob/living/user, obj/item/tool) - . = ..() - default_unfasten_wrench(user, tool) - return ITEM_INTERACT_SUCCESS + if(user.combat_mode) + return NONE -/obj/machinery/reagentgrinder/screwdriver_act(mob/living/user, obj/item/tool) - . = ITEM_INTERACT_SUCCESS - if(!beaker && !length(holdingitems)) - return default_deconstruction_screwdriver(user, icon_state, icon_state, tool) + var/tool_result = ITEM_INTERACT_BLOCKING + if(operating) + balloon_alert(user, "still operating!") + return tool_result -/obj/machinery/reagentgrinder/crowbar_act(mob/living/user, obj/item/tool) - return default_deconstruction_crowbar(tool) + if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN) + update_appearance(UPDATE_OVERLAYS) + tool_result = ITEM_INTERACT_SUCCESS + return tool_result -/obj/machinery/reagentgrinder/attackby(obj/item/weapon, mob/living/user, params) - if(panel_open) //Can't insert objects when its screwed open - return TRUE +/obj/machinery/reagentgrinder/screwdriver_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE - if(!weapon.grind_requirements(src)) //Error messages should be in the objects' definitions - return + var/tool_result = ITEM_INTERACT_BLOCKING + if(operating) + balloon_alert(user, "still operating!") + return tool_result - if (is_reagent_container(weapon) && !(weapon.item_flags & ABSTRACT) && weapon.is_open_container()) - var/obj/item/reagent_containers/container = weapon - . = TRUE //no afterattack - if(!user.transferItemToLoc(container, src)) - return - replace_beaker(user, container) - to_chat(user, span_notice("You add [container] to [src].")) - update_appearance() - return TRUE //no afterattack - - if(holdingitems.len >= limit) - to_chat(user, span_warning("[src] is filled to capacity!")) - return TRUE - - //Fill machine with a bag! - if(istype(weapon, /obj/item/storage/bag)) - if(!weapon.contents.len) - to_chat(user, span_notice("[weapon] is empty!")) - return TRUE - - var/list/inserted = list() - if(weapon.atom_storage.remove_type(/obj/item/food/grown, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) - for(var/i in inserted) - holdingitems[i] = TRUE - inserted = list() - if(weapon.atom_storage.remove_type(/obj/item/food/honeycomb, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) - for(var/i in inserted) - holdingitems[i] = TRUE - - if(!weapon.contents.len) - to_chat(user, span_notice("You empty [weapon] into [src].")) - else - to_chat(user, span_notice("You fill [src] to the brim.")) - return TRUE + if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool)) + update_appearance(UPDATE_OVERLAYS) + tool_result = ITEM_INTERACT_SUCCESS + return tool_result - if(!weapon.grind_results && !weapon.juice_typepath) - if(user.combat_mode) - return ..() - else - to_chat(user, span_warning("You cannot grind/juice [weapon] into reagents!")) - return TRUE +/obj/machinery/reagentgrinder/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE - if(user.transferItemToLoc(weapon, src)) - to_chat(user, span_notice("You add [weapon] to [src].")) - holdingitems[weapon] = TRUE - return FALSE + var/tool_result = ITEM_INTERACT_BLOCKING + if(operating) + balloon_alert(user, "still operating!") + return tool_result + + if(default_deconstruction_crowbar(tool)) + tool_result = ITEM_INTERACT_SUCCESS + return tool_result /obj/machinery/reagentgrinder/proc/on_storage_dump(datum/source, datum/storage/storage, mob/user) SIGNAL_HANDLER + var/list/obj/item/contents_to_dump = list() for(var/obj/item/to_dump in storage.real_location) - if(holdingitems.len >= limit) - break - - if(!to_dump.grind_results && !to_dump.juice_typepath) + if(to_dump.atom_storage) //No recursive handling of contents please continue + contents_to_dump += to_dump - if(!storage.attempt_remove(to_dump, src, silent = TRUE)) - continue + to_chat(user, span_notice("You dumped [load_items(user, contents_to_dump)] items from [storage.parent] into [src].")) - holdingitems[to_dump] = TRUE - - to_chat(user, span_notice("You dump [storage.parent] into [src].")) return STORAGE_DUMP_HANDLED -/obj/machinery/reagentgrinder/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave +/obj/machinery/reagentgrinder/attack_hand_secondary(mob/user, list/modifiers) + . = ..() + if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) + return + if(operating || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) + return + replace_beaker(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/machinery/reagentgrinder/attack_robot_secondary(mob/user, list/modifiers) + return attack_hand_secondary(user, modifiers) + +/obj/machinery/reagentgrinder/attack_ai_secondary(mob/user, list/modifiers) + return attack_hand_secondary(user, modifiers) + +/obj/machinery/reagentgrinder/ui_interact(mob/user) . = ..() - if(operating || !user.can_perform_action(src, ALLOW_SILICON_REACH)) + //some interaction sanity checks + if(!anchored || operating || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) return + var/static/radial_eject = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_eject") + var/static/radial_mix = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_mix") + //create list of options available var/list/options = list() + //actions to be performed on the items stored inside + for(var/obj/item/to_process in src) + if((to_process in component_parts) || to_process == beaker) + continue - if(beaker || length(holdingitems)) - options["eject"] = radial_eject + if(!QDELETED(beaker) && !beaker.reagents.holder_full() && is_operational && anchored) + var/static/radial_grind = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_grind") + options["grind"] = radial_grind + var/static/radial_juice = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_juice") + options["juice"] = radial_juice + + options["eject"] = radial_eject + break + //eject action if we have a beaker + if(!QDELETED(beaker)) + options["eject"] = radial_eject + //mix reagents present inside + if(beaker?.reagents.total_volume && is_operational && anchored) + options["mix"] = radial_mix + //examine action if Ai is trying to see whats up if(HAS_AI_ACCESS(user)) if(machine_stat & NOPOWER) return + var/static/radial_examine = image(icon = 'icons/hud/radial.dmi', icon_state = "radial_examine") options["examine"] = radial_examine - // if there is no power or it's broken, the procs will fail but the buttons will still show - if(length(holdingitems)) - options["grind"] = radial_grind - options["juice"] = radial_juice - else if(beaker?.reagents.total_volume) - options["mix"] = radial_mix - - var/choice - - if(length(options) < 1) - return - if(length(options) == 1) - for(var/key in options) - choice = key - else - choice = show_radial_menu(user, src, options, require_near = !HAS_SILICON_ACCESS(user)) - - // post choice verification - if(operating || (HAS_AI_ACCESS(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH)) + //display choices & perform action + var/choice = show_radial_menu( + user, + src, + options, + custom_check = CALLBACK(src, PROC_REF(check_interactable), user), + require_near = !HAS_SILICON_ACCESS(user), + ) + if(!choice) return - switch(choice) if("eject") - eject(user) - if("grind") - grind(user) - if("juice") - juice(user) + replace_beaker(user) + dump_inventory_contents() + if("grind", "juice") + operate_for(60 DECISECONDS, choice == "juice", user) if("mix") - mix(user) + mix(50 DECISECONDS, user) if("examine") - examine(user) - -/obj/machinery/reagentgrinder/proc/eject(mob/user) - drop_all_items() - if(beaker) - replace_beaker(user) - -/obj/machinery/reagentgrinder/proc/remove_object(obj/item/weapon) - holdingitems -= weapon - qdel(weapon) - -/obj/machinery/reagentgrinder/proc/start_shaking() - var/static/list/transforms - if(!transforms) - var/matrix/M1 = matrix() - var/matrix/M2 = matrix() - var/matrix/M3 = matrix() - var/matrix/M4 = matrix() - M1.Translate(-1, 0) - M2.Translate(0, 1) - M3.Translate(1, 0) - M4.Translate(0, -1) - transforms = list(M1, M2, M3, M4) - animate(src, transform=transforms[1], time=0.4, loop=-1) - animate(transform=transforms[2], time=0.2) - animate(transform=transforms[3], time=0.4) - animate(transform=transforms[4], time=0.6) - -/obj/machinery/reagentgrinder/proc/shake_for(duration) - start_shaking() //start shaking - addtimer(CALLBACK(src, PROC_REF(stop_shaking)), duration) - -/obj/machinery/reagentgrinder/proc/stop_shaking() - update_appearance() - animate(src, transform = matrix()) - -/obj/machinery/reagentgrinder/proc/operate_for(time, silent = FALSE, juicing = FALSE) - shake_for(time / speed) + to_chat(user, examine_block("[examine(user)]")) + +/** + * Checks if the radial menu can interact with this machine + * Arguments + * + * * mob/user - the player interacting with this machine + */ +/obj/machinery/reagentgrinder/proc/check_interactable(mob/user) + PRIVATE_PROC(TRUE) + + if(!can_interact(user)) + return FALSE + + if(!anchored || operating || !user.can_perform_action(src, ALLOW_SILICON_REACH)) + return FALSE + + return TRUE + +/** + * Grinds/Juices all contents inside the grinder + * Arguments + * + * * time - the duration in deciseconds to perform the operation + * * juicing - FALSE to grind, TRUE to juice + * * mob/user - the player who initiated this process + */ +/obj/machinery/reagentgrinder/proc/operate_for(time, juicing = FALSE, mob/user) + PRIVATE_PROC(TRUE) + + var/duration = time / speed + + Shake(duration = duration) operating = TRUE +<<<<<<< HEAD if(!silent) if(!juicing) playsound(src, 'sound/machines/blender.ogg', 50, TRUE) @@ -317,71 +427,94 @@ playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) use_power(active_power_usage * time * 0.1) // .1 needed here to convert time (in deciseconds) to seconds such that watts * seconds = joules addtimer(CALLBACK(src, PROC_REF(stop_operating)), time / speed) +======= + if(!juicing) + playsound(src, 'sound/machines/blender.ogg', 50, TRUE) + else + playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) +>>>>>>> 7356d10bc6d ([MIRROR] General maintenance for reagent grinder (#1642)) -/obj/machinery/reagentgrinder/proc/stop_operating() - operating = FALSE - -/obj/machinery/reagentgrinder/proc/juice(mob/user) - power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) - return - operate_for(50, juicing = TRUE) - for(var/obj/item/ingredient in holdingitems) + var/total_weight + for(var/obj/item/weapon in src) + if((weapon in component_parts) || weapon == beaker) + continue if(beaker.reagents.holder_full()) break - if(ingredient.flags_1 & HOLOGRAM_1) - to_chat(user, span_notice("You try to juice [ingredient], but it fades away!")) - qdel(ingredient) - continue + //recursively process everything inside this atom + var/item_processed = FALSE + var/item_weight = weapon.w_class + for(var/obj/item/ingredient as anything in weapon.get_all_contents_type(/obj/item)) + if(beaker.reagents.holder_full()) + break + + if(juicing) + if(ingredient.juice_typepath) + if(!ingredient.juice(beaker.reagents, user)) + to_chat(user, span_danger("[src] shorts out as it tries to juice up [ingredient], and transfers it back to storage.")) + continue + item_processed = TRUE + else if(ingredient.grind_results) + if(!ingredient.grind(beaker.reagents, user)) + if(isstack(ingredient)) + to_chat(user, span_notice("[src] attempts to grind as many pieces of [ingredient] as possible.")) + else + to_chat(user, span_danger("[src] shorts out as it tries to grind up [ingredient], and transfers it back to storage.")) + continue + item_processed = TRUE + + //happens only for stacks where some of the sheets were grinded so we roughly compute the weight grinded + if(item_weight != weapon.w_class) + total_weight += item_weight - weapon.w_class + else + total_weight += item_weight - if(ingredient.juice_typepath) - juice_item(ingredient, user) + //delete only if operation was successfull for atleast 1 item(also delete atoms for whom only some of its contents were processed as they are non functional now) + if(item_processed) + qdel(weapon) -/obj/machinery/reagentgrinder/proc/juice_item(obj/item/ingredient, mob/user) //Juicing results can be found in respective object definitions - if(!ingredient.juice(beaker.reagents, user)) - to_chat(user, span_danger("[src] shorts out as it tries to juice up [ingredient], and transfers it back to storage.")) - return - remove_object(ingredient) + //use power according to the total weight of items grinded + use_energy((active_power_usage * (duration / 1 SECONDS)) * (total_weight / maximum_weight)) -/obj/machinery/reagentgrinder/proc/grind(mob/user) - power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) - return - operate_for(60) - warn_of_dust() // don't breathe this. - for(var/obj/item/ingredient in holdingitems) - if(beaker.reagents.holder_full()) - break + addtimer(CALLBACK(src, PROC_REF(stop_operating)), duration) - if(ingredient.flags_1 & HOLOGRAM_1) - to_chat(user, span_notice("You try to grind [ingredient], but it fades away!")) - qdel(ingredient) - continue +///Reset the operating status of the machine +/obj/machinery/reagentgrinder/proc/stop_operating() + PRIVATE_PROC(TRUE) + + operating = FALSE - if(ingredient.grind_results) - grind_item(ingredient, user) +/** + * Mixes the reagents inside the beaker + * Arguments + * + * * time - the length of time in deciseconds to operate + * * mob/user - the player who started the mixing process + */ +/obj/machinery/reagentgrinder/proc/mix(time, mob/user) + PRIVATE_PROC(TRUE) -/obj/machinery/reagentgrinder/proc/grind_item(obj/item/ingredient, mob/user) //Grind results can be found in respective object definitions - if(!ingredient.grind(beaker.reagents, user)) - if(isstack(ingredient)) - to_chat(user, span_notice("[src] attempts to grind as many pieces of [ingredient] as possible.")) - else - to_chat(user, span_danger("[src] shorts out as it tries to grind up [ingredient], and transfers it back to storage.")) - return - remove_object(ingredient) + var/duration = time / speed -/obj/machinery/reagentgrinder/proc/mix(mob/user) - //For butter and other things that would change upon shaking or mixing - power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN)) - return - operate_for(50, juicing = TRUE) - addtimer(CALLBACK(src, PROC_REF(mix_complete)), 50 / speed) + Shake(duration = duration) + operating = TRUE + playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) + + addtimer(CALLBACK(src, PROC_REF(mix_complete), duration), duration) -/obj/machinery/reagentgrinder/proc/mix_complete() - if(beaker?.reagents.total_volume <= 0) +/** + * Mix the reagents + * Arguments + * + * * duration - the time spent in mixing + */ +/obj/machinery/reagentgrinder/proc/mix_complete(duration) + PRIVATE_PROC(TRUE) + + if(QDELETED(beaker) || beaker.reagents.total_volume <= 0) + operating = FALSE return + //Recipe to make Butter var/butter_amt = FLOOR(beaker.reagents.get_reagent_amount(/datum/reagent/consumable/milk) / MILK_TO_BUTTER_COEFF, 1) var/purity = beaker.reagents.get_reagent_purity(/datum/reagent/consumable/milk) @@ -389,9 +522,15 @@ for(var/i in 1 to butter_amt) var/obj/item/food/butter/tasty_butter = new(drop_location()) tasty_butter.reagents.set_all_reagents_purity(purity) + //Recipe to make Mayonnaise if (beaker.reagents.has_reagent(/datum/reagent/consumable/eggyolk)) beaker.reagents.convert_reagent(/datum/reagent/consumable/eggyolk, /datum/reagent/consumable/mayonnaise) + //Recipe to make whipped cream if (beaker.reagents.has_reagent(/datum/reagent/consumable/cream)) beaker.reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) + + //power consumed based on the ratio of total reagents mixed + use_energy((active_power_usage * (duration / 1 SECONDS)) * (beaker.reagents.total_volume / beaker.reagents.maximum_volume)) + operating = FALSE diff --git a/icons/obj/machines/kitchen.dmi b/icons/obj/machines/kitchen.dmi index 5bd820e554ad859edb32b196a8013155699c804c..c94afb8d78ad6a8440aa8ef79b477109bbe64574 100644 GIT binary patch literal 15911 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 P4tgu6DqAZ3A@KhIn6bjB literal 16326 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 CmZk#$ From 9de6fbce36fcbc418b3d00bb495d19b4d2d84db5 Mon Sep 17 00:00:00 2001 From: Iajret Date: Thu, 28 Mar 2024 15:35:37 +0300 Subject: [PATCH 2/2] merge conflict --- .../reagents/chemistry/machinery/reagentgrinder.dm | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 2271ea98464..708be786404 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -419,20 +419,10 @@ Shake(duration = duration) operating = TRUE -<<<<<<< HEAD - if(!silent) - if(!juicing) - playsound(src, 'sound/machines/blender.ogg', 50, TRUE) - else - playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) - use_energy(active_power_usage * time / (1 SECONDS)) - addtimer(CALLBACK(src, PROC_REF(stop_operating)), time / speed) -======= if(!juicing) playsound(src, 'sound/machines/blender.ogg', 50, TRUE) else playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) ->>>>>>> 7356d10bc6d ([MIRROR] General maintenance for reagent grinder (#1642)) var/total_weight for(var/obj/item/weapon in src)