/proc/chem_recipes_do_conflict(datum/chemical_reaction/r1, datum/chemical_reaction/r2) //We have to check to see if either is competitive so can ignore it (competitive reagents are supposed to conflict) if((r1.reaction_flags & REACTION_COMPETITIVE) || (r2.reaction_flags & REACTION_COMPETITIVE)) return FALSE //do the non-list tests first, because they are cheaper if(r1.required_container != r2.required_container) return FALSE if(r1.is_cold_recipe == r2.is_cold_recipe) if(r1.required_temp != r2.required_temp) //one reaction requires a more extreme temperature than the other, so there is no conflict return FALSE else var/datum/chemical_reaction/cold_one = r1.is_cold_recipe ? r1 : r2 var/datum/chemical_reaction/warm_one = r1.is_cold_recipe ? r2 : r1 if(cold_one.required_temp < warm_one.required_temp) //the range of temperatures does not overlap, so there is no conflict return FALSE //find the reactions with the shorter and longer required_reagents list var/datum/chemical_reaction/long_req var/datum/chemical_reaction/short_req if(r1.required_reagents.len > r2.required_reagents.len) long_req = r1 short_req = r2 else if(r1.required_reagents.len < r2.required_reagents.len) long_req = r2 short_req = r1 else //if they are the same length, sort instead by the length of the catalyst list //this is important if the required_reagents lists are the same if(r1.required_catalysts.len > r2.required_catalysts.len) long_req = r1 short_req = r2 else long_req = r2 short_req = r1 //check if the shorter reaction list is a subset of the longer one var/list/overlap = r1.required_reagents & r2.required_reagents if(overlap.len != short_req.required_reagents.len) //there is at least one reagent in the short list that is not in the long list, so there is no conflict return FALSE //check to see if the shorter reaction's catalyst list is also a subset of the longer reaction's catalyst list //if the longer reaction's catalyst list is a subset of the shorter ones, that is fine //if the reaction lists are the same, the short reaction will have the shorter required_catalysts list, so it will register as a conflict var/list/short_minus_long_catalysts = short_req.required_catalysts - long_req.required_catalysts if(short_minus_long_catalysts.len) //there is at least one unique catalyst for the short reaction, so there is no conflict return FALSE //if we got this far, the longer reaction will be impossible to create if the shorter one is earlier in GLOB.chemical_reactions_list_reactant_index, and will require the reagents to be added in a particular order otherwise return TRUE /proc/get_chemical_reaction(id) if(!GLOB.chemical_reactions_list_reactant_index) return for(var/reagent in GLOB.chemical_reactions_list_reactant_index) for(var/R in GLOB.chemical_reactions_list_reactant_index[reagent]) var/datum/reac = R if(reac.type == id) return R /proc/remove_chemical_reaction(datum/chemical_reaction/R) if(!GLOB.chemical_reactions_list_reactant_index || !R) return for(var/rid in R.required_reagents) GLOB.chemical_reactions_list_reactant_index[rid] -= R //see build_chemical_reactions_list in holder.dm for explanations /proc/add_chemical_reaction(datum/chemical_reaction/add) if(!GLOB.chemical_reactions_list_reactant_index || !add.required_reagents || !add.required_reagents.len) return var/rand_reagent = pick(add.required_reagents) if(!GLOB.chemical_reactions_list_reactant_index[rand_reagent]) GLOB.chemical_reactions_list_reactant_index[rand_reagent] = list() GLOB.chemical_reactions_list_reactant_index[rand_reagent] += add //Creates foam from the reagent. Metaltype is for metal foam, notification is what to show people in textbox /datum/reagents/proc/create_foam(foamtype, foam_volume, result_type = null, notification = null, log = FALSE) var/location = get_turf(my_atom) var/datum/effect_system/fluid_spread/foam/foam = new foamtype() foam.set_up(amount = foam_volume, holder = my_atom, location = location, carry = src, result_type = result_type) foam.start(log = log) clear_reagents() if(!notification) return for(var/mob/M in viewers(5, location)) to_chat(M, notification) ///Converts the pH into a tgui readable color - i.e. white and black text is readable over it. This is NOT the colourwheel for pHes however. /proc/convert_ph_to_readable_color(pH) switch(pH) if(-INFINITY to 1) return "red" if(1 to 2) return "orange" if(2 to 3) return "average" if(3 to 4) return "yellow" if(4 to 5) return "olive" if(5 to 6) return "good" if(6 to 8) return "green" if(8 to 9.5) return "teal" if(9.5 to 11) return "blue" if(11 to 12.5) return "violet" if(12.5 to INFINITY) return "purple" ///Converts pH to universal indicator colours. This is the colorwheel for pHes #define CONVERT_PH_TO_COLOR(pH, color) \ switch(pH) {\ if(14 to INFINITY)\ { color = "#462c83" }\ if(13 to 14)\ { color = "#63459b" }\ if(12 to 13)\ { color = "#5a51a2" }\ if(11 to 12)\ { color = "#3853a4" }\ if(10 to 11)\ { color = "#3f93cf" }\ if(9 to 10)\ { color = "#0bb9b7" }\ if(8 to 9)\ { color = "#23b36e" }\ if(7 to 8)\ { color = "#3aa651" }\ if(6 to 7)\ { color = "#4cb849" }\ if(5 to 6)\ { color = "#b5d335" }\ if(4 to 5)\ { color = "#f7ec1e" }\ if(3 to 4)\ { color = "#fbc314" }\ if(2 to 3)\ { color = "#f26724" }\ if(1 to 2)\ { color = "#ef1d26" }\ if(-INFINITY to 1)\ { color = "#c6040c" }\ } ///Returns a list of chemical_reaction datums that have the input STRING as a product /proc/get_reagent_type_from_product_string(string) var/input_reagent = replacetext(LOWER_TEXT(string), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name if (isnull(input_reagent)) return var/list/shortcuts = list("meth" = /datum/reagent/drug/methamphetamine) if(shortcuts[input_reagent]) input_reagent = shortcuts[input_reagent] else input_reagent = find_reagent(input_reagent) return input_reagent ///Returns reagent datum from typepath /proc/find_reagent(input) . = FALSE if(GLOB.chemical_reagents_list[input]) //prefer IDs! return input else return get_chem_id(input) /proc/find_reagent_object_from_type(input) if(GLOB.chemical_reagents_list[input]) //prefer IDs! return GLOB.chemical_reagents_list[input] else return null ///Returns a random reagent object, with the option to blacklist reagents. /proc/get_random_reagent_id(list/blacklist) var/static/list/reagent_static_list = list() //This is static, and will be used by default if a blacklist is not passed. var/list/reagent_list_to_process if(blacklist) //If we do have a blacklist, we recompile a new list with the excluded reagents not present and pick from there. reagent_list_to_process = list() else reagent_list_to_process = reagent_static_list if(!reagent_list_to_process.len) for(var/datum/reagent/reagent_path as anything in subtypesof(/datum/reagent)) if(is_path_in_list(reagent_path, blacklist)) continue if(initial(reagent_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) reagent_list_to_process += reagent_path var/picked_reagent = pick(reagent_list_to_process) return picked_reagent ///Returns a random reagent consumable ethanol object minus blacklisted reagents /proc/get_random_drink_id() var/static/list/random_drinks = list() if(!random_drinks.len) for(var/datum/reagent/drink_path as anything in subtypesof(/datum/reagent/consumable/ethanol)) if(initial(drink_path.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) random_drinks += drink_path var/picked_drink = pick(random_drinks) return picked_drink ///Returns reagent datum from reagent name string /proc/get_chem_id(chem_name) for(var/X in GLOB.chemical_reagents_list) var/datum/reagent/R = GLOB.chemical_reagents_list[X] if(ckey(chem_name) == ckey(LOWER_TEXT(R.name))) return X ///Takes a type in and returns a list of associated recipes /proc/get_recipe_from_reagent_product(input_type) if(!input_type) return var/list/matching_reactions = GLOB.chemical_reactions_list_product_index[input_type] return matching_reactions /proc/reagent_paths_list_to_text(list/reagents, addendum) var/list/temp = list() for(var/datum/reagent/R as anything in reagents) temp |= initial(R.name) if(addendum) temp += addendum return jointext(temp, ", ")