diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 15d8af848c0..c10c04a9fa1 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -984,11 +984,10 @@ /obj/item/proc/grind(datum/reagents/target_holder, mob/user) if(on_grind() == -1) return FALSE - if(!reagents) - reagents = new() - target_holder.add_reagent_list(grind_results) - if(reagents && target_holder) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + if(target_holder) + target_holder.add_reagent_list(grind_results) + if(reagents) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) return 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 @@ -1001,9 +1000,10 @@ /obj/item/proc/juice(datum/reagents/target_holder, mob/user) if(on_juice() == -1) return FALSE - reagents.convert_reagent(/datum/reagent/consumable, juice_typepath, include_source_subtypes = TRUE) - if(reagents && target_holder) - reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) + if(reagents) + reagents.convert_reagent(/datum/reagent/consumable, juice_typepath, include_source_subtypes = TRUE) + if(target_holder) + reagents.trans_to(target_holder, reagents.total_volume, transferred_by = user) return TRUE /obj/item/proc/set_force_string() diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 5c616fa4803..7050309268c 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -145,18 +145,49 @@ /obj/item/stack/set_custom_materials(list/materials, multiplier=1, is_update=FALSE) return is_update ? ..() : set_mats_per_unit(materials, multiplier/(amount || 1)) - -/obj/item/stack/on_grind() - . = ..() - for(var/i in 1 to length(grind_results)) //This should only call if it's ground, so no need to check if grind_results exists - grind_results[grind_results[i]] *= get_amount() //Gets the key at position i, then the reagent amount of that key, then multiplies it by stack size - /obj/item/stack/grind_requirements() if(is_cyborg) to_chat(usr, span_warning("[src] is too integrated into your chassis and can't be ground up!")) return return TRUE +/obj/item/stack/grind(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) + var/available_volume = target_holder.maximum_volume - target_holder.total_volume + + //compute total volume of reagents that will be occupied by grind_results + var/total_volume = 0 + for(var/reagent in grind_results) + total_volume += grind_results[reagent] + + //compute number of pieces(or sheets) from available_volume + var/available_amount = min(current_amount, round(available_volume / total_volume)) + if(available_amount <= 0) + return FALSE + + //Now transfer the grind results scaled by available_amount + var/list/grind_reagents = grind_results.Copy() + for(var/reagent in grind_reagents) + grind_reagents[reagent] *= available_amount + target_holder.add_reagent_list(grind_reagents) + + /** + * use available_amount of sheets/pieces, return TRUE only if all sheets/pieces of this stack were used + * we don't delete this stack when it reaches 0 because we expect the all in one grinder, etc to delete + * this stack if grinding was successfull + */ + use(available_amount, check = FALSE) + return available_amount == current_amount + /obj/item/stack/proc/get_main_recipes() RETURN_TYPE(/list) SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/plumbing/plumbers/grinder_chemical.dm b/code/modules/plumbing/plumbers/grinder_chemical.dm index 5e3c3b0f5d3..e70977bc1f4 100644 --- a/code/modules/plumbing/plumbers/grinder_chemical.dm +++ b/code/modules/plumbing/plumbers/grinder_chemical.dm @@ -1,6 +1,6 @@ /obj/machinery/plumbing/grinder_chemical name = "chemical grinder" - desc = "chemical grinder." + desc = "Chemical grinder. Can either grind or juice stuff you put in." icon_state = "grinder_chemical" layer = ABOVE_ALL_MOB_LAYER plane = ABOVE_GAME_PLANE @@ -8,7 +8,6 @@ reagent_flags = TRANSPARENT | DRAINABLE buffer = 400 active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 2 - var/eat_dir = SOUTH /obj/machinery/plumbing/grinder_chemical/Initialize(mapload, bolt, layer) . = ..() @@ -18,21 +17,35 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/obj/machinery/plumbing/grinder_chemical/setDir(newdir) - . = ..() - eat_dir = newdir +/obj/machinery/plumbing/grinder_chemical/attackby(obj/item/weapon, mob/user, params) + if(istype(weapon, /obj/item/storage/bag)) + to_chat(user, span_notice("You dump items from [weapon] into the grinder.")) + for(var/obj/item/obj_item in weapon.contents) + grind(obj_item) + else + to_chat(user, span_notice("You attempt to grind [weapon].")) + grind(weapon) + + return TRUE /obj/machinery/plumbing/grinder_chemical/CanAllowThrough(atom/movable/mover, border_dir) . = ..() if(!anchored) return - if(border_dir == eat_dir) - return TRUE + if(!istype(mover, /obj/item)) + return FALSE + return TRUE /obj/machinery/plumbing/grinder_chemical/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER + grind(AM) +/** + * Grinds/Juices the atom + * Arguments + * * [AM][atom] - the atom to grind or juice + */ /obj/machinery/plumbing/grinder_chemical/proc/grind(atom/AM) if(machine_stat & NOPOWER) return @@ -40,11 +53,14 @@ return if(!isitem(AM)) return + var/obj/item/I = AM + var/result if(I.grind_results || I.juice_typepath) use_power(active_power_usage) if(I.grind_results) - I.grind(src, src) + result = I.grind(reagents, usr) else if (I.juice_typepath) - I.juice(src, src) - qdel(I) + result = I.juice(reagents, usr) + if(result) + qdel(I) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 4e5930b96df..902ccf35e6a 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -1391,9 +1391,7 @@ /// Is this holder full or not /datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE + return total_volume >= maximum_volume /// Get the amount of this reagent /datum/reagents/proc/get_reagent_amount(reagent, include_subtypes = FALSE) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 35be2dc1865..26ebfa1d18d 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -99,11 +99,9 @@ . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return - if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH)) + if(operating || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH)) return - if(operating) - return - replace_beaker(user) + eject(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/machinery/reagentgrinder/attack_robot_secondary(mob/user, list/modifiers) @@ -146,24 +144,28 @@ default_unfasten_wrench(user, tool) return TOOL_ACT_TOOLTYPE_SUCCESS -/obj/machinery/reagentgrinder/attackby(obj/item/I, mob/living/user, params) - //You can only screw open empty grinder - if(!beaker && !length(holdingitems) && default_deconstruction_screwdriver(user, icon_state, icon_state, I)) - return +/obj/machinery/reagentgrinder/screwdriver_act(mob/living/user, obj/item/tool) + . = TOOL_ACT_TOOLTYPE_SUCCESS + if(!beaker && !length(holdingitems)) + return default_deconstruction_screwdriver(user, icon_state, icon_state, tool) - if(default_deconstruction_crowbar(I)) - return +/obj/machinery/reagentgrinder/crowbar_act(mob/living/user, obj/item/tool) + return default_deconstruction_crowbar(tool) +/obj/machinery/reagentgrinder/attackby(obj/item/weapon, mob/living/user, params) if(panel_open) //Can't insert objects when its screwed open return TRUE - if (is_reagent_container(I) && !(I.item_flags & ABSTRACT) && I.is_open_container()) - var/obj/item/reagent_containers/B = I + if(!weapon.grind_requirements(src)) //Error messages should be in the objects' definitions + return + + 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(B, src)) + if(!user.transferItemToLoc(container, src)) return - replace_beaker(user, B) - to_chat(user, span_notice("You add [B] to [src].")) + replace_beaker(user, container) + to_chat(user, span_notice("You add [container] to [src].")) update_appearance() return TRUE //no afterattack @@ -172,39 +174,36 @@ return TRUE //Fill machine with a bag! - if(istype(I, /obj/item/storage/bag)) - if(!I.contents.len) - to_chat(user, span_notice("[I] is empty!")) + 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(I.atom_storage.remove_type(/obj/item/food/grown, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) + 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(I.atom_storage.remove_type(/obj/item/food/honeycomb, src, limit - length(holdingitems), TRUE, FALSE, user, inserted)) + 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(!I.contents.len) - to_chat(user, span_notice("You empty [I] into [src].")) + 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(!I.grind_results && !I.juice_typepath) + if(!weapon.grind_results && !weapon.juice_typepath) if(user.combat_mode) return ..() else - to_chat(user, span_warning("You cannot grind [I] into reagents!")) + to_chat(user, span_warning("You cannot grind/juice [weapon] into reagents!")) return TRUE - if(!I.grind_requirements(src)) //Error messages should be in the objects' definitions - return - - if(user.transferItemToLoc(I, src)) - to_chat(user, span_notice("You add [I] to [src].")) - holdingitems[I] = TRUE + if(user.transferItemToLoc(weapon, src)) + to_chat(user, span_notice("You add [weapon] to [src].")) + holdingitems[weapon] = TRUE return FALSE /obj/machinery/reagentgrinder/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave @@ -261,9 +260,9 @@ if(beaker) replace_beaker(user) -/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O) - holdingitems -= O - qdel(O) +/obj/machinery/reagentgrinder/proc/remove_object(obj/item/weapon) + holdingitems -= weapon + qdel(weapon) /obj/machinery/reagentgrinder/proc/start_shaking() var/static/list/transforms @@ -306,11 +305,11 @@ /obj/machinery/reagentgrinder/proc/juice(mob/user) power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) return operate_for(50, juicing = TRUE) for(var/obj/item/i in holdingitems) - if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(beaker.reagents.holder_full()) break var/obj/item/I = i if(I.juice_typepath) @@ -324,12 +323,12 @@ /obj/machinery/reagentgrinder/proc/grind(mob/user) power_change() - if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(!beaker || machine_stat & (NOPOWER|BROKEN) || beaker.reagents.holder_full()) return operate_for(60) warn_of_dust() // don't breathe this. for(var/i in holdingitems) - if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume) + if(beaker.reagents.holder_full()) break var/obj/item/I = i if(I.grind_results) @@ -337,7 +336,10 @@ /obj/machinery/reagentgrinder/proc/grind_item(obj/item/I, mob/user) //Grind results can be found in respective object definitions if(!I.grind(beaker.reagents, user)) - to_chat(usr, span_danger("[src] shorts out as it tries to grind up [I], and transfers it back to storage.")) + if(isstack(I)) + to_chat(usr, span_notice("[src] attempts to grind as many pieces of [I] as possible.")) + else + to_chat(usr, span_danger("[src] shorts out as it tries to grind up [I], and transfers it back to storage.")) return remove_object(I) @@ -347,7 +349,7 @@ if(!beaker || machine_stat & (NOPOWER|BROKEN)) return operate_for(50, juicing = TRUE) - addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/machinery/reagentgrinder, mix_complete)), 50) + addtimer(CALLBACK(src, PROC_REF(mix_complete)), 50 / speed) /obj/machinery/reagentgrinder/proc/mix_complete() if(beaker?.reagents.total_volume <= 0) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 069c770f009..b5930955a31 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -537,7 +537,10 @@ /obj/item/reagent_containers/cup/mortar/proc/grind_item(obj/item/item, mob/living/carbon/human/user) if(!item.grind(reagents, user)) - to_chat(user, span_notice("You fail to grind [item].")) + if(isstack(item)) + to_chat(usr, 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