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
🆑
refactor: code for copying reagents has been refactored. Please report
bugs on github
/🆑
This commit is contained in:
SyncIt21
2025-08-05 04:42:58 +02:00
committed by GitHub
parent 04711c7600
commit a1d27e384d
12 changed files with 58 additions and 102 deletions
@@ -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
@@ -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)
+10 -4
View File
@@ -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
@@ -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
@@ -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
@@ -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