Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Reactions now use volume averaged purity #1868

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 9 additions & 30 deletions code/modules/reagents/chemistry/equilibrium.dm
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
return FALSE

//To prevent reactions outside of the pH window from starting.
if(!((holder.ph >= (reaction.optimal_ph_min - reaction.determin_ph_range)) && (holder.ph <= (reaction.optimal_ph_max + reaction.determin_ph_range))))
if(holder.ph < (reaction.optimal_ph_min - reaction.determin_ph_range) || holder.ph > (reaction.optimal_ph_max + reaction.determin_ph_range))
return FALSE

//All checks pass. cache the product ratio
Expand Down Expand Up @@ -265,24 +265,23 @@
//Begin checks
//Calculate DeltapH (Deviation of pH from optimal)
//Within mid range
var/acceptable_ph
if (cached_ph >= reaction.optimal_ph_min && cached_ph <= reaction.optimal_ph_max)
delta_ph = 1 //100% purity for this step
//Lower range
else if (cached_ph < reaction.optimal_ph_min) //If we're outside of the optimal lower bound
if (cached_ph < (reaction.optimal_ph_min - reaction.determin_ph_range)) //If we're outside of the deterministic bound
acceptable_ph = reaction.optimal_ph_min - reaction.determin_ph_range
if (cached_ph < acceptable_ph) //If we're outside of the deterministic bound
delta_ph = 0 //0% purity
else //We're in the deterministic phase
delta_ph = (((cached_ph - (reaction.optimal_ph_min - reaction.determin_ph_range)) ** reaction.ph_exponent_factor) / ((reaction.determin_ph_range ** reaction.ph_exponent_factor))) //main pH calculation
delta_ph = ((cached_ph - acceptable_ph) / reaction.determin_ph_range) ** reaction.ph_exponent_factor
//Upper range
else if (cached_ph > reaction.optimal_ph_max) //If we're above of the optimal lower bound
if (cached_ph > (reaction.optimal_ph_max + reaction.determin_ph_range)) //If we're outside of the deterministic bound
acceptable_ph = reaction.optimal_ph_max + reaction.determin_ph_range
if (cached_ph > acceptable_ph) //If we're outside of the deterministic bound
delta_ph = 0 //0% purity
else //We're in the deterministic phase
delta_ph = (((- cached_ph + (reaction.optimal_ph_max + reaction.determin_ph_range)) ** reaction.ph_exponent_factor) / (reaction.determin_ph_range ** reaction.ph_exponent_factor))//Reverse - to + to prevent math operation failures.

//This should never proc, but it's a catch incase someone puts in incorrect values
else
stack_trace("[holder.my_atom] attempted to determine FermiChem pH for '[reaction.type]' which had an invalid pH of [cached_ph] for set recipie pH vars. It's likely the recipe vars are wrong.")
delta_ph = ((acceptable_ph - cached_ph) / reaction.determin_ph_range) ** reaction.ph_exponent_factor

//Calculate DeltaT (Deviation of T from optimal)
if(!reaction.is_cold_recipe)
Expand Down Expand Up @@ -316,7 +315,7 @@
purity = delta_ph

//Then adjust purity of result with beaker reagent purity.
purity *= average_purity()
purity *= holder.get_average_purity()

//Then adjust it from the input modifier
purity *= purity_modifier
Expand Down Expand Up @@ -399,23 +398,3 @@
//i.e. we have created all the reagents needed for this reaction
if(total_step_added >= step_target_vol)
to_delete = TRUE

/*
* Calculates the total sum normalised purity of ALL reagents in a holder
* Currently calculates it irrespective of required reagents at the start, but this should be changed if this is powergamed to required reagents
* It's not currently because overly_impure affects all reagents
*/
/datum/equilibrium/proc/average_purity()
PRIVATE_PROC(TRUE)

var/list/cached_reagents = holder.reagent_list

var/num_of_reagents = cached_reagents.len
if(!num_of_reagents)//I've never seen it get here with 0, but in case - it gets here when it blows up from overheat
stack_trace("No reactants found mid reaction for [reaction.type]. Beaker: [holder.my_atom]")
return 0 //we exploded and cleared reagents - but lets not kill the process

var/cached_purity
for(var/datum/reagent/reagent as anything in cached_reagents)
cached_purity += reagent.purity
return cached_purity / num_of_reagents
38 changes: 21 additions & 17 deletions code/modules/reagents/chemistry/holder/reactions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -308,36 +308,39 @@
var/list/cached_required_reagents = selected_reaction.required_reagents
var/list/cached_results = selected_reaction.results
var/datum/cached_my_atom = my_atom
var/multiplier = INFINITY
for(var/reagent in cached_required_reagents)
multiplier = round(min(multiplier, get_reagent_amount(reagent) / cached_required_reagents[reagent]))

if(!multiplier)//Incase we're missing reagents - usually from on_reaction being called in an equlibrium when the results.len == 0 handlier catches a misflagged reaction
//find how much ration of products to create
var/multiplier = INFINITY
for(var/datum/reagent/requirement as anything in cached_required_reagents)
multiplier = min(multiplier, get_reagent_amount(requirement) / cached_required_reagents[requirement])
multiplier = round(multiplier, CHEMICAL_QUANTISATION_LEVEL)
if(!multiplier)//Incase we're missing reagents - usually from on_reaction being called in an equlibrium when the results.len == 0 handler catches a misflagged reaction
return FALSE
var/sum_purity = 0
for(var/_reagent in cached_required_reagents)//this is not an object
var/datum/reagent/reagent = has_reagent(_reagent)
if (!reagent)
continue
sum_purity += reagent.purity
remove_reagent(_reagent, (multiplier * cached_required_reagents[_reagent]))
sum_purity /= cached_required_reagents.len

for(var/product in selected_reaction.results)
multiplier = max(multiplier, 1) //this shouldn't happen ...
var/yield = (cached_results[product]*multiplier)*sum_purity
//average purity to be used in scaling the yield of products formed
var/average_purity = get_average_purity()

//remove the required reagents
for(var/datum/reagent/requirement as anything in cached_required_reagents)//this is not an object
remove_reagent(requirement, cached_required_reagents[requirement] * multiplier)

//add the result reagents whose yield depend on the average purity
var/yield
for(var/datum/reagent/product as anything in cached_results)
yield = cached_results[product] * multiplier * average_purity
SSblackbox.record_feedback("tally", "chemical_reaction", yield, product)
add_reagent(product, yield, null, chem_temp, sum_purity)
add_reagent(product, yield, null, chem_temp, average_purity)

//play sounds on the target atom
var/list/seen = viewers(4, get_turf(my_atom))
var/iconhtml = icon2html(cached_my_atom, seen)
if(cached_my_atom)
if(!ismob(cached_my_atom)) // No bubbling mobs
if(selected_reaction.mix_sound)
playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, TRUE)

my_atom.audible_message(span_notice("[iconhtml] [selected_reaction.mix_message]"))

//use slime extract
if(istype(cached_my_atom, /obj/item/slime_extract))
var/obj/item/slime_extract/extract = my_atom
extract.extract_uses--
Expand All @@ -353,4 +356,5 @@
my_turf.pollute_turf(selected_reaction.pollutant_type, selected_reaction.pollutant_amount * multiplier)
//NOVA EDIT END

//finish the reaction
selected_reaction.on_reaction(src, null, multiplier)
Loading