From d2c44709377dd88a61ae57f97324971dda286c5a Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:58:17 +0530 Subject: [PATCH] Refactors for grinding & juicing (#87735) ## About The Pull Request - Grinding & juicing are now recursive operations (grind the item & all its contents) not just for reagent grinder but also for mortar pedestal & plumbing grinder so you can get all them juices - Fixes #87719. Plumbing grinder won't destroy slime extracts after grinding - Mortar pedestal now grinds & juices more items since it correctly checks if that object has more reagents to offer - Reagent grinder, plumbing grinder & mortar pedestal now respect `blend_requirements()` so you get consistent behaviour across them ## Changelog :cl: fix: mortar pedestal now grinds & juices items that previously could not be processed fix: plumbing grinder won't destroy slime extracts after grinding refactor: grinding & juicing code has been refactored overall. Please report bugs on github /:cl: --- code/game/objects/items.dm | 71 +++++++++++++++++-- code/game/objects/items/stacks/stack.dm | 6 +- code/modules/hydroponics/grown.dm | 9 +-- .../plumbing/plumbers/grinder_chemical.dm | 36 ++++++---- .../chemistry/machinery/chem_master.dm | 5 ++ .../chemistry/machinery/reagentgrinder.dm | 46 +++++------- .../reagents/reagent_containers/cups/_cup.dm | 20 +++--- 7 files changed, 126 insertions(+), 67 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 28d52d32604..cba2a3ee46c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1027,36 +1027,93 @@ ///Called BEFORE the object is ground up - use this to change grind results based on conditions. Return "-1" to prevent the grinding from occurring /obj/item/proc/on_grind() + PROTECTED_PROC(TRUE) + return SEND_SIGNAL(src, COMSIG_ITEM_ON_GRIND) ///Grind item, adding grind_results to item's reagents and transfering to target_holder if specified -/obj/item/proc/grind(datum/reagents/target_holder, mob/user) +/obj/item/proc/grind(datum/reagents/target_holder, mob/user, atom/movable/grinder = loc) + SHOULD_NOT_OVERRIDE(TRUE) + . = FALSE - if(on_grind() == -1) + if(on_grind() == -1 || target_holder.holder_full()) return + . = grind_atom(target_holder, user) + + //reccursive grinding to get all them juices + var/result + for(var/obj/item/ingredient as anything in get_all_contents_type(/obj/item)) + if(ingredient == src) + continue + + result = ingredient.grind(target_holder, user) + if(!.) + . = result + + if(. && istype(grinder)) + return grinder.blended(src, grinded = TRUE) + +///Subtypes override his proc for custom grinding +/obj/item/proc/grind_atom(datum/reagents/target_holder, mob/user) + PROTECTED_PROC(TRUE) + + . = FALSE if(length(grind_results)) target_holder.add_reagent_list(grind_results) . = TRUE - if(reagents?.total_volume) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + if(reagents?.trans_to(target_holder, reagents.total_volume, transferred_by = user)) . = TRUE ///Called BEFORE the object is ground up - use this to change grind results based on conditions. Return "-1" to prevent the grinding from occurring /obj/item/proc/on_juice() + PROTECTED_PROC(TRUE) + if(!juice_typepath) return -1 + return SEND_SIGNAL(src, COMSIG_ITEM_ON_JUICE) ///Juice item, converting nutriments into juice_typepath and transfering to target_holder if specified -/obj/item/proc/juice(datum/reagents/target_holder, mob/user) +/obj/item/proc/juice(datum/reagents/target_holder, mob/user, atom/movable/juicer = loc) + SHOULD_NOT_OVERRIDE(TRUE) + + . = FALSE if(on_juice() == -1 || !reagents?.total_volume) - return FALSE + return + + . = juice_atom(target_holder, user) + + //reccursive juicing to get all them juices + var/result + for(var/obj/item/ingredient as anything in get_all_contents_type(/obj/item)) + if(ingredient == src) + continue + + result = ingredient.juice(target_holder, user) + if(!.) + . = result + + if(. && istype(juicer)) + return juicer.blended(src, grinded = FALSE) + +///Subtypes override his proc for custom juicing +/obj/item/proc/juice_atom(datum/reagents/target_holder, mob/user) + PROTECTED_PROC(TRUE) + + . = FALSE if(ispath(juice_typepath)) reagents.convert_reagent(/datum/reagent/consumable/nutriment, juice_typepath, include_source_subtypes = FALSE) reagents.convert_reagent(/datum/reagent/consumable/nutriment/vitamin, juice_typepath, include_source_subtypes = FALSE) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + . = TRUE + + if(!QDELETED(target_holder)) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + +///What should The atom that blended an object do with it afterwards? Default behaviour is to delete it +/atom/movable/proc/blended(obj/item/blended_item, grinded) + qdel(blended_item) return TRUE diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 18891ebdd93..fd1529eb330 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -135,14 +135,10 @@ return return TRUE -/obj/item/stack/grind(datum/reagents/target_holder, mob/user) +/obj/item/stack/grind_atom(datum/reagents/target_holder, mob/user) var/current_amount = get_amount() if(current_amount <= 0 || QDELETED(src)) //just to get rid of this 0 amount/deleted stack we return success return TRUE - if(on_grind() == -1) - return FALSE - if(isnull(target_holder)) - return TRUE if(reagents) reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 6edbfd382f9..b5527782011 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -139,10 +139,7 @@ reagents.add_reagent(/datum/reagent/consumable/ethanol/fruit_wine, reagent.volume, data, added_purity = reagent_purity) reagents.del_reagent(reagent.type) -/obj/item/food/grown/grind(datum/reagents/target_holder, mob/user) - if(on_grind() == -1) - return FALSE - +/obj/item/food/grown/grind_atom(datum/reagents/target_holder, mob/user) var/grind_results_num = LAZYLEN(grind_results) if(grind_results_num) var/average_purity = reagents.get_average_purity() @@ -152,9 +149,7 @@ for(var/reagent in grind_results) reagents.add_reagent(reagent, single_reagent_amount, added_purity = average_purity) - if(reagents && target_holder) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) - return TRUE + return reagents?.trans_to(target_holder, reagents.total_volume, transferred_by = user) #undef BITE_SIZE_POTENCY_MULTIPLIER #undef BITE_SIZE_VOLUME_MULTIPLIER diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index bd0a69e6d5e..c631e26def6 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -74,7 +74,7 @@ to_chat(user, span_notice("You dump items from [tool] into the grinder.")) for(var/obj/item/obj_item in tool.contents) - grind(obj_item) + blend(obj_item) return ITEM_INTERACT_SUCCESS else if(!tool.tool_behaviour) var/action = "[grinding ? "grind" : "juice"]" @@ -83,7 +83,7 @@ return ITEM_INTERACT_BLOCKING to_chat(user, span_notice("You attempt to [action] [tool].")) - grind(tool) + blend(tool) return ITEM_INTERACT_SUCCESS /obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/mover, border_dir) @@ -97,33 +97,45 @@ /obj/machinery/plumbing/grinder_chemical/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - INVOKE_ASYNC(src, PROC_REF(grind), AM) + if(!isitem(AM)) + return + + INVOKE_ASYNC(src, PROC_REF(blend), AM) + + +/obj/machinery/plumbing/grinder_chemical/blended(obj/item/blended_item, grinded) + //don't delete slime extracts + if(istype(blended_item, /obj/item/slime_extract)) + //so you can't regrind them for extra stuff + blended_item.grind_results = null + + blended_item.forceMove(drop_location()) + + return TRUE + + return ..() /** * Grinds/Juices the atom * Arguments * * [AM][atom] - the atom to grind or juice */ -/obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM) +/obj/machinery/plumbing/grinder_chemical/proc/blend(obj/item/I) PRIVATE_PROC(TRUE) if(!is_operational || !anchored) return if(reagents.holder_full()) return - if(!isitem(AM)) - return - var/obj/item/I = AM if((I.item_flags & ABSTRACT) || (I.flags_1 & HOLOGRAM_1)) return + if(!I.blend_requirements(src)) + return - var/result if(!grinding) - result = I.juice(reagents, usr) + I.juice(reagents, usr, src) else if(length(I.grind_results) || I.reagents?.total_volume) - result = I.grind(reagents, usr) + I.grind(reagents, usr, src) use_energy(active_power_usage) - if(result) - qdel(I) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 2aac6a457ab..bcb6cac2f18 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -454,6 +454,11 @@ //are we printing a valid container var/container_found = FALSE for(var/category in printable_containers) + //container found in previous iteration + if(container_found) + break + + //find for matching typepath for(var/obj/item/reagent_containers/container as anything in printable_containers[category]) if(target == container) container_found = TRUE diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 141fb7c4e6f..7716784e4b4 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -434,43 +434,33 @@ playsound(src, 'sound/machines/juicer.ogg', 20, TRUE) var/total_weight - for(var/obj/item/weapon in src) - if((weapon in component_parts) || weapon == beaker) - continue + var/item_weight + for(var/obj/item/ingredient in contents) if(beaker.reagents.holder_full()) break + if((ingredient in component_parts) || ingredient == beaker) + 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 + //record item weight before & after blending + item_weight = ingredient.w_class - if(juicing) - 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(length(ingredient.grind_results) || ingredient.reagents?.total_volume) - 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 + if(juicing) + 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 + else 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 //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 + if(item_weight != ingredient.w_class) + total_weight += item_weight - ingredient.w_class else total_weight += item_weight - //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) - //use power according to the total weight of items grinded use_energy((active_power_usage * (duration / 1 SECONDS)) * (total_weight / maximum_weight)) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index b4493eb2ae4..0c6d638fca1 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -506,11 +506,17 @@ if(grinded) to_chat(user, span_warning("There is something inside already!")) return - if(I.juice_typepath || I.grind_results) + if(!I.blend_requirements(src)) + to_chat(user, span_warning("Cannot grind this!")) + return + if(length(I.grind_results) || I.reagents?.total_volume) I.forceMove(src) grinded = I - return - to_chat(user, span_warning("You can't grind this!")) + +/obj/item/reagent_containers/cup/mortar/blended(obj/item/blended_item, grinded) + src.grinded = null + + return ..() /obj/item/reagent_containers/cup/mortar/proc/grind_item(obj/item/item, mob/living/carbon/human/user) if(item.flags_1 & HOLOGRAM_1) @@ -520,13 +526,12 @@ if(!item.grind(reagents, user)) if(isstack(item)) - to_chat(usr, span_notice("[src] attempts to grind as many pieces of [item] as possible.")) + to_chat(user, span_notice("[src] attempts to grind as many pieces of [item] as possible.")) else to_chat(user, span_danger("You fail to grind [item].")) return + to_chat(user, span_notice("You grind [item] into a nice powder.")) - grinded = null - QDEL_NULL(item) /obj/item/reagent_containers/cup/mortar/proc/juice_item(obj/item/item, mob/living/carbon/human/user) if(item.flags_1 & HOLOGRAM_1) @@ -537,9 +542,8 @@ if(!item.juice(reagents, user)) to_chat(user, span_notice("You fail to juice [item].")) return + to_chat(user, span_notice("You juice [item] into a fine liquid.")) - grinded = null - QDEL_NULL(item) //Coffeepots: for reference, a standard cup is 30u, to allow 20u for sugar/sweetener/milk/creamer /obj/item/reagent_containers/cup/coffeepot