From a1d27e384dc6707a1db2a31cc4ab316fec235366 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 5 Aug 2025 08:12:58 +0530 Subject: [PATCH] Merges `copy_to()` into `trans_to()` for reagent holder (#92410) ## About The Pull Request Merges `/datum/reagents/proc/copy_to()` -> `/datum/reagents/proc/trans_to()`. Added a parameter `copy_only` to indicate we want a copy operation ## Why It's Good For The Game - Less code to maintain - All the functionality of `trans_to()`[logging, transferring single reagent, expelling reagents from stomach, etc] now applies for copying reagents as well which was missing a lot of it, so we have consistent behaviour ## Changelog :cl: refactor: code for copying reagents has been refactored. Please report bugs on github /:cl: --- code/datums/components/food/edible.dm | 2 +- .../fluid_spread/effects_foam.dm | 6 +- .../fluid_spread/effects_smoke.dm | 8 +- code/game/objects/items/food/egg.dm | 4 +- .../food_and_drinks/machinery/processor.dm | 2 +- .../plumbing/plumbers/_plumb_reagents.dm | 10 +-- .../reagents/chemistry/holder/holder.dm | 78 +++---------------- .../chemistry/machinery/smoke_machine.dm | 2 +- code/modules/reagents/chemistry/reagents.dm | 14 +++- .../reagents/reaction_agents_reagents.dm | 30 ++++--- .../reagent_containers/cups/glassbottle.dm | 2 +- .../reagents/reagent_containers/hypospray.dm | 2 +- 12 files changed, 58 insertions(+), 102 deletions(-) diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 21bb8a49f97..8a9255d3a18 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -327,7 +327,7 @@ Behavior that's still missing from this component that original food items had t var/volume = ROUND_UP(original_atom.reagents.maximum_volume / chosen_processing_option[TOOL_PROCESSING_AMOUNT]) this_food.create_reagents(volume, this_food.reagents?.flags) - original_atom.reagents.copy_to(this_food, original_atom.reagents.total_volume / chosen_processing_option[TOOL_PROCESSING_AMOUNT], 1) + original_atom.reagents.trans_to(this_food, original_atom.reagents.total_volume / chosen_processing_option[TOOL_PROCESSING_AMOUNT], copy_only = TRUE) if(original_atom.name != initial(original_atom.name)) this_food.name = "slice of [original_atom.name]" diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm index 4698e153607..788740e9f32 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_foam.dm @@ -166,7 +166,7 @@ foam_mob(foaming, seconds_per_tick) var/obj/effect/particle_effect/fluid/foam/spread_foam = new type(spread_turf, group, src) - reagents.copy_to(spread_foam, (reagents.total_volume)) + reagents.trans_to(spread_foam, reagents.total_volume, copy_only = TRUE) spread_foam.add_atom_colour(color, FIXED_COLOUR_PRIORITY) spread_foam.result_type = result_type SSfoam.queue_spread(spread_foam) @@ -199,7 +199,7 @@ /datum/effect_system/fluid_spread/foam/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, result_type = null, stop_reactions = FALSE) . = ..() - carry?.copy_to(chemholder, carry.total_volume, no_react = stop_reactions) + carry?.trans_to(chemholder, carry.total_volume, no_react = stop_reactions, copy_only = TRUE) if(!isnull(result_type)) src.result_type = result_type @@ -208,7 +208,7 @@ var/foamcolor = mix_color_from_reagents(chemholder.reagent_list) if(reagent_scale > 1) // Make room in case we were created by a particularly stuffed payload. foam.reagents.maximum_volume *= reagent_scale - chemholder.copy_to(foam, chemholder.total_volume, reagent_scale) // Foam has an amplifying effect on the reagents it is supplied with. This is balanced by the reagents being diluted as the area the foam covers increases. + chemholder.trans_to(foam, chemholder.total_volume, reagent_scale, copy_only = TRUE) // Foam has an amplifying effect on the reagents it is supplied with. This is balanced by the reagents being diluted as the area the foam covers increases. foam.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY) if(!isnull(result_type)) foam.result_type = result_type diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm index c5e365eee8e..c9e68ce6ede 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -86,7 +86,7 @@ smoke_mob(smoker, seconds_per_tick) var/obj/effect/particle_effect/fluid/smoke/spread_smoke = new type(spread_turf, group, src) - reagents.copy_to(spread_smoke, reagents.total_volume) + reagents.trans_to(spread_smoke, reagents.total_volume, copy_only = TRUE) spread_smoke.add_atom_colour(color, FIXED_COLOUR_PRIORITY) spread_smoke.lifetime = lifetime @@ -392,7 +392,7 @@ return FALSE var/fraction = (seconds_per_tick SECONDS) / initial(lifetime) - reagents.copy_to(smoker, reagents.total_volume, fraction, copy_methods = SMOKE_MACHINE) + reagents.trans_to(smoker, reagents.total_volume, fraction, methods = SMOKE_MACHINE, copy_only = TRUE) reagents.expose(smoker, SMOKE_MACHINE, fraction) return TRUE @@ -423,7 +423,7 @@ /datum/effect_system/fluid_spread/smoke/chem/set_up(range = 1, amount = DIAMOND_AREA(range), atom/holder, atom/location = null, datum/reagents/carry = null, silent = FALSE) . = ..() - carry?.copy_to(chemholder, carry.total_volume) + carry?.trans_to(chemholder, carry.total_volume, copy_only = TRUE) if(silent) return @@ -452,7 +452,7 @@ var/start_loc = holder ? get_turf(holder) : src.location var/mixcolor = mix_color_from_reagents(chemholder.reagent_list) var/obj/effect/particle_effect/fluid/smoke/chem/smoke = new effect_type(start_loc, new /datum/fluid_group(amount)) - chemholder.copy_to(smoke, chemholder.total_volume) + chemholder.trans_to(smoke, chemholder.total_volume, copy_only = TRUE) if(mixcolor) smoke.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with diff --git a/code/game/objects/items/food/egg.dm b/code/game/objects/items/food/egg.dm index 8ef8ff8f29f..8faea08ad94 100644 --- a/code/game/objects/items/food/egg.dm +++ b/code/game/objects/items/food/egg.dm @@ -134,7 +134,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) if(LAZYACCESS(modifiers, ICON_Y)) broken_egg.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y/2), ICON_SIZE_Y/2) playsound(user, 'sound/items/sheath.ogg', 40, TRUE) - reagents.copy_to(broken_egg, reagents.total_volume) + reagents.trans_to(broken_egg, reagents.total_volume, copy_only = TRUE) hit_griddle.AddToGrill(broken_egg, user) interacting_with.balloon_alert(user, "cracks [src] open") @@ -383,7 +383,7 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0) if(LAZYACCESS(modifiers, ICON_Y)) broken_egg.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(ICON_SIZE_Y/2), ICON_SIZE_Y/2) playsound(user, 'sound/items/sheath.ogg', 40, TRUE) - reagents.copy_to(broken_egg, reagents.total_volume) + reagents.trans_to(broken_egg, reagents.total_volume, copy_only = TRUE) hit_griddle.AddToGrill(broken_egg, user) interacting_with.balloon_alert(user, "cracks [src] open") diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 374a5ed92bb..859628abc98 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -72,7 +72,7 @@ var/atom/processed_food = new recipe.output(drop_location()) if(processed_food.reagents && what.reagents) processed_food.reagents.clear_reagents() - what.reagents.copy_to(processed_food, what.reagents.total_volume, multiplier = 1 / cached_multiplier) + what.reagents.trans_to(processed_food, what.reagents.total_volume, multiplier = 1 / cached_multiplier, copy_only = TRUE) if(cached_mats) processed_food.set_custom_materials(cached_mats, 1 / cached_multiplier) diff --git a/code/modules/plumbing/plumbers/_plumb_reagents.dm b/code/modules/plumbing/plumbers/_plumb_reagents.dm index 1f9a2e5e961..4e18a0fbca5 100644 --- a/code/modules/plumbing/plumbers/_plumb_reagents.dm +++ b/code/modules/plumbing/plumbers/_plumb_reagents.dm @@ -27,7 +27,8 @@ remove_blacklisted = FALSE, //unused for plumbing, we don't care what reagents are inside us methods = LINEAR, //default round robin technique for transferring reagents show_message = TRUE, //unused for plumbing, used for logging only - ignore_stomach = FALSE //unused for plumbing, reagents flow only between machines & is not injected to mobs at any point in time + ignore_stomach = FALSE, //unused for plumbing, reagents flow only between machines & is not injected to mobs at any point in time + copy_only = FALSE //unused ) if(QDELETED(target) || !total_volume) return FALSE @@ -85,8 +86,6 @@ transfer_amount = reagent.volume * part if(reagent.intercept_reagents_transfer(target_holder, amount)) - update_total() - target_holder.update_total() continue transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount, copy_data(reagent), chem_temp, reagent.purity, reagent.ph, no_react = TRUE) //we only handle reaction after every reagent has been transferred. @@ -156,7 +155,8 @@ remove_blacklisted = FALSE, methods = LINEAR, show_message = TRUE, - ignore_stomach = FALSE + ignore_stomach = FALSE, + copy_only = FALSE ) var/obj/machinery/plumbing/reaction_chamber/reactor = my_atom var/list/datum/reagent/catalysts = reactor.catalysts @@ -233,8 +233,6 @@ transfer_amount = working_volume * part if(reagent.intercept_reagents_transfer(target_holder, amount)) - update_total() - target_holder.update_total() continue transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount, copy_data(reagent), chem_temp, reagent.purity, reagent.ph, no_react = TRUE) //we only handle reaction after every reagent has been transferred. diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index 9d77804bcd9..3e505c830b3 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -409,6 +409,7 @@ * * methods - passed through to [/datum/reagents/proc/expose] and [/datum/reagent/proc/on_transfer] * * show_message - passed through to [/datum/reagents/proc/expose] * * ignore_stomach - when using methods INGEST will not use the stomach as the target + * * copy_only - transfers the reagents without removing it from this holder */ /datum/reagents/proc/trans_to( atom/target, @@ -421,7 +422,8 @@ remove_blacklisted = FALSE, methods = NONE, show_message = TRUE, - ignore_stomach = FALSE + ignore_stomach = FALSE, + copy_only = FALSE ) if(QDELETED(target) || !total_volume) return FALSE @@ -488,21 +490,21 @@ if(preserve_data) trans_data = copy_data(reagent) - if(reagent.intercept_reagents_transfer(target_holder, transfer_amount)) - update_total() - target_holder.update_total() + if(reagent.intercept_reagents_transfer(target_holder, transfer_amount, copy_only)) continue transfered_amount = target_holder.add_reagent(reagent.type, transfer_amount * multiplier, trans_data, chem_temp, reagent.purity, reagent.ph, no_react = TRUE, reagent_added = r_to_send, creation_callback = CALLBACK(src, PROC_REF(_on_transfer_creation), reagent, target_holder)) //we only handle reaction after every reagent has been transferred. if(!transfered_amount) continue total_transfered_amount += transfered_amount - reagent.volume -= transfer_amount + if(!copy_only) + reagent.volume -= transfer_amount transfer_log += "[reagent.type] ([transfered_amount]u, [reagent.purity] purity)" if(!isnull(target_id)) break - update_total() + if(!copy_only) + update_total() //expose target to reagent changes if(methods) @@ -522,7 +524,8 @@ if(!no_react) transfer_reactions(target_holder) - handle_reactions() + if(!copy_only) + handle_reactions() target_holder.handle_reactions() return total_transfered_amount @@ -533,67 +536,6 @@ SEND_SIGNAL(reagent, COMSIG_REAGENT_ON_TRANSFER, target_holder, new_reagent) -/** - * Copies the reagents to the target object - * Arguments - * - * * [target][obj] - the target to transfer reagents to - * * multiplier - multiplies each reagent amount by this number well byond their available volume before transfering. used to create reagents from thin air if you ever need to - * * preserve_data - preserve user data of all reagents after transfering - * * no_react - if TRUE will not handle reactions - * * copy_methods - forwards reagent exposure method flags like INGEST & INHALE to reagent.on_transfer to trigger transfer effects. - */ -/datum/reagents/proc/copy_to( - atom/target, - amount = 1, - multiplier = 1, - preserve_data = TRUE, - no_react = FALSE, - copy_methods = NONE, -) - if(QDELETED(target) || !total_volume) - return - - if(!IS_FINITE(amount)) - stack_trace("non finite amount passed to copy_to [amount] amount of reagents") - return FALSE - - var/datum/reagents/target_holder - if(istype(target, /datum/reagents)) - target_holder = target - else - if(!target.reagents) - return - target_holder = target.reagents - - // Prevents small amount problems, as well as zero and below zero amounts. - amount = round(min(amount, total_volume, target_holder.maximum_volume - target_holder.total_volume), CHEMICAL_QUANTISATION_LEVEL) - if(amount <= 0) - return - - var/list/cached_reagents = reagent_list - var/part = amount / total_volume - var/transfer_amount - var/total_transfered_amount = 0 - var/trans_data = null - var/list/r_to_send = copy_methods ? list() : null - - for(var/datum/reagent/reagent as anything in cached_reagents) - transfer_amount = reagent.volume * part * multiplier - if(preserve_data) - trans_data = copy_data(reagent) - total_transfered_amount += target_holder.add_reagent(reagent.type, transfer_amount, trans_data, chem_temp, reagent.purity, reagent.ph, reagent_added = r_to_send, no_react = TRUE) - - //expose target to reagent changes - if(copy_methods) - target_holder.expose(target, copy_methods, 1, FALSE, r_to_send) - - if(!no_react) - transfer_reactions(target_holder) - target_holder.handle_reactions() - - return total_transfered_amount - /** * Multiplies reagents inside this holder by a specific amount * Arguments diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index 53c8ca49056..54358350d5c 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -35,7 +35,7 @@ src.location = get_turf(location) src.amount = amount if(carry) - carry.copy_to(chemholder, 20) + carry.trans_to(chemholder, 20, copy_only = TRUE) carry.remove_all(amount / efficiency) /obj/machinery/smoke_machine/Initialize(mapload) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index e9ee81fe2b7..d26272934cc 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -189,11 +189,17 @@ /datum/reagent/proc/on_burn_wound_processing(datum/wound/burn/flesh/burn_wound) return -/* -Used to run functions before a reagent is transferred. Returning TRUE will block the transfer attempt. -Primarily used in reagents/reaction_agents +/** + * Intercepts the reagent transfer/copy operation to do some work before it takes place. + * Used to perform some reaction work. Return TRUE To cancel the operation + * + * Arguments + * + * * datum/reagents/target - the target holder we are being transferred to + * * amount - the amount of reagent being transferred + * * copy_only - if TRUE we don't remove ourself from the holder because its a reagent copy & not transfer operation */ -/datum/reagent/proc/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/proc/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) return FALSE /// Called when this reagent is first added to a mob diff --git a/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm b/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm index eac83c5efc9..2a7ce91cc8d 100644 --- a/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/reaction_agents_reagents.dm @@ -2,14 +2,14 @@ name = "Reaction Agent" description = "Hello! I am a bugged reagent. Please report me for my crimes. Thank you!!" -/datum/reagent/reaction_agent/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/reaction_agent/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) if(!target) return FALSE if(target.flags & NO_REACT) return FALSE if(target.has_reagent(/datum/reagent/stabilizing_agent)) return FALSE - if(LAZYLEN(target.reagent_list) == 0) + if(!target.total_volume) return FALSE if(LAZYLEN(target.reagent_list) == 1) if(target.has_reagent(type)) //Allow dispensing into self @@ -27,7 +27,7 @@ glass_price = DRINK_PRICE_HIGH //Consumes self on addition and shifts ph -/datum/reagent/reaction_agent/acidic_buffer/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/reaction_agent/acidic_buffer/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) . = ..() if(!.) return @@ -39,11 +39,14 @@ else message = "The beaker froths as the pH changes!" target.adjust_all_reagents_ph((-(amount / target.total_volume) * BUFFER_IONIZING_STRENGTH)) + target.update_total() //give feedback & remove from holder because it's not transferred target.my_atom.audible_message(span_warning(message)) playsound(target.my_atom, 'sound/effects/chemistry/bufferadd.ogg', 50, TRUE) - holder.remove_reagent(type, amount) + if(!copy_only) + volume -= amount + holder.update_total() /datum/reagent/reaction_agent/basic_buffer name = "Strong Basic Buffer" @@ -55,7 +58,7 @@ fallback_icon_state = "base_buffer_fallback" glass_price = DRINK_PRICE_HIGH -/datum/reagent/reaction_agent/basic_buffer/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/reaction_agent/basic_buffer/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) . = ..() if(!.) return @@ -67,11 +70,14 @@ else message = "The beaker froths as the pH changes!" target.adjust_all_reagents_ph(((amount / target.total_volume) * BUFFER_IONIZING_STRENGTH)) + target.update_total() //give feedback & remove from holder because it's not transferred target.my_atom.audible_message(span_warning(message)) playsound(target.my_atom, 'sound/effects/chemistry/bufferadd.ogg', 50, TRUE) - holder.remove_reagent(type, amount) + if(!copy_only) + volume -= amount + holder.update_total() //purity testor/reaction agent prefactors @@ -91,7 +97,7 @@ ph = 3 color = "#ffffff" -/datum/reagent/reaction_agent/purity_tester/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/reaction_agent/purity_tester/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) . = ..() if(!.) return @@ -105,7 +111,9 @@ playsound(target.my_atom, 'sound/effects/chemistry/bufferadd.ogg', 50, TRUE) else target.my_atom.audible_message(span_warning("The added reagent doesn't seem to do much.")) - holder.remove_reagent(type, amount) + if(!copy_only) + volume -= amount + holder.update_total() ///How much the reaction speed is sped up by - for 5u added to 100u, an additional step of 1 will be done up to a max of 2x #define SPEED_REAGENT_STRENGTH 20 @@ -116,7 +124,7 @@ ph = 10 color = "#e61f82" -/datum/reagent/reaction_agent/speed_agent/intercept_reagents_transfer(datum/reagents/target, amount) +/datum/reagent/reaction_agent/speed_agent/intercept_reagents_transfer(datum/reagents/target, amount, copy_only) . = ..() if(!.) return FALSE @@ -131,6 +139,8 @@ power *= creation_purity power = clamp(power, 0, 2) reaction.react_timestep(power, creation_purity) - holder.remove_reagent(type, amount) + if(!copy_only) + volume -= amount + holder.update_total() #undef SPEED_REAGENT_STRENGTH diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index 2438be6bd9c..391a1bfc241 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -918,7 +918,7 @@ if(!bottle) return ..() icon_state = bottle.icon_state - bottle.reagents.copy_to(src, 100) + bottle.reagents.trans_to(src, 100, copy_only = TRUE) if(istype(bottle, /obj/item/reagent_containers/cup/glass/bottle/juice)) desc += " You're not sure if making this out of a carton was the brightest idea." isGlass = FALSE diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index e786badff1d..bd953c1ec6e 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -55,7 +55,7 @@ trans = reagents.trans_to(affected_mob, amount_per_transfer_from_this, transferred_by = user, methods = INJECT) else reagents.expose(affected_mob, INJECT, fraction) - trans = reagents.copy_to(affected_mob, amount_per_transfer_from_this, copy_methods = INJECT) + trans = reagents.trans_to(affected_mob, amount_per_transfer_from_this, methods = INJECT, copy_only = TRUE) to_chat(user, span_notice("[trans] unit\s injected. [reagents.total_volume] unit\s remaining in [src].")) log_combat(user, affected_mob, "injected", src, "([contained])") return TRUE