diff --git a/code/modules/food_and_drinks/recipes/soup_mixtures.dm b/code/modules/food_and_drinks/recipes/soup_mixtures.dm index b35bc128d32..b9f08d8e26e 100644 --- a/code/modules/food_and_drinks/recipes/soup_mixtures.dm +++ b/code/modules/food_and_drinks/recipes/soup_mixtures.dm @@ -62,24 +62,45 @@ if(!length(required_ingredients)) return TRUE - // This is very unoptimized for something ran every handle-reaction for every soup recipe. - // Look into ways for improving this, cause bleh + //copy of all ingredients to check out var/list/reqs_copy = required_ingredients.Copy() + //number of ingredients who's requested amounts has been satisfied + var/completed_ingredients = 0 for(var/obj/item/ingredient as anything in pot.added_ingredients) - // See if we fulfill all reqs - for(var/ingredient_type in required_ingredients) - if(!istype(ingredient, ingredient_type)) - continue - if(isstack(ingredient)) - var/obj/item/stack/stack_ingredient = ingredient - reqs_copy[ingredient_type] -= stack_ingredient.amount + var/ingredient_type = ingredient.type + do + { + var/ingredient_count = reqs_copy[ingredient_type] + + //means we still have left over ingredients + if(ingredient_count) + //decode ingredient type i.e. stack or not and fulfill request + if(ispath(ingredient_type, /obj/item/stack)) + var/obj/item/stack/stack_ingredient = ingredient + ingredient_count -= stack_ingredient.amount + else + ingredient_count -= 1 + + //assign final values + if(ingredient_count <= 0) + completed_ingredients += 1 + ingredient_count = 0 + reqs_copy[ingredient_type] = ingredient_count + + //work complete + break + + //means we have to look for subtypes + else if(isnull(ingredient_count)) + ingredient_type = type2parent(ingredient_type) + + //means we have no more remaining ingredients so bail, can happen if multiple ingredients of the same type/subtype are in the pot else - reqs_copy[ingredient_type] -= 1 + break + } + while(ingredient_type != /obj/item) - for(var/fulfilled in reqs_copy) - if(reqs_copy[fulfilled] > 0) - return FALSE - return TRUE + return completed_ingredients == reqs_copy.len /datum/chemical_reaction/food/soup/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) if(!length(required_ingredients)) @@ -167,24 +188,31 @@ new_ingredient.reagents?.chem_temp = holder.chem_temp cached_ingredients[new_ref] = new_ingredient.reagents?.total_volume || 1 + var/turf/below_pot = get_turf(pot) for(var/datum/weakref/ingredient_ref as anything in cached_ingredients) var/obj/item/ingredient = ingredient_ref.resolve() + // An ingredient has gone missing, stop the reaction if(QDELETED(ingredient) || ingredient.loc != holder.my_atom) testing("Soup reaction ended due to having an invalid ingredient present.") return END_REACTION - // Don't add any more reagents if we've boiled over - if(reaction.data["boiled_over"]) - continue - - // Transfer 20% of the initial reagent volume of the ingredient to the soup - transfer_ingredient_reagents(ingredient, holder, max(cached_ingredients[ingredient_ref] * 0.2, 2)) + // Transfer 20% of the initial reagent volume of the ingredient to the soup. + if(!transfer_ingredient_reagents(ingredient, holder, max(cached_ingredients[ingredient_ref] * 0.2, 2))) + continue //all reagents were transfered // Uh oh we reached the top of the pot, the soup's gonna boil over. if(holder.total_volume >= holder.maximum_volume * 0.95) - boil_over(holder) - reaction.data["boiled_over"] = TRUE + below_pot.visible_message(span_warning("[pot] starts to boil over!")) + // Create a spread of dirty foam + var/datum/effect_system/fluid_spread/foam/dirty/soup_mess = new() + soup_mess.reagent_scale = 0.1 // (Just a little) + soup_mess.set_up(range = 1, holder = pot, location = below_pot, carry = holder, stop_reactions = TRUE) + soup_mess.start() + // Loses a bit from the foam + for(var/datum/reagent/reagent as anything in holder.reagent_list) + reagent.volume *= 0.5 + holder.update_total() /datum/chemical_reaction/food/soup/reaction_finish(datum/reagents/holder, datum/equilibrium/reaction, react_vol) . = ..() @@ -234,45 +262,34 @@ /** * Transfers reagents from the passed reagent to the soup pot, as a "result" + * Also handles deleting a portion of nutriment reagents present, pseudo-converting + * it into soup reagent. Returns TRUE if any reagents were transfered FALSE if there is + * nothing to transfer * - * Also handles deleting a portion of nutriment reagents present, pseudo-converting it into soup reagent - * - * * ingredient: The ingredient to transfer reagents from - * * holder: The reagent holder of the soup pot the reaction is taking place in - * * amount: The amount of reagents to transfer, if null will transfer all reagents + * Arguments + * * obj/item/ingredient - The ingredient to transfer reagents from + * * datum/reagentsholder - The reagent holder of the soup pot the reaction is taking place in + * * amount - The amount of reagents to transfer, if null will transfer all reagents */ /datum/chemical_reaction/food/soup/proc/transfer_ingredient_reagents(obj/item/ingredient, datum/reagents/holder, amount) if(ingredient_reagent_multiplier <= 0) - return + return FALSE var/datum/reagents/ingredient_pool = ingredient.reagents // Some ingredients are purely flavor (no pun intended) and will have reagents if(isnull(ingredient_pool) || ingredient_pool.total_volume <= 0) - return + return FALSE if(isnull(amount)) amount = ingredient_pool.total_volume testing("Soup reaction has made it to the finishing step with ingredients that still contain reagents. [amount] reagents left in [ingredient].") // Some of the nutriment goes into "creating the soup reagent" itself, gets deleted. // Mainly done so that nutriment doesn't overpower the main course - ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment, amount * percentage_of_nutriment_converted) - ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment/vitamin, amount * percentage_of_nutriment_converted) + var/remove_amount = amount * percentage_of_nutriment_converted + ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment, remove_amount) + ingredient_pool.remove_reagent(/datum/reagent/consumable/nutriment/vitamin, remove_amount) // The other half of the nutriment, and the rest of the reagents, will get put directly into the pot ingredient_pool.trans_to(holder, amount, ingredient_reagent_multiplier, no_react = TRUE) - -/// Called whenever the soup pot overfills with reagent. -/datum/chemical_reaction/food/soup/proc/boil_over(datum/reagents/holder) - var/obj/item/reagent_containers/cup/soup_pot/pot = holder.my_atom - var/turf/below_pot = get_turf(pot) - below_pot.visible_message(span_warning("[pot] starts to boil over!")) - // Create a spread of dirty foam - var/datum/effect_system/fluid_spread/foam/dirty/soup_mess = new() - soup_mess.reagent_scale = 0.1 // (Just a little) - soup_mess.set_up(range = 1, holder = pot, location = below_pot, carry = holder, stop_reactions = TRUE) - soup_mess.start() - // Loses a bit from the foam - for(var/datum/reagent/reagent as anything in holder.reagent_list) - reagent.volume = round(reagent.volume * 0.9, 0.05) - holder.update_total() + return TRUE /// Adds text to the requirements list of the recipe /// Return a list of strings, each string will be a new line in the requirements list diff --git a/code/modules/reagents/chemistry/equilibrium.dm b/code/modules/reagents/chemistry/equilibrium.dm index bcca8eb67da..2a7ca3daaa9 100644 --- a/code/modules/reagents/chemistry/equilibrium.dm +++ b/code/modules/reagents/chemistry/equilibrium.dm @@ -57,10 +57,6 @@ /datum/equilibrium/New(datum/chemical_reaction/input_reaction, datum/reagents/input_holder) reaction = input_reaction holder = input_holder - if(!holder || !reaction) //sanity check - stack_trace("A new [type] was set up, with incorrect/null input vars!") - to_delete = TRUE - return if(!check_inital_conditions()) //If we're outside of the scope of the reaction vars to_delete = TRUE return @@ -78,6 +74,7 @@ LAZYREMOVE(holder.reaction_list, src) holder = null reaction = null + to_delete = TRUE return ..() /* @@ -87,39 +84,51 @@ * Don't call this unless you know what you're doing, this is an internal proc */ /datum/equilibrium/proc/check_inital_conditions() + if(QDELETED(holder)) + stack_trace("an equilibrium is missing it's holder.") + return FALSE + if(QDELETED(reaction)) + stack_trace("an equilibrium is missing it's reaction.") + return FALSE + if(!length(reaction.required_reagents)) + stack_trace("an equilibrium is missing required reagents.") + return FALSE + //Make sure we have the right multipler for on_reaction() for(var/single_reagent in reaction.required_reagents) - multiplier = min(multiplier, round((holder.get_reagent_amount(single_reagent) / reaction.required_reagents[single_reagent]), CHEMICAL_QUANTISATION_LEVEL)) - if(multiplier == INFINITY) + multiplier = min(multiplier, holder.get_reagent_amount(single_reagent) / reaction.required_reagents[single_reagent]) + multiplier = round(multiplier, CHEMICAL_QUANTISATION_LEVEL) + if(!multiplier) //we have no more or very little reagents left return FALSE - //Consider purity gating too? - probably not, purity is hard to determine + //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)))) return FALSE + + //All checks pass. cache the product ratio + if(length(reaction.results)) + product_ratio = 0 + for(var/product in reaction.results) + product_ratio += reaction.results[product] + else + product_ratio = 1 return TRUE -/* -* Check to make sure our input vars are sensible - is the holder overheated? does it have the required reagents? Does it have the required calalysts? -* -* If you're adding more checks for reactions, this is the proc to edit -* otherwise, generally, don't call this directed except internally -*/ +/** + * Check to make sure our input vars are sensible + * 1) Is our atom in which this reaction is occuring still intact? + * 2) Do we still have reagents to react with + * 3) Do we have the required catalysts? + * If you're adding more checks for reactions, this is the proc to edit + * otherwise, generally, don't call this directed except internally + */ /datum/equilibrium/proc/check_reagent_properties() - //Have we exploded from on_reaction? - if(!holder.my_atom || holder.reagent_list.len == 0) - return FALSE - if(!holder) - stack_trace("an equilibrium is missing it's holder.") - return FALSE - if(!reaction) - stack_trace("an equilibrium is missing it's reaction.") + //Have we exploded from on_reaction or did we run out of reagents? + if(QDELETED(holder.my_atom) || !holder.reagent_list.len) return FALSE - //set up catalyst checks + //Check for catalysts var/total_matching_catalysts = 0 - //Reagents check should be handled in the calculate_yield() from multiplier - - //If the product/reactants are too impure for(var/datum/reagent/reagent as anything in holder.reagent_list) //this is done this way to reduce processing compared to holder.has_reagent(P) for(var/datum/reagent/catalyst as anything in reaction.required_catalysts) @@ -130,11 +139,8 @@ if(reagent.volume >= catalyst_agent.min_volume) catalyst_agent.consider_catalyst(src) - if(!(total_matching_catalysts == reaction.required_catalysts.len)) - return FALSE - - //All good! - return TRUE + //Our present catalysts should match with our required catalyts + return total_matching_catalysts == reaction.required_catalysts.len /* * Calculates how much we're aiming to create @@ -144,61 +150,29 @@ * Generally an internal proc */ /datum/equilibrium/proc/calculate_yield() - if(!reaction) - stack_trace("Tried to calculate an equlibrium for reaction [reaction.type], but there was no reaction set for the datum") - return FALSE - multiplier = INFINITY for(var/reagent in reaction.required_reagents) - multiplier = min(multiplier, round((holder.get_reagent_amount(reagent) / reaction.required_reagents[reagent]), CHEMICAL_QUANTISATION_LEVEL)) + multiplier = min(multiplier, holder.get_reagent_amount(reagent) / reaction.required_reagents[reagent]) + multiplier = round(multiplier, CHEMICAL_QUANTISATION_LEVEL) + if(!multiplier) //we have no more or very little reagents left + return FALSE - if(!length(reaction.results)) //Incase of no reagent product - product_ratio = 1 + //Incase of no reagent product + if(!length(reaction.results)) step_target_vol = INFINITY for(var/reagent in reaction.required_reagents) step_target_vol = min(step_target_vol, multiplier * reaction.required_reagents[reagent]) - if(step_target_vol == 0 || multiplier == 0) - return FALSE - //Sanity Check - if(step_target_vol == INFINITY || multiplier == INFINITY) //I don't see how this can happen, but I'm not bold enough to let infinities roll around for free - to_delete = TRUE - CRASH("Tried to calculate target vol for [reaction.type] with no products, but could not find required reagents for the reaction. If it got here, something is really broken with the recipe.") return TRUE - product_ratio = 0 + //If we have reagent products step_target_vol = 0 - var/true_reacted_vol //Because volumes can be lost mid reactions + reacted_vol = 0 //Because volumes can be lost mid reactions for(var/product in reaction.results) - step_target_vol += (reaction.results[product]*multiplier) - product_ratio += reaction.results[product] - true_reacted_vol += holder.get_reagent_amount(product) - if(step_target_vol == 0 || multiplier == INFINITY) - return FALSE - target_vol = step_target_vol + true_reacted_vol - reacted_vol = true_reacted_vol + step_target_vol += (multiplier * reaction.results[product]) + reacted_vol += holder.get_reagent_amount(product) + target_vol = reacted_vol + step_target_vol return TRUE -/* -* Deals with lag - allows a reaction to speed up to 3x from seconds_per_tick -* "Charged" time (time_deficit) discharges by incrementing reactions by doubling them -* If seconds_per_tick is greater than 1.5, then we save the extra time for the next ticks -* -* Arguments: -* * seconds_per_tick - the time between the last proc in world.time -*/ -/datum/equilibrium/proc/deal_with_time(seconds_per_tick) - if(seconds_per_tick > 1) - time_deficit += seconds_per_tick - 1 - seconds_per_tick = 1 //Lets make sure reactions aren't super speedy and blow people up from a big lag spike - else if (time_deficit) - if(time_deficit < 0.25) - seconds_per_tick += time_deficit - time_deficit = 0 - else - seconds_per_tick += 0.25 - time_deficit -= 0.25 - return seconds_per_tick - /* * Main method of checking for explosive - or failed states * Checks overheated() and overly_impure() of a reaction @@ -226,10 +200,29 @@ SSblackbox.record_feedback("tally", "chemical_reaction", 1, "[reaction.type] overly impure reaction steps") reaction.overly_impure(holder, src, step_volume_added) - //did we explode? - if(!holder.my_atom || holder.reagent_list.len == 0) - return FALSE - return TRUE + //did we explode or run out of reagents? + return !QDELETED(holder.my_atom) && holder.reagent_list.len + +/* +* Deals with lag - allows a reaction to speed up to 3x from seconds_per_tick +* "Charged" time (time_deficit) discharges by incrementing reactions by doubling them +* If seconds_per_tick is greater than 1.5, then we save the extra time for the next ticks +* +* Arguments: +* * seconds_per_tick - the time between the last proc in world.time +*/ +/datum/equilibrium/proc/deal_with_time(seconds_per_tick) + if(seconds_per_tick > 1) + time_deficit += seconds_per_tick - 1 + seconds_per_tick = 1 //Lets make sure reactions aren't super speedy and blow people up from a big lag spike + else if (time_deficit) + if(time_deficit < 0.25) + seconds_per_tick += time_deficit + time_deficit = 0 + else + seconds_per_tick += 0.25 + time_deficit -= 0.25 + return seconds_per_tick /* * Main reaction processor - Increments the reaction by a timestep @@ -243,8 +236,7 @@ * * purity_modifier - how much to modify the step's purity by (0 - 1) */ /datum/equilibrium/proc/react_timestep(seconds_per_tick, purity_modifier = 1) - if(to_delete) - //This occurs when it explodes + if(to_delete) //Sanity incase we try to complete a failed reaction return FALSE if(!check_reagent_properties()) //this is first because it'll call explosions first to_delete = TRUE @@ -270,13 +262,13 @@ if (cached_ph < (reaction.optimal_ph_min - reaction.determin_ph_range)) //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 - (reaction.optimal_ph_min - reaction.determin_ph_range)) ** reaction.ph_exponent_factor) / ((reaction.determin_ph_range ** reaction.ph_exponent_factor))) //main pH calculation //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 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. + 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 @@ -285,7 +277,7 @@ //Calculate DeltaT (Deviation of T from optimal) if(!reaction.is_cold_recipe) if (cached_temp < reaction.optimal_temp && cached_temp >= reaction.required_temp) - delta_t = (((cached_temp - reaction.required_temp)**reaction.temp_exponent_factor)/((reaction.optimal_temp - reaction.required_temp)**reaction.temp_exponent_factor)) + delta_t = (((cached_temp - reaction.required_temp) ** reaction.temp_exponent_factor) / ((reaction.optimal_temp - reaction.required_temp) ** reaction.temp_exponent_factor)) else if (cached_temp >= reaction.optimal_temp) delta_t = 1 else //too hot @@ -294,7 +286,7 @@ return else if (cached_temp > reaction.optimal_temp && cached_temp <= reaction.required_temp) - delta_t = (((reaction.required_temp - cached_temp)**reaction.temp_exponent_factor)/((reaction.required_temp - reaction.optimal_temp)**reaction.temp_exponent_factor)) + delta_t = (((reaction.required_temp - cached_temp) ** reaction.temp_exponent_factor) / ((reaction.required_temp - reaction.optimal_temp) ** reaction.temp_exponent_factor)) else if (cached_temp <= reaction.optimal_temp) delta_t = 1 else //Too cold @@ -310,7 +302,8 @@ //Catalyst modifier delta_t *= speed_mod - purity = delta_ph//set purity equal to pH offset + //set purity equal to pH offset + purity = delta_ph //Then adjust purity of result with beaker reagent purity. purity *= reactant_purity(reaction) @@ -319,16 +312,15 @@ purity *= purity_modifier //Now we calculate how much to add - this is normalised to the rate up limiter - var/delta_chem_factor = (reaction.rate_up_lim*delta_t)*seconds_per_tick//add/remove factor - var/total_step_added = 0 + var/delta_chem_factor = (reaction.rate_up_lim * delta_t) * seconds_per_tick//add/remove factor //keep limited if(delta_chem_factor > step_target_vol) delta_chem_factor = step_target_vol - else if (delta_chem_factor < CHEMICAL_VOLUME_ROUNDING) - delta_chem_factor = CHEMICAL_VOLUME_ROUNDING //Normalise to multiproducts - delta_chem_factor /= product_ratio - delta_chem_factor = round(delta_chem_factor, CHEMICAL_VOLUME_ROUNDING) // Might not be needed - left here incase testmerge shows that it does. Remove before full commit. + delta_chem_factor = round(delta_chem_factor / product_ratio, CHEMICAL_VOLUME_ROUNDING) + if(delta_chem_factor <= 0) + to_delete = TRUE + return //Calculate how much product to make and how much reactant to remove factors.. for(var/reagent in reaction.required_reagents) @@ -336,12 +328,13 @@ //Apply pH changes var/pH_adjust if(reaction.reaction_flags & REACTION_PH_VOL_CONSTANT) - pH_adjust = ((delta_chem_factor * reaction.required_reagents[reagent])/target_vol)*(reaction.H_ion_release*h_ion_mod) + pH_adjust = ((delta_chem_factor * reaction.required_reagents[reagent]) / target_vol) * (reaction.H_ion_release * h_ion_mod) else //Default adds pH independant of volume - pH_adjust = (delta_chem_factor * reaction.required_reagents[reagent])*(reaction.H_ion_release*h_ion_mod) + pH_adjust = (delta_chem_factor * reaction.required_reagents[reagent]) * (reaction.H_ion_release * h_ion_mod) holder.adjust_specific_reagent_ph(reagent, pH_adjust) var/step_add + var/total_step_added = 0 for(var/product in reaction.results) //create the products step_add = delta_chem_factor * reaction.results[product] @@ -351,9 +344,9 @@ //Apply pH changes var/pH_adjust if(reaction.reaction_flags & REACTION_PH_VOL_CONSTANT) - pH_adjust = (step_add/target_vol)*(reaction.H_ion_release*h_ion_mod) + pH_adjust = (step_add / target_vol) * (reaction.H_ion_release * h_ion_mod) else - pH_adjust = step_add*(reaction.H_ion_release*h_ion_mod) + pH_adjust = step_add * (reaction.H_ion_release * h_ion_mod) holder.adjust_specific_reagent_ph(product, pH_adjust) reacted_vol += step_add total_step_added += step_add @@ -367,7 +360,7 @@ //Apply thermal output of reaction to beaker if(reaction.reaction_flags & REACTION_HEAT_ARBITARY) - holder.chem_temp += clamp((reaction.thermic_constant* total_step_added*thermic_mod), 0, CHEMICAL_MAXIMUM_TEMPERATURE) //old method - for every bit added, the whole temperature is adjusted + holder.chem_temp += clamp((reaction.thermic_constant * total_step_added * thermic_mod), 0, CHEMICAL_MAXIMUM_TEMPERATURE) //old method - for every bit added, the whole temperature is adjusted else //Standard mechanics var/heat_energy = reaction.thermic_constant * total_step_added * thermic_mod * SPECIFIC_HEAT_DEFAULT holder.adjust_thermal_energy(heat_energy, 0, CHEMICAL_MAXIMUM_TEMPERATURE) //heat is relative to the beaker conditions @@ -386,32 +379,26 @@ to_delete = TRUE //end reactions faster so plumbing is faster - if((step_add >= step_target_vol) && (length(holder.reaction_list == 1)))//length is so that plumbing is faster - but it doesn't disable competitive reactions. Basically, competitive reactions will likely reach their step target at the start, so this will disable that. We want to avoid that. But equally, we do want to full stop a holder from reacting asap so plumbing isn't waiting an tick to resolve. + //length is so that plumbing is faster - but it doesn't disable competitive reactions. Basically, competitive reactions will likely reach their step target at the start, so this will disable that. We want to avoid that. But equally, we do want to full stop a holder from reacting asap so plumbing isn't waiting an tick to resolve. + if((step_add >= step_target_vol) && (length(holder.reaction_list == 1))) to_delete = TRUE - holder.update_total()//do NOT recalculate reactions - + holder.update_total() /* * 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/reactant_purity(datum/chemical_reaction/C) var/list/cached_reagents = holder.reagent_list - var/i = 0 - var/cached_purity - for(var/datum/reagent/reagent as anything in holder.reagent_list) - if (reagent in cached_reagents) - cached_purity += reagent.purity - i++ - if(!i)//I've never seen it get here with 0, but in case - it gets here when it blows up from overheat + + 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 [C.type]. Beaker: [holder.my_atom]") return 0 //we exploded and cleared reagents - but lets not kill the process - return cached_purity/i -///Panic stop a reaction - cleanup should be handled by the next timestep -/datum/equilibrium/proc/force_clear_reactive_agents() - for(var/reagent in reaction.required_reagents) - holder.remove_reagent(reagent, (multiplier * reaction.required_reagents[reagent])) + var/cached_purity + for(var/datum/reagent/reagent as anything in cached_reagents) + cached_purity += reagent.purity + return cached_purity / num_of_reagents diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index 62dc148bba2..51490c5890f 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -189,7 +189,7 @@ var/datum/reagent/reagent = holder.has_reagent(id) if(!reagent) return - reagent.volume = round((reagent.volume*0.98), 0.01) //Slowly lower yield per tick + reagent.volume = round((reagent.volume * 0.98), CHEMICAL_QUANTISATION_LEVEL) //Slowly lower yield per tick /** * Occurs when a reation is too impure (i.e. it's below purity_min)