diff --git a/code/modules/reagents/chemistry/holder(nonProc.old.functional.).dm b/code/modules/reagents/chemistry/holder(nonProc.old.functional.).dm deleted file mode 100644 index c38f065383..0000000000 --- a/code/modules/reagents/chemistry/holder(nonProc.old.functional.).dm +++ /dev/null @@ -1,967 +0,0 @@ -/proc/build_chemical_reagent_list() - //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id - - if(GLOB.chemical_reagents_list) - return - - var/paths = subtypesof(/datum/reagent) - GLOB.chemical_reagents_list = list() - - for(var/path in paths) - var/datum/reagent/D = new path() - GLOB.chemical_reagents_list[D.id] = D - -/proc/build_chemical_reactions_list() - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list - // It is filtered into multiple lists within a list. - // For example: - // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma - - if(GLOB.chemical_reactions_list) - return - - var/paths = subtypesof(/datum/chemical_reaction) - GLOB.chemical_reactions_list = list() - - for(var/path in paths) - - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() - - if(D.required_reagents && D.required_reagents.len) - for(var/reaction in D.required_reagents) - reaction_ids += reaction - - // Create filters based on each reagent id in the required reagents list - for(var/id in reaction_ids) - if(!GLOB.chemical_reactions_list[id]) - GLOB.chemical_reactions_list[id] = list() - GLOB.chemical_reactions_list[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant - -/////////////////////////////////////////////////////////////////////////////////// - -/datum/reagents - var/list/datum/reagent/reagent_list = new/list() - var/total_volume = 0 - var/maximum_volume = 100 - var/atom/my_atom = null - var/chem_temp = 150 - var/pH = REAGENT_NORMAL_PH - var/last_tick = 1 - var/addiction_tick = 1 - var/list/datum/reagent/addiction_list = new/list() - var/reagents_holder_flags - -/datum/reagents/New(maximum=100) - maximum_volume = maximum - - //I dislike having these here but map-objects are initialised before world/New() is called. >_> - if(!GLOB.chemical_reagents_list) - build_chemical_reagent_list() - if(!GLOB.chemical_reactions_list) - build_chemical_reactions_list() - -/datum/reagents/Destroy() - . = ..() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - qdel(R) - cached_reagents.Cut() - cached_reagents = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null - my_atom = null - -// Used in attack logs for reagents in pills and such -/datum/reagents/proc/log_list() - if(!length(reagent_list)) - return "no reagents" - - var/list/data = list() - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.id] ([round(R.volume, 0.1)]u)" - //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. - return english_list(data) - -/datum/reagents/proc/remove_any(amount = 1) - var/list/cached_reagents = reagent_list - var/total_transfered = 0 - var/current_list_element = 1 - - current_list_element = rand(1, cached_reagents.len) - - while(total_transfered != amount) - if(total_transfered >= amount) - break - if(total_volume <= 0 || !cached_reagents.len) - break - - if(current_list_element > cached_reagents.len) - current_list_element = 1 - - var/datum/reagent/R = cached_reagents[current_list_element] - remove_reagent(R.id, 1) - - current_list_element++ - total_transfered++ - update_total() - - handle_reactions() - return total_transfered - -/datum/reagents/proc/remove_all(amount = 1) - var/list/cached_reagents = reagent_list - if(total_volume > 0) - var/part = amount / total_volume - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - remove_reagent(R.id, R.volume * part) - - update_total() - handle_reactions() - return amount - -/datum/reagents/proc/get_master_reagent_name() - var/list/cached_reagents = reagent_list - var/name - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - name = R.name - - return name - -/datum/reagents/proc/get_master_reagent_id() - var/list/cached_reagents = reagent_list - var/id - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - id = R.id - - return id - -/datum/reagents/proc/get_master_reagent() - var/list/cached_reagents = reagent_list - var/datum/reagent/master - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - master = R - - return master - -/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - if(amount < 0) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/transfer_amount = T.volume * part - if(preserve_data) - trans_data = copy_data(T) - - //fermichem Added ph TODO: add T.purity - R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - //R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, T.purity, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - remove_reagent(T.id, transfer_amount) - - update_total() - R.update_total() - if(!no_react) - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - - if(amount < 0) - return - amount = min(min(amount, total_volume), R.maximum_volume-R.total_volume) - var/part = amount / total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/copy_amount = T.volume * part - if(preserve_data) - trans_data = T.data - R.add_reagent(T.id, copy_amount * multiplier, trans_data) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N - var/list/cached_reagents = reagent_list - if (!target) - return - if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) - return - if(amount < 0) - return - - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent)= R.overdose_threshold && !R.overdosed) - R.overdosed = 1 - need_mob_update += R.overdose_start(C) - if(R.addiction_threshold) - if(R.volume >= R.addiction_threshold && !is_type_in_list(R, cached_addictions)) - var/datum/reagent/new_reagent = new R.type() - cached_addictions.Add(new_reagent) - if(R.overdosed) - need_mob_update += R.overdose_process(C) - if(is_type_in_list(R,cached_addictions)) - for(var/addiction in cached_addictions) - var/datum/reagent/A = addiction - if(istype(R, A)) - A.addiction_stage = -15 // you're satisfied for a good while. - need_mob_update += R.on_mob_life(C) - - if(can_overdose) - if(addiction_tick == 6) - addiction_tick = 1 - for(var/addiction in cached_addictions) - var/datum/reagent/R = addiction - if(C && R) - R.addiction_stage++ - if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end) - need_mob_update += R.addiction_act_stage1(C) - else if(R.addiction_stage1_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end) - need_mob_update += R.addiction_act_stage2(C) - else if(R.addiction_stage2_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end) - need_mob_update += R.addiction_act_stage3(C) - else if(R.addiction_stage3_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end) - need_mob_update += R.addiction_act_stage4(C) - else if(R.addiction_stage4_end <= R.addiction_stage) - to_chat(C, "You feel like you've gotten over your need for [R.name].") - SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.id]_addiction") - cached_addictions.Remove(R) - addiction_tick++ - if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates. - C.updatehealth() - C.update_canmove() - C.update_stamina() - update_total() - - -/datum/reagents/proc/set_reacting(react = TRUE) - if(react) - reagents_holder_flags &= ~(REAGENT_NOREACT) - else - reagents_holder_flags |= REAGENT_NOREACT - -/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_move (A, Running) - update_total() - -/datum/reagents/proc/conditional_update(atom/A) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_update (A) - update_total() - -/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar - var/list/cached_reagents = reagent_list //a list of the reagents? - var/list/cached_reactions = GLOB.chemical_reactions_list //a list of the whole reactions? - var/datum/cached_my_atom = my_atom //It says my atom, but I didn't bring one with me!! - if(reagents_holder_flags & REAGENT_NOREACT) //Not sure on reagents_holder_flags, but I think it checks to see if theres a reaction with current stuff. - return //Yup, no reactions here. No siree. - - var/reaction_occurred = 0 // checks if reaction, binary variable - do //What does do do in byond? It sounds very redundant? is it a while loop? - var/list/possible_reactions = list() //init list - reaction_occurred = 0 // sets it back to 0? - for(var/reagent in cached_reagents) //for reagent in beaker/holder - var/datum/reagent/R = reagent //check to make sure that reagent is there for the reaction list - for(var/reaction in cached_reactions[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id - if(!reaction) - continue - - var/datum/chemical_reaction/C = reaction - var/list/cached_required_reagents = C.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 - var/list/cached_required_catalysts = C.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 - var/required_temp = C.required_temp - var/is_cold_recipe = C.is_cold_recipe - var/meets_temp_requirement = 0 - var/has_special_react = C.special_react - var/can_special_react = 0 - //FermiChem WHY ARE VARIBLES SO ESTRANGED it makes me sad - /* - var/OptimalTempMin = C.OptimalTempMin // Lower area of bell curve for determining heat based rate reactions - var/OptimalTempMax = C.OptimalTempMax - var/ExplodeTemp = C.ExplodeTemp - var/OptimalpHMin = C.OptimalpHMin - var/OptimalpHMax = C.OptimalpHMax - var/ReactpHLim = C.ReactpHLim - //var/CatalystFact = C.CatalystFact - var/CurveSharpT = C.CurveSharpT - var/CurveSharppH = C.CurveSharppH - var/ThermicConstant = C.ThermicConstant - var/HIonRelease = C.HIonRelease - var/RateUpLim = C.RateUpLim - var/FermiChem = C.FermiChem - var/FermiExplode = C.FermiExplode - var/ImpureChem = C.ImpureChem - */ - //FermiChem - - for(var/B in cached_required_reagents) - if(!has_reagent(B, cached_required_reagents[B])) - break - total_matching_reagents++ - for(var/B in cached_required_catalysts) - if(!has_reagent(B, cached_required_catalysts[B])) - break - total_matching_catalysts++ - if(cached_my_atom) - if(!C.required_container) - matching_container = 1 - - else - if(cached_my_atom.type == C.required_container)//if the suspected container is a container - matching_container = 1 - if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs - return - if(!C.required_other)//Checks for other things required - matching_other = 1//binary check passes - - else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem - var/obj/item/slime_extract/M = cached_my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 - else - if(!C.required_container)//I'm not sure why this is here twice, I think if it's not a beaker? Oh, cyro. - matching_container = 1 - if(!C.required_other) - matching_other = 1 - - //FermiChem - if (chem_temp > C.ExplodeTemp)//Check to see if reaction is too hot! - if (C.FermiExplode == TRUE) - //To be added! - else - FermiExplode() - //explode function!! - - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! - meets_temp_requirement = 1//binary pass - - if(!has_special_react || C.check_special_react(src)) - can_special_react = 1 - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) - possible_reactions += C - - if(possible_reactions.len)//does list exist? - var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions)//why V, surely that would indicate volume? V is the reaction potential. - var/datum/chemical_reaction/competitor = V //competitor? I think this is theres two of them. Troubling..! - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. - if(competitor.required_temp <= selected_reaction.required_temp)//only returns with lower if reaction "is cold" var. - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor - var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list - var/list/cached_results = selected_reaction.results//resultant chemical list - var/special_react_result = selected_reaction.check_special_react(src) - var/list/multiplier = INFINITY //Wat - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. - //FermiChem relies on two additional properties; pH and impurity - //Temperature plays into a larger role too. - //if(selected_reaction) - var/datum/chemical_reaction/C = selected_reaction - if (C.FermiChem == TRUE) - //FermiReact(C) - //B is Beaker - //P is product - //multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - var/ammoReacted = 0 - //get purity from combined beaker reactant purities. - var/purity = 1 - - - while (ammoReacted < multiplier) - message_admins("Loop beginning") - CHECK_TICK - //Begin Parse - - //Check extremes first - if (chem_temp > C.ExplodeTemp) - //go to explode proc - message_admins("temperature is over limit: [C.ExplodeTemp] Current temperature: [chem_temp]") - FermiExplode() - - if (pH > 14 || pH < 0) - //Create chemical sludge eventually(for now just destroy the beaker I guess?) - //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) - message_admins("pH is lover limit, cur pH: [pH]") - FermiExplode() - - //For now, purity is handled elsewhere - - //Calculate DeltaT (Deviation of T from optimal) - if (chem_temp < C.OptimalTempMax || chem_temp >= C.OptimalTempMin) - deltaT = (((C.OptimalTempMin - chem_temp)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT)) - // 350 300 - else if (chem_temp >= C.OptimalTempMax) - deltaT = 1 - else - deltaT = 0 - message_admins("calculating temperature factor, min: [C.OptimalTempMin], max: [C.OptimalTempMax], Exponential: [C.CurveSharpT], deltaT: [deltaT]") - - //Calculate DeltapH (Deviation of pH from optimal) - //Lower range - if (pH < C.OptimalpHMin) - if (pH < (C.OptimalpHMin - C.ReactpHLim)) - deltapH = 0 - else - deltapH = (((pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH)) - //Upper range - else if (pH > C.OptimalpHMin) - if (pH > (C.OptimalpHMin + C.ReactpHLim)) - deltapH = 0 - else - deltapH = ((C.ReactpHLim -(pH - (C.OptimalpHMax + C.ReactpHLim))+C.ReactpHLim)/(C.ReactpHLim**C.CurveSharppH)) - //Within mid range - else if (pH >= C.OptimalpHMin && pH <= C.OptimalpHMax) - deltapH = 1 - //This should never proc: - else - message_admins("Fermichem's pH broke!! Please let Fermis know!!") - WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])") - //TODO Add CatalystFact - message_admins("calculating pH factor(purity), pH: [pH], min: [C.OptimalpHMin]-[C.ReactpHLim], max: [C.OptimalpHMax]+[C.ReactpHLim], deltapH: [deltapH]") - - stepChemAmmount = multiplier * deltaT - if (stepChemAmmount > C.RateUpLim) - stepChemAmmount = C.RateUpLim - else if (stepChemAmmount < 0.01) - stepChemAmmount = 0.1 - if (ammoReacted > 0) - purity = ((purity * ammoReacted) + (deltapH * stepChemAmmount)) /((ammoReacted + stepChemAmmount)) //This should add the purity to the product - else - purity = deltapH - message_admins("purity: [purity], purity of beaker") - message_admins("Temp before change: [chem_temp], pH after change: [pH]") - //Apply pH changes and thermal output of reaction to beaker - chem_temp += (C.ThermicConstant * stepChemAmmount) - pH += (C.HIonRelease * stepChemAmmount) - message_admins("Temp after change: [chem_temp], pH after change: [pH]") - - // End. - - selected_reaction.on_reaction(src, multiplier, special_react_result) - - message_admins("cached_results: [cached_results], multiplier: [multiplier], stepChemAmmount [stepChemAmmount]") - for(var/B in cached_required_reagents) - message_admins("cached_results: [cached_results], multiplier: [multiplier], stepChemAmmount [stepChemAmmount]") - remove_reagent(B, (stepChemAmmount * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmmount, P)//log - add_reagent(P, cached_results[P]*stepChemAmmount, null, chem_temp)//add reagent function!! I THINK I can do this: - - ammoReacted = ammoReacted + stepChemAmmount - CHECK_TICK - - reaction_occurred = 1 - SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", ammoReacted, C.id)//log - //Standard reaction mechanics: - else: - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log - add_reagent(P, cached_results[P]*multiplier, null, chem_temp)//add reagent function!! I THINK I can do this: - - - var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers - 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, 1) - - for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - - if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 - - while(reaction_occurred)//while do nothing? - update_total()//Don't know waht this does. - return 0//end! - -/datum/reagents/proc/FermiReact() - return - -/datum/reagents/proc/FermiExplode() - return - -/datum/reagents/proc/isolate_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id != reagent) - del_reagent(R.id) - update_total() - -/datum/reagents/proc/del_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id == reagent) - if(my_atom && isliving(my_atom)) - var/mob/living/M = my_atom - R.on_mob_delete(M) - qdel(R) - reagent_list -= R - update_total() - if(my_atom) - my_atom.on_reagent_change(DEL_REAGENT) - return 1 - -/datum/reagents/proc/update_total() - var/list/cached_reagents = reagent_list - total_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume < 0.1) - del_reagent(R.id) - else - total_volume += R.volume - - return 0 - -/datum/reagents/proc/clear_reagents() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - del_reagent(R.id) - return 0 - -/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1) - var/react_type - if(isliving(A)) - react_type = "LIVING" - if(method == INGEST) - var/mob/living/L = A - L.taste(src) - else if(isturf(A)) - react_type = "TURF" - else if(isobj(A)) - react_type = "OBJ" - else - return - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - switch(react_type) - if("LIVING") - var/touch_protection = 0 - if(method == VAPOR) - var/mob/living/L = A - touch_protection = L.get_permeability_protection() - R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection) - if("TURF") - R.reaction_turf(A, R.volume * volume_modifier, show_message) - if("OBJ") - R.reaction_obj(A, R.volume * volume_modifier, show_message) - -/datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE - -//Returns the average specific heat for all reagents currently in this holder. -/datum/reagents/proc/specific_heat() - . = 0 - var/cached_amount = total_volume //cache amount - var/list/cached_reagents = reagent_list //cache reagents - for(var/I in cached_reagents) - var/datum/reagent/R = I - . += R.specific_heat * (R.volume / cached_amount) - -/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) - var/S = specific_heat() - chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000) - -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, pH = 7, no_react = 0)//EDIT HERE TOO ~FERMICHEM~ - if(!isnum(amount) || !amount) - return FALSE - - if(amount <= 0) - return FALSE - - var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] - if(!D) - WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") - return FALSE - - update_total() - var/cached_total = total_volume - if(cached_total + amount > maximum_volume) - amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. - if(amount <= 0) - return FALSE - var/new_total = cached_total + amount - var/cached_temp = chem_temp - var/list/cached_reagents = reagent_list - - //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. - var/specific_heat = 0 - var/thermal_energy = 0 - for(var/i in cached_reagents) - var/datum/reagent/R = i - specific_heat += R.specific_heat * (R.volume / new_total) - thermal_energy += R.specific_heat * R.volume * cached_temp - specific_heat += D.specific_heat * (amount / new_total) - thermal_energy += D.specific_heat * amount * reagtemp - chem_temp = thermal_energy / (specific_heat * new_total) - //// - - //add the reagent to the existing if it exists - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) - if(!no_react) - handle_reactions() - return TRUE - - //otherwise make a new one - var/datum/reagent/R = new D.type(data) - cached_reagents += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - if(!no_react) - handle_reactions() - return TRUE - -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(isnull(amount)) - amount = 0 - CRASH("null amount passed to reagent code") - return FALSE - - if(!isnum(amount)) - return FALSE - - if(amount < 0) - return FALSE - - var/list/cached_reagents = reagent_list - - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - //clamp the removal amount to be between current reagent amount - //and zero, to prevent removing more than the holder has stored - amount = CLAMP(amount, 0, R.volume) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - if(my_atom) - my_atom.on_reagent_change(REM_REAGENT) - return TRUE - - return FALSE - -/datum/reagents/proc/has_reagent(reagent, amount = -1) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - if(!amount) - return R - else - if(R.volume >= amount) - return R - else - return 0 - - return 0 - -/datum/reagents/proc/get_reagent_amount(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - return R.volume - - return 0 - -/datum/reagents/proc/get_reagents() - var/list/names = list() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - names += R.name - - return jointext(names, ",") - -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. - if(!isnum(amount)) - return 1 - var/list/cached_reagents = reagent_list - var/has_removed_reagent = 0 - - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.id, amount, safety) - - return has_removed_reagent - -//two helper functions to preserve data across reactions (needed for xenoarch) -/datum/reagents/proc/get_data(reagent_id) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - return R.data - -/datum/reagents/proc/set_data(reagent_id, new_data) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - R.data = new_data - -/datum/reagents/proc/copy_data(datum/reagent/current_reagent) - if(!current_reagent || !current_reagent.data) - return null - if(!istype(current_reagent.data, /list)) - return current_reagent.data - - var/list/trans_data = current_reagent.data.Copy() - - // We do this so that introducing a virus to a blood sample - // doesn't automagically infect all other blood samples from - // the same donor. - // - // Technically we should probably copy all data lists, but - // that could possibly eat up a lot of memory needlessly - // if most data lists are read-only. - if(trans_data["viruses"]) - var/list/v = trans_data["viruses"] - trans_data["viruses"] = v.Copy() - - return trans_data - -/datum/reagents/proc/get_reagent(type) - var/list/cached_reagents = reagent_list - . = locate(type) in cached_reagents - -/datum/reagents/proc/generate_taste_message(minimum_percent=15) - // the lower the minimum percent, the more sensitive the message is. - var/list/out = list() - var/list/tastes = list() //descriptor = strength - if(minimum_percent <= 100) - for(var/datum/reagent/R in reagent_list) - if(!R.taste_mult) - continue - - if(istype(R, /datum/reagent/consumable/nutriment)) - var/list/taste_data = R.data - for(var/taste in taste_data) - var/ratio = taste_data[taste] - var/amount = ratio * R.taste_mult * R.volume - if(taste in tastes) - tastes[taste] += amount - else - tastes[taste] = amount - else - var/taste_desc = R.taste_description - var/taste_amount = R.volume * R.taste_mult - if(taste_desc in tastes) - tastes[taste_desc] += taste_amount - else - tastes[taste_desc] = taste_amount - //deal with percentages - // TODO it would be great if we could sort these from strong to weak - var/total_taste = counterlist_sum(tastes) - if(total_taste > 0) - for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue - var/intensity_desc = "a hint of" - if(percent > minimum_percent * 2 || percent == 100) - intensity_desc = "" - else if(percent > minimum_percent * 3) - intensity_desc = "the strong flavor of" - if(intensity_desc != "") - out += "[intensity_desc] [taste_desc]" - else - out += "[taste_desc]" - - return english_list(out, "something indescribable") - -/datum/reagents/proc/expose_temperature(var/temperature, var/coeff=0.02) - var/temp_delta = (temperature - chem_temp) * coeff - if(temp_delta > 0) - chem_temp = min(chem_temp + max(temp_delta, 1), temperature) - else - chem_temp = max(chem_temp + min(temp_delta, -1), temperature) - chem_temp = round(chem_temp) - handle_reactions() - -/////////////////////////////////////////////////////////////////////////////////// - - -// Convenience proc to create a reagents holder for an atom -// Max vol is maximum volume of holder -/atom/proc/create_reagents(max_vol) - if(reagents) - qdel(reagents) - reagents = new/datum/reagents(max_vol) - reagents.my_atom = src - -/proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents - var/static/list/random_reagents = list() - if(!random_reagents.len) - for(var/thing in subtypesof(/datum/reagent)) - var/datum/reagent/R = thing - if(initial(R.can_synth)) - random_reagents += initial(R.id) - var/picked_reagent = pick(random_reagents) - return picked_reagent \ No newline at end of file diff --git a/code/modules/reagents/chemistry/holderBackup.dm b/code/modules/reagents/chemistry/holderBackup.dm deleted file mode 100644 index b434b348f0..0000000000 --- a/code/modules/reagents/chemistry/holderBackup.dm +++ /dev/null @@ -1,952 +0,0 @@ - -/proc/build_chemical_reagent_list() - //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id - - if(GLOB.chemical_reagents_list) - return - - var/paths = subtypesof(/datum/reagent) - GLOB.chemical_reagents_list = list() - - for(var/path in paths) - var/datum/reagent/D = new path() - GLOB.chemical_reagents_list[D.id] = D - -/proc/build_chemical_reactions_list() - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list - // It is filtered into multiple lists within a list. - // For example: - // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma - - if(GLOB.chemical_reactions_list) - return - - var/paths = subtypesof(/datum/chemical_reaction) - GLOB.chemical_reactions_list = list() - - for(var/path in paths) - - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() - - if(D.required_reagents && D.required_reagents.len) - for(var/reaction in D.required_reagents) - reaction_ids += reaction - - // Create filters based on each reagent id in the required reagents list - for(var/id in reaction_ids) - if(!GLOB.chemical_reactions_list[id]) - GLOB.chemical_reactions_list[id] = list() - GLOB.chemical_reactions_list[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant - -/////////////////////////////////////////////////////////////////////////////////// - -/datum/reagents - var/list/datum/reagent/reagent_list = new/list() - var/total_volume = 0 - var/maximum_volume = 100 - var/atom/my_atom = null - var/chem_temp = 150 - var/pH = REAGENT_NORMAL_PH - var/last_tick = 1 - var/addiction_tick = 1 - var/list/datum/reagent/addiction_list = new/list() - var/reagents_holder_flags - -/datum/reagents/New(maximum=100) - maximum_volume = maximum - - //I dislike having these here but map-objects are initialised before world/New() is called. >_> - if(!GLOB.chemical_reagents_list) - build_chemical_reagent_list() - if(!GLOB.chemical_reactions_list) - build_chemical_reactions_list() - -/datum/reagents/Destroy() - . = ..() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - qdel(R) - cached_reagents.Cut() - cached_reagents = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null - my_atom = null - -// Used in attack logs for reagents in pills and such -/datum/reagents/proc/log_list() - if(!length(reagent_list)) - return "no reagents" - - var/list/data = list() - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.id] ([round(R.volume, 0.1)]u)" - //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. - return english_list(data) - -/datum/reagents/proc/remove_any(amount = 1) - var/list/cached_reagents = reagent_list - var/total_transfered = 0 - var/current_list_element = 1 - - current_list_element = rand(1, cached_reagents.len) - - while(total_transfered != amount) - if(total_transfered >= amount) - break - if(total_volume <= 0 || !cached_reagents.len) - break - - if(current_list_element > cached_reagents.len) - current_list_element = 1 - - var/datum/reagent/R = cached_reagents[current_list_element] - remove_reagent(R.id, 1) - - current_list_element++ - total_transfered++ - update_total() - - handle_reactions() - return total_transfered - -/datum/reagents/proc/remove_all(amount = 1) - var/list/cached_reagents = reagent_list - if(total_volume > 0) - var/part = amount / total_volume - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - remove_reagent(R.id, R.volume * part) - - update_total() - handle_reactions() - return amount - -/datum/reagents/proc/get_master_reagent_name() - var/list/cached_reagents = reagent_list - var/name - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - name = R.name - - return name - -/datum/reagents/proc/get_master_reagent_id() - var/list/cached_reagents = reagent_list - var/id - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - id = R.id - - return id - -/datum/reagents/proc/get_master_reagent() - var/list/cached_reagents = reagent_list - var/datum/reagent/master - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - master = R - - return master - -/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - if(amount < 0) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/transfer_amount = T.volume * part - if(preserve_data) - trans_data = copy_data(T) - - //fermichem Added ph TODO: add T.purity - R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - //R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, T.purity, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - remove_reagent(T.id, transfer_amount) - - update_total() - R.update_total() - if(!no_react) - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - - if(amount < 0) - return - amount = min(min(amount, total_volume), R.maximum_volume-R.total_volume) - var/part = amount / total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/copy_amount = T.volume * part - if(preserve_data) - trans_data = T.data - R.add_reagent(T.id, copy_amount * multiplier, trans_data) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N - var/list/cached_reagents = reagent_list - if (!target) - return - if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) - return - if(amount < 0) - return - - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent)= R.overdose_threshold && !R.overdosed) - R.overdosed = 1 - need_mob_update += R.overdose_start(C) - if(R.addiction_threshold) - if(R.volume >= R.addiction_threshold && !is_type_in_list(R, cached_addictions)) - var/datum/reagent/new_reagent = new R.type() - cached_addictions.Add(new_reagent) - if(R.overdosed) - need_mob_update += R.overdose_process(C) - if(is_type_in_list(R,cached_addictions)) - for(var/addiction in cached_addictions) - var/datum/reagent/A = addiction - if(istype(R, A)) - A.addiction_stage = -15 // you're satisfied for a good while. - need_mob_update += R.on_mob_life(C) - - if(can_overdose) - if(addiction_tick == 6) - addiction_tick = 1 - for(var/addiction in cached_addictions) - var/datum/reagent/R = addiction - if(C && R) - R.addiction_stage++ - if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end) - need_mob_update += R.addiction_act_stage1(C) - else if(R.addiction_stage1_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end) - need_mob_update += R.addiction_act_stage2(C) - else if(R.addiction_stage2_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end) - need_mob_update += R.addiction_act_stage3(C) - else if(R.addiction_stage3_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end) - need_mob_update += R.addiction_act_stage4(C) - else if(R.addiction_stage4_end <= R.addiction_stage) - to_chat(C, "You feel like you've gotten over your need for [R.name].") - SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.id]_addiction") - cached_addictions.Remove(R) - addiction_tick++ - if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates. - C.updatehealth() - C.update_canmove() - C.update_stamina() - update_total() - - -/datum/reagents/proc/set_reacting(react = TRUE) - if(react) - reagents_holder_flags &= ~(REAGENT_NOREACT) - else - reagents_holder_flags |= REAGENT_NOREACT - -/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_move (A, Running) - update_total() - -/datum/reagents/proc/conditional_update(atom/A) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_update (A) - update_total() - -/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar - //FermiChem - var/purity = 1 - var/ammoReacted = 0 - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - - var/list/cached_reagents = reagent_list //a list of the reagents? - var/list/cached_reactions = GLOB.chemical_reactions_list //a list of the whole reactions? - var/datum/cached_my_atom = my_atom //It says my atom, but I didn't bring one with me!! - if(reagents_holder_flags & REAGENT_NOREACT) //Not sure on reagents_holder_flags, but I think it checks to see if theres a reaction with current stuff. - return //Yup, no reactions here. No siree. - - var/reaction_occurred = 0 // checks if reaction, binary variable - do //What does do do in byond? It sounds very redundant? is it a while loop? - var/list/possible_reactions = list() //init list - reaction_occurred = 0 // sets it back to 0? - for(var/reagent in cached_reagents) //for reagent in beaker/holder - var/datum/reagent/R = reagent //check to make sure that reagent is there for the reaction list - for(var/reaction in cached_reactions[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id - if(!reaction) - continue - - var/datum/chemical_reaction/C = reaction - var/list/cached_required_reagents = C.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 - var/list/cached_required_catalysts = C.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 - var/required_temp = C.required_temp - var/is_cold_recipe = C.is_cold_recipe - var/meets_temp_requirement = 0 - var/has_special_react = C.special_react - var/can_special_react = 0 - //FermiChem WHY ARE VARIBLES SO ESTRANGED it makes me sad - var/OptimalTempMin = C.OptimalTempMin // Lower area of bell curve for determining heat based rate reactions - var/OptimalTempMax = C.OptimalTempMax - var/ExplodeTemp = C.ExplodeTemp - var/OptimalpHMin = C.OptimalpHMin - var/OptimalpHMax = C.OptimalpHMax - var/ReactpHLim = C.ReactpHLim - //var/CatalystFact = C.CatalystFact - var/CurveSharpT = C.CurveSharpT - var/CurveSharppH = C.CurveSharppH - var/ThermicConstant = C.ThermicConstant - var/HIonRelease = C.HIonRelease - var/RateUpLim = C.RateUpLim - var/FermiChem = C.FermiChem - var/FermiExplode = C.FermiExplode - var/ImpureChem = C.ImpureChem - - //FermiChem - /* - var/purity = 1 - var/ammoReacted = 0 - - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - */ - - for(var/B in cached_required_reagents) - if(!has_reagent(B, cached_required_reagents[B])) - break - total_matching_reagents++ - for(var/B in cached_required_catalysts) - if(!has_reagent(B, cached_required_catalysts[B])) - break - total_matching_catalysts++ - if(cached_my_atom) - if(!C.required_container) - matching_container = 1 - - else - if(cached_my_atom.type == C.required_container)//if the suspected container is a container - matching_container = 1 - if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs - return - if(!C.required_other)//Checks for other things required - matching_other = 1//binary check passes - - else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem - var/obj/item/slime_extract/M = cached_my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 - else - if(!C.required_container)//I'm not sure why this is here twice, I think if it's not a beaker? Oh, cyro. - matching_container = 1 - if(!C.required_other) - matching_other = 1 - - //FermiChem - - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! - meets_temp_requirement = 1//binary pass - - if(!has_special_react || C.check_special_react(src)) - can_special_react = 1 - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) - possible_reactions += C - - if(possible_reactions.len)//does list exist? - var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions)//why V, surely that would indicate volume? V is the reaction potential. - var/datum/chemical_reaction/competitor = V //competitor? I think this is theres two of them. Troubling..! - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. - if(competitor.required_temp <= selected_reaction.required_temp)//only returns with lower if reaction "is cold" var. - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor - var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list - var/list/cached_results = selected_reaction.results//resultant chemical list - var/special_react_result = selected_reaction.check_special_react(src) - var/list/multiplier = INFINITY //Wat - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. - //FermiChem relies on two additional properties; pH and impurity - //Temperature plays into a larger role too. - if (C.FermiChem == TRUE) - message_admins("Hee!!!! Someone is doing a Fermi reaction!!! I'm so excited!!") - //FermiReact(C) - //B is Beaker - //P is product - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - while (ammoReacted < multiplier) - //Begin Parse - - //Check extremes first - if (chem_temp > ExplodeTemp) - //go to explode proc - FermiExplode() - - if (pH > 14 || pH < 0) - //Create chemical sludge eventually(for now just destroy the beaker I guess?) - //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) - FermiExplode() - - //For now, purity is handled elsewhere - - //Calculate DeltaT (Deviation of T from optimal) - if (chem_temp < C.OptimalTempMax) - deltaT = (((C.OptimalTempMin - chem_temp)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMax)**C.CurveSharpT)) - else if (chem_temp >= C.OptimalTempMax) - deltaT = 1 - else - deltaT = 0 - - //Calculate DeltapH (Deviation of pH from optimal) - //Lower range - if (pH < C.OptimalpHMin) - if (pH < (C.OptimalpHMin - C.ReactpHLim)) - deltapH = 0 - else - deltapH = (((pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharp)/(C.ReactpHLim**C.CurveSharppH)) - //Upper range - else if (pH > C.OptimalpHMin) - if (pH > (C.OptimalpHMin + C.ReactpHLim)) - deltapH = 0 - else - deltapH = ((C.ReactpHLim -(pH - (C.OptimalpHMax + C.ReactpHLim))+C.ReactpHLim)/(C.ReactpHLim**C.CurveSharppH)) - //Within mid range - else if (pH >= C.OptimalpHMin && pH <= C.OptimalpHMax) - deltapH = 1 - //This should never proc: - else - message_admins("Fermichem's pH broke!! Please let Fermis know!!") - WARNING("[my_atom] attempted to determine FermiChem pH for '[reagent]' which broke for some reason! ([usr])") - //TODO Add CatalystFact - - stepChemAmmount = multiplier * deltaT - if (ammoReacted > 0) - P.purity = ((P.purity * ammoReacted) + (deltapH * stepChemAmmount)) /(2 * (ammoReacted + stepChemAmmount)) //This should add the purity to the product - else - P.purity = deltapH - //Apply pH changes and thermal output of reaction to beaker - chem_temp += (C.ThermicConstant * stepChemAmmount) - pH += (C.HIonRelease * stepChemAmmount) - - // End. - - selected_reaction.on_reaction(src, multiplier, special_react_result) - - for(var/B in cached_required_reagents) - remove_reagent(B, (stepChemAmmount * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmmount, P)//log - add_reagent(P, cached_results[P]*stepChemAmmount, null, chem_temp)//add reagent function!! I THINK I can do this: - - - ammoReacted = ammoReacted + stepChemAmmount - - reaction_occurred = 1 - SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", cached_results[P]*ammoReacted, P)//log - //Standard reaction mechanics: - else: - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log - add_reagent(P, cached_results[P]*multiplier, null, chem_temp)//add reagent function!! I THINK I can do this: - - - var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers - 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, 1) - - for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - - if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 - - while(reaction_occurred)//while do nothing? - update_total()//Don't know waht this does. - return 0//end! - -/datum/reagents/proc/FermiReact() - return - -/datum/reagents/proc/FermiExplode() - return - -/datum/reagents/proc/isolate_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id != reagent) - del_reagent(R.id) - update_total() - -/datum/reagents/proc/del_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id == reagent) - if(my_atom && isliving(my_atom)) - var/mob/living/M = my_atom - R.on_mob_delete(M) - qdel(R) - reagent_list -= R - update_total() - if(my_atom) - my_atom.on_reagent_change(DEL_REAGENT) - return 1 - -/datum/reagents/proc/update_total() - var/list/cached_reagents = reagent_list - total_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume < 0.1) - del_reagent(R.id) - else - total_volume += R.volume - - return 0 - -/datum/reagents/proc/clear_reagents() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - del_reagent(R.id) - return 0 - -/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1) - var/react_type - if(isliving(A)) - react_type = "LIVING" - if(method == INGEST) - var/mob/living/L = A - L.taste(src) - else if(isturf(A)) - react_type = "TURF" - else if(isobj(A)) - react_type = "OBJ" - else - return - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - switch(react_type) - if("LIVING") - var/touch_protection = 0 - if(method == VAPOR) - var/mob/living/L = A - touch_protection = L.get_permeability_protection() - R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection) - if("TURF") - R.reaction_turf(A, R.volume * volume_modifier, show_message) - if("OBJ") - R.reaction_obj(A, R.volume * volume_modifier, show_message) - -/datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE - -//Returns the average specific heat for all reagents currently in this holder. -/datum/reagents/proc/specific_heat() - . = 0 - var/cached_amount = total_volume //cache amount - var/list/cached_reagents = reagent_list //cache reagents - for(var/I in cached_reagents) - var/datum/reagent/R = I - . += R.specific_heat * (R.volume / cached_amount) - -/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) - var/S = specific_heat() - chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000) - -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, pH = 7, no_react = 0)//EDIT HERE TOO ~FERMICHEM~ - if(!isnum(amount) || !amount) - return FALSE - - if(amount <= 0) - return FALSE - - var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] - if(!D) - WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") - return FALSE - - update_total() - var/cached_total = total_volume - if(cached_total + amount > maximum_volume) - amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. - if(amount <= 0) - return FALSE - var/new_total = cached_total + amount - var/cached_temp = chem_temp - var/list/cached_reagents = reagent_list - - //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. - var/specific_heat = 0 - var/thermal_energy = 0 - for(var/i in cached_reagents) - var/datum/reagent/R = i - specific_heat += R.specific_heat * (R.volume / new_total) - thermal_energy += R.specific_heat * R.volume * cached_temp - specific_heat += D.specific_heat * (amount / new_total) - thermal_energy += D.specific_heat * amount * reagtemp - chem_temp = thermal_energy / (specific_heat * new_total) - //// - - //add the reagent to the existing if it exists - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) - if(!no_react) - handle_reactions() - return TRUE - - //otherwise make a new one - var/datum/reagent/R = new D.type(data) - cached_reagents += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - if(!no_react) - handle_reactions() - return TRUE - -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(isnull(amount)) - amount = 0 - CRASH("null amount passed to reagent code") - return FALSE - - if(!isnum(amount)) - return FALSE - - if(amount < 0) - return FALSE - - var/list/cached_reagents = reagent_list - - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - //clamp the removal amount to be between current reagent amount - //and zero, to prevent removing more than the holder has stored - amount = CLAMP(amount, 0, R.volume) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - if(my_atom) - my_atom.on_reagent_change(REM_REAGENT) - return TRUE - - return FALSE - -/datum/reagents/proc/has_reagent(reagent, amount = -1) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - if(!amount) - return R - else - if(R.volume >= amount) - return R - else - return 0 - - return 0 - -/datum/reagents/proc/get_reagent_amount(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - return R.volume - - return 0 - -/datum/reagents/proc/get_reagents() - var/list/names = list() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - names += R.name - - return jointext(names, ",") - -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. - if(!isnum(amount)) - return 1 - var/list/cached_reagents = reagent_list - var/has_removed_reagent = 0 - - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.id, amount, safety) - - return has_removed_reagent - -//two helper functions to preserve data across reactions (needed for xenoarch) -/datum/reagents/proc/get_data(reagent_id) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - return R.data - -/datum/reagents/proc/set_data(reagent_id, new_data) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - R.data = new_data - -/datum/reagents/proc/copy_data(datum/reagent/current_reagent) - if(!current_reagent || !current_reagent.data) - return null - if(!istype(current_reagent.data, /list)) - return current_reagent.data - - var/list/trans_data = current_reagent.data.Copy() - - // We do this so that introducing a virus to a blood sample - // doesn't automagically infect all other blood samples from - // the same donor. - // - // Technically we should probably copy all data lists, but - // that could possibly eat up a lot of memory needlessly - // if most data lists are read-only. - if(trans_data["viruses"]) - var/list/v = trans_data["viruses"] - trans_data["viruses"] = v.Copy() - - return trans_data - -/datum/reagents/proc/get_reagent(type) - var/list/cached_reagents = reagent_list - . = locate(type) in cached_reagents - -/datum/reagents/proc/generate_taste_message(minimum_percent=15) - // the lower the minimum percent, the more sensitive the message is. - var/list/out = list() - var/list/tastes = list() //descriptor = strength - if(minimum_percent <= 100) - for(var/datum/reagent/R in reagent_list) - if(!R.taste_mult) - continue - - if(istype(R, /datum/reagent/consumable/nutriment)) - var/list/taste_data = R.data - for(var/taste in taste_data) - var/ratio = taste_data[taste] - var/amount = ratio * R.taste_mult * R.volume - if(taste in tastes) - tastes[taste] += amount - else - tastes[taste] = amount - else - var/taste_desc = R.taste_description - var/taste_amount = R.volume * R.taste_mult - if(taste_desc in tastes) - tastes[taste_desc] += taste_amount - else - tastes[taste_desc] = taste_amount - //deal with percentages - // TODO it would be great if we could sort these from strong to weak - var/total_taste = counterlist_sum(tastes) - if(total_taste > 0) - for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue - var/intensity_desc = "a hint of" - if(percent > minimum_percent * 2 || percent == 100) - intensity_desc = "" - else if(percent > minimum_percent * 3) - intensity_desc = "the strong flavor of" - if(intensity_desc != "") - out += "[intensity_desc] [taste_desc]" - else - out += "[taste_desc]" - - return english_list(out, "something indescribable") - -/datum/reagents/proc/expose_temperature(var/temperature, var/coeff=0.02) - var/temp_delta = (temperature - chem_temp) * coeff - if(temp_delta > 0) - chem_temp = min(chem_temp + max(temp_delta, 1), temperature) - else - chem_temp = max(chem_temp + min(temp_delta, -1), temperature) - chem_temp = round(chem_temp) - handle_reactions() - -/////////////////////////////////////////////////////////////////////////////////// - - -// Convenience proc to create a reagents holder for an atom -// Max vol is maximum volume of holder -/atom/proc/create_reagents(max_vol) - if(reagents) - qdel(reagents) - reagents = new/datum/reagents(max_vol) - reagents.my_atom = src - -/proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents - var/static/list/random_reagents = list() - if(!random_reagents.len) - for(var/thing in subtypesof(/datum/reagent)) - var/datum/reagent/R = thing - if(initial(R.can_synth)) - random_reagents += initial(R.id) - var/picked_reagent = pick(random_reagents) - return picked_reagent diff --git a/code/modules/reagents/chemistry/holderProcBackup.dm b/code/modules/reagents/chemistry/holderProcBackup.dm deleted file mode 100644 index 02ebbc5096..0000000000 --- a/code/modules/reagents/chemistry/holderProcBackup.dm +++ /dev/null @@ -1,1003 +0,0 @@ - -/proc/build_chemical_reagent_list() - //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id - - if(GLOB.chemical_reagents_list) - return - - var/paths = subtypesof(/datum/reagent) - GLOB.chemical_reagents_list = list() - - for(var/path in paths) - var/datum/reagent/D = new path() - GLOB.chemical_reagents_list[D.id] = D - -/proc/build_chemical_reactions_list() - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list - // It is filtered into multiple lists within a list. - // For example: - // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma - - if(GLOB.chemical_reactions_list) - return - - var/paths = subtypesof(/datum/chemical_reaction) - GLOB.chemical_reactions_list = list() - - for(var/path in paths) - - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() - - if(D.required_reagents && D.required_reagents.len) - for(var/reaction in D.required_reagents) - reaction_ids += reaction - - // Create filters based on each reagent id in the required reagents list - for(var/id in reaction_ids) - if(!GLOB.chemical_reactions_list[id]) - GLOB.chemical_reactions_list[id] = list() - GLOB.chemical_reactions_list[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant - -/////////////////////////////////////////////////////////////////////////////////// - -/datum/reagents - var/list/datum/reagent/reagent_list = new/list() - var/total_volume = 0 - var/maximum_volume = 100 - var/atom/my_atom = null - var/chem_temp = 150 - var/pH = REAGENT_NORMAL_PH - var/last_tick = 1 - var/addiction_tick = 1 - var/list/datum/reagent/addiction_list = new/list() - var/reagents_holder_flags - var/targetVol = 0 - var/reactedVol = 0 - var/fermiIsReacting = FALSE - var/fermiReactID = null - -/datum/reagents/New(maximum=100) - maximum_volume = maximum - - //I dislike having these here but map-objects are initialised before world/New() is called. >_> - if(!GLOB.chemical_reagents_list) - build_chemical_reagent_list() - if(!GLOB.chemical_reactions_list) - build_chemical_reactions_list() - -/datum/reagents/Destroy() - . = ..() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - qdel(R) - cached_reagents.Cut() - cached_reagents = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null - my_atom = null - -// Used in attack logs for reagents in pills and such -/datum/reagents/proc/log_list() - if(!length(reagent_list)) - return "no reagents" - - var/list/data = list() - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.id] ([round(R.volume, 0.1)]u)" - //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. - return english_list(data) - -/datum/reagents/proc/remove_any(amount = 1) - var/list/cached_reagents = reagent_list - var/total_transfered = 0 - var/current_list_element = 1 - - current_list_element = rand(1, cached_reagents.len) - - while(total_transfered != amount) - if(total_transfered >= amount) - break - if(total_volume <= 0 || !cached_reagents.len) - break - - if(current_list_element > cached_reagents.len) - current_list_element = 1 - - var/datum/reagent/R = cached_reagents[current_list_element] - remove_reagent(R.id, 1) - - current_list_element++ - total_transfered++ - update_total() - - handle_reactions() - return total_transfered - -/datum/reagents/proc/remove_all(amount = 1) - var/list/cached_reagents = reagent_list - if(total_volume > 0) - var/part = amount / total_volume - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - remove_reagent(R.id, R.volume * part) - - update_total() - handle_reactions() - return amount - -/datum/reagents/proc/get_master_reagent_name() - var/list/cached_reagents = reagent_list - var/name - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - name = R.name - - return name - -/datum/reagents/proc/get_master_reagent_id() - var/list/cached_reagents = reagent_list - var/id - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - id = R.id - - return id - -/datum/reagents/proc/get_master_reagent() - var/list/cached_reagents = reagent_list - var/datum/reagent/master - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - master = R - - return master - -/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - if(amount < 0) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/transfer_amount = T.volume * part - if(preserve_data) - trans_data = copy_data(T) - - //fermichem Added ph TODO: add T.purity - R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - //R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, T.purity, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - remove_reagent(T.id, transfer_amount) - - update_total() - R.update_total() - if(!no_react) - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - - if(amount < 0) - return - amount = min(min(amount, total_volume), R.maximum_volume-R.total_volume) - var/part = amount / total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/copy_amount = T.volume * part - if(preserve_data) - trans_data = T.data - R.add_reagent(T.id, copy_amount * multiplier, trans_data) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N - var/list/cached_reagents = reagent_list - if (!target) - return - if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) - return - if(amount < 0) - return - - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent)= R.overdose_threshold && !R.overdosed) - R.overdosed = 1 - need_mob_update += R.overdose_start(C) - if(R.addiction_threshold) - if(R.volume >= R.addiction_threshold && !is_type_in_list(R, cached_addictions)) - var/datum/reagent/new_reagent = new R.type() - cached_addictions.Add(new_reagent) - if(R.overdosed) - need_mob_update += R.overdose_process(C) - if(is_type_in_list(R,cached_addictions)) - for(var/addiction in cached_addictions) - var/datum/reagent/A = addiction - if(istype(R, A)) - A.addiction_stage = -15 // you're satisfied for a good while. - need_mob_update += R.on_mob_life(C) - - if(can_overdose) - if(addiction_tick == 6) - addiction_tick = 1 - for(var/addiction in cached_addictions) - var/datum/reagent/R = addiction - if(C && R) - R.addiction_stage++ - if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end) - need_mob_update += R.addiction_act_stage1(C) - else if(R.addiction_stage1_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end) - need_mob_update += R.addiction_act_stage2(C) - else if(R.addiction_stage2_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end) - need_mob_update += R.addiction_act_stage3(C) - else if(R.addiction_stage3_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end) - need_mob_update += R.addiction_act_stage4(C) - else if(R.addiction_stage4_end <= R.addiction_stage) - to_chat(C, "You feel like you've gotten over your need for [R.name].") - SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.id]_addiction") - cached_addictions.Remove(R) - addiction_tick++ - if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates. - C.updatehealth() - C.update_canmove() - C.update_stamina() - update_total() - - -/datum/reagents/proc/set_reacting(react = TRUE) - if(react) - reagents_holder_flags &= ~(REAGENT_NOREACT) - else - reagents_holder_flags |= REAGENT_NOREACT - -/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_move (A, Running) - update_total() - -/datum/reagents/proc/conditional_update(atom/A) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_update (A) - update_total() - -/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar - var/list/cached_reagents = reagent_list //a list of the reagents? - var/list/cached_reactions = GLOB.chemical_reactions_list //a list of the whole reactions? - var/datum/cached_my_atom = my_atom //It says my atom, but I didn't bring one with me!! - if(reagents_holder_flags & REAGENT_NOREACT) //Not sure on reagents_holder_flags, but I think it checks to see if theres a reaction with current stuff. - return //Yup, no reactions here. No siree. - - var/reaction_occurred = 0 // checks if reaction, binary variable - var/continue_reacting = FALSE //Helps keep track what kind of reaction is occuring; standard or fermi. - - if(fermiIsReacting == TRUE) - if (reactedVol >= targetVol && targetVol != 0) - STOP_PROCESSING(SSfastprocess, src) - fermiIsReacting = FALSE - message_admins("FermiChem processing stopped") - reaction_occurred = 1 - return - - - - do //What does do do in byond? It sounds very redundant? is it a while loop? - var/list/possible_reactions = list() //init list - reaction_occurred = 0 // sets it back to 0? - for(var/reagent in cached_reagents) //for reagent in beaker/holder - var/datum/reagent/R = reagent //check to make sure that reagent is there for the reaction list - for(var/reaction in cached_reactions[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id - if(!reaction) - continue - - var/datum/chemical_reaction/C = reaction - var/list/cached_required_reagents = C.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 - var/list/cached_required_catalysts = C.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 - var/required_temp = C.required_temp - var/is_cold_recipe = C.is_cold_recipe - var/meets_temp_requirement = 0 - var/has_special_react = C.special_react - var/can_special_react = 0 - - - for(var/B in cached_required_reagents) - if(!has_reagent(B, cached_required_reagents[B])) - break - total_matching_reagents++ - for(var/B in cached_required_catalysts) - if(!has_reagent(B, cached_required_catalysts[B])) - break - total_matching_catalysts++ - if(cached_my_atom) - if(!C.required_container) - matching_container = 1 - - else - if(cached_my_atom.type == C.required_container)//if the suspected container is a container - matching_container = 1 - if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs - return - if(!C.required_other)//Checks for other things required - matching_other = 1//binary check passes - - else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem - var/obj/item/slime_extract/M = cached_my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 - else - if(!C.required_container)//I'm not sure why this is here twice, I think if it's not a beaker? Oh, cyro. - matching_container = 1 - if(!C.required_other) - matching_other = 1 - - //FermiChem - /* - if (chem_temp > C.ExplodeTemp)//Check to see if reaction is too hot! - if (C.FermiExplode == TRUE) - //To be added! - else - FermiExplode() - //explode function!! - */ - - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! - meets_temp_requirement = 1//binary pass - - if(!has_special_react || C.check_special_react(src)) - can_special_react = 1 - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) - possible_reactions += C - - if(possible_reactions.len)//does list exist? - var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions)//why V, surely that would indicate volume? V is the reaction potential. - var/datum/chemical_reaction/competitor = V //competitor? I think this is theres two of them. Troubling..! - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. - if(competitor.required_temp <= selected_reaction.required_temp)//only returns with lower if reaction "is cold" var. - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor - var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list - var/list/cached_results = selected_reaction.results//resultant chemical list - var/special_react_result = selected_reaction.check_special_react(src) - var/list/multiplier = INFINITY //Wat - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. - //FermiChem relies on two additional properties; pH and impurity - //Temperature plays into a larger role too. - //BRANCH HERE - //if(selected_reaction) - var/datum/chemical_reaction/C = selected_reaction - - if (C.FermiChem == TRUE && !continue_reacting) - message_admins("FermiChem Proc'd") - reaction_occurred = 1 - - for(var/P in selected_reaction.results) - targetVol = cached_results[P]*multiplier - - if (chem_temp > C.OptimalTempMin)//To prevent pointless reactions - if (reactedVol < targetVol) - //reactedVol = FermiReact(selected_reaction, chem_temp, pH, multiplier, reactedVol, targetVol, cached_required_reagents, cached_results) - START_PROCESSING(SSfastprocess, src) - message_admins("FermiChem processing started") - fermiIsReacting = TRUE - fermiReactID = selected_reaction - else - fermiIsReacting = FALSE - STOP_PROCESSING(SSfastprocess, src) - else - return - - - SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", reactedVol, C.id)//log - - //Standard reaction mechanics: - else - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log - add_reagent(P, cached_results[P]*multiplier, null, chem_temp)//add reagent function!! I THINK I can do this: - - - var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers - 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, 1) - - for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - - if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 - continue_reacting = TRUE - - while(reaction_occurred)//while do nothing? - update_total()//Don't know waht this does. - return 0//end! - -/datum/reagents/process() - if (chem_temp > C.OptimalTempMin)//To prevent pointless reactions - if (reactedVol < targetVol) - reactedVol = FermiReact(fermiReactID, chem_temp, pH, multiplier, reactedVol, targetVol, cached_required_reagents, cached_results) - else - STOP_PROCESSING(SSfastprocess, src) - //handle_reactions() - -/datum/reagents/proc/FermiReact(selected_reaction, chem_temp, pH, multiplier, reactedVol, targetVol, cached_required_reagents, cached_results) - var/datum/chemical_reaction/C = selected_reaction - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - //var/ammoReacted = 0 - //get purity from combined beaker reactant purities HERE. - var/purity = 1 - //var/tempVol = totalVol - //var/list/multiplier = INFINITY - - message_admins("Loop beginning") - //Begin Parse - - //Check extremes first - if (chem_temp > C.ExplodeTemp) - //go to explode proc - message_admins("temperature is over limit: [C.ExplodeTemp] Current temperature: [chem_temp]") - FermiExplode() - - if (pH > 14 || pH < 0) - //Create chemical sludge eventually(for now just destroy the beaker I guess?) - //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) - message_admins("pH is lover limit, cur pH: [pH]") - FermiExplode() - - //For now, purity is handled elsewhere - - //Calculate DeltaT (Deviation of T from optimal) - if (chem_temp < C.OptimalTempMax && chem_temp >= C.OptimalTempMin) - deltaT = (((C.OptimalTempMin - chem_temp)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT)) - else if (chem_temp >= C.OptimalTempMax) - deltaT = 1 - else - deltaT = 0 - message_admins("calculating temperature factor, min: [C.OptimalTempMin], max: [C.OptimalTempMax], Exponential: [C.CurveSharpT], deltaT: [deltaT]") - - //Calculate DeltapH (Deviation of pH from optimal) - //Lower range - if (pH < C.OptimalpHMin) - if (pH < (C.OptimalpHMin - C.ReactpHLim)) - deltapH = 0 - else - deltapH = (((pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH)) - //Upper range - else if (pH > C.OptimalpHMin) - if (pH > (C.OptimalpHMin + C.ReactpHLim)) - deltapH = 0 - else - deltapH = ((C.ReactpHLim -(pH - (C.OptimalpHMax + C.ReactpHLim))+C.ReactpHLim)/(C.ReactpHLim**C.CurveSharppH)) - //Within mid range - else if (pH >= C.OptimalpHMin && pH <= C.OptimalpHMax) - deltapH = 1 - //This should never proc: - else - message_admins("Fermichem's pH broke!! Please let Fermis know!!") - WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])") - //TODO Add CatalystFact - message_admins("calculating pH factor(purity), pH: [pH], min: [C.OptimalpHMin]-[C.ReactpHLim], max: [C.OptimalpHMax]+[C.ReactpHLim], deltapH: [deltapH]") - - stepChemAmmount = targetVol * deltaT - if (stepChemAmmount > C.RateUpLim) - stepChemAmmount = C.RateUpLim - else if (stepChemAmmount < 0.01) - stepChemAmmount = 0.01 - - if ((reactedVol + stepChemAmmount) > targetVol) - stepChemAmmount = targetVol - reactedVol - message_admins("target volume reached. Reaction should stop after this loop") - - if (reactedVol > 0) - purity = ((purity * reactedVol) + (deltapH * stepChemAmmount)) /((reactedVol+ stepChemAmmount)) //This should add the purity to the product - else - purity = deltapH - message_admins("purity: [purity], purity of beaker") - message_admins("Temp before change: [chem_temp], pH after change: [pH]") - //Apply pH changes and thermal output of reaction to beaker - chem_temp += (C.ThermicConstant * stepChemAmmount) - pH += (C.HIonRelease * stepChemAmmount) - message_admins("Temp after change: [chem_temp], pH after change: [pH]") - - // End. - /* - for(var/B in cached_required_reagents) // - tempVol = min(reactedVol, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - */ - message_admins("cached_results: [cached_results], reactedVol: [reactedVol], stepChemAmmount [stepChemAmmount]") - - - - for(var/B in cached_required_reagents) - message_admins("cached_required_reagents(B): [cached_required_reagents[B]], reactedVol: [reactedVol], base stepChemAmmount [stepChemAmmount]") - remove_reagent(B, (stepChemAmmount * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in cached_results)//Not sure how this works, what is selected_reaction.results? - reactedVol = max(reactedVol, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmmount, P)//log - add_reagent(P, cached_results[P]*stepChemAmmount, null, chem_temp)//add reagent function!! I THINK I can do this: - - reactedVol = reactedVol + stepChemAmmount - - - return //(reactedVol) - -/datum/reagents/proc/FermiExplode() - return - -/datum/reagents/proc/isolate_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id != reagent) - del_reagent(R.id) - update_total() - -/datum/reagents/proc/del_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id == reagent) - if(my_atom && isliving(my_atom)) - var/mob/living/M = my_atom - R.on_mob_delete(M) - qdel(R) - reagent_list -= R - update_total() - if(my_atom) - my_atom.on_reagent_change(DEL_REAGENT) - return 1 - -/datum/reagents/proc/update_total() - var/list/cached_reagents = reagent_list - total_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume < 0.1) - del_reagent(R.id) - else - total_volume += R.volume - - return 0 - -/datum/reagents/proc/clear_reagents() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - del_reagent(R.id) - return 0 - -/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1) - var/react_type - if(isliving(A)) - react_type = "LIVING" - if(method == INGEST) - var/mob/living/L = A - L.taste(src) - else if(isturf(A)) - react_type = "TURF" - else if(isobj(A)) - react_type = "OBJ" - else - return - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - switch(react_type) - if("LIVING") - var/touch_protection = 0 - if(method == VAPOR) - var/mob/living/L = A - touch_protection = L.get_permeability_protection() - R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection) - if("TURF") - R.reaction_turf(A, R.volume * volume_modifier, show_message) - if("OBJ") - R.reaction_obj(A, R.volume * volume_modifier, show_message) - -/datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE - -//Returns the average specific heat for all reagents currently in this holder. -/datum/reagents/proc/specific_heat() - . = 0 - var/cached_amount = total_volume //cache amount - var/list/cached_reagents = reagent_list //cache reagents - for(var/I in cached_reagents) - var/datum/reagent/R = I - . += R.specific_heat * (R.volume / cached_amount) - -/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) - var/S = specific_heat() - chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000) - -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, pH = 7, no_react = 0)//EDIT HERE TOO ~FERMICHEM~ - if(!isnum(amount) || !amount) - return FALSE - - if(amount <= 0) - return FALSE - - var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] - if(!D) - WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") - return FALSE - - update_total() - var/cached_total = total_volume - if(cached_total + amount > maximum_volume) - amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. - if(amount <= 0) - return FALSE - var/new_total = cached_total + amount - var/cached_temp = chem_temp - var/list/cached_reagents = reagent_list - - //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. - var/specific_heat = 0 - var/thermal_energy = 0 - for(var/i in cached_reagents) - var/datum/reagent/R = i - specific_heat += R.specific_heat * (R.volume / new_total) - thermal_energy += R.specific_heat * R.volume * cached_temp - specific_heat += D.specific_heat * (amount / new_total) - thermal_energy += D.specific_heat * amount * reagtemp - chem_temp = thermal_energy / (specific_heat * new_total) - //// - - //add the reagent to the existing if it exists - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) - if(!no_react) - handle_reactions() - return TRUE - - //otherwise make a new one - var/datum/reagent/R = new D.type(data) - cached_reagents += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - if(!no_react) - handle_reactions() - return TRUE - -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(isnull(amount)) - amount = 0 - CRASH("null amount passed to reagent code") - return FALSE - - if(!isnum(amount)) - return FALSE - - if(amount < 0) - return FALSE - - var/list/cached_reagents = reagent_list - - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - //clamp the removal amount to be between current reagent amount - //and zero, to prevent removing more than the holder has stored - amount = CLAMP(amount, 0, R.volume) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - if(my_atom) - my_atom.on_reagent_change(REM_REAGENT) - return TRUE - - return FALSE - -/datum/reagents/proc/has_reagent(reagent, amount = -1) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - if(!amount) - return R - else - if(R.volume >= amount) - return R - else - return 0 - - return 0 - -/datum/reagents/proc/get_reagent_amount(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - return R.volume - - return 0 - -/datum/reagents/proc/get_reagents() - var/list/names = list() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - names += R.name - - return jointext(names, ",") - -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. - if(!isnum(amount)) - return 1 - var/list/cached_reagents = reagent_list - var/has_removed_reagent = 0 - - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.id, amount, safety) - - return has_removed_reagent - -//two helper functions to preserve data across reactions (needed for xenoarch) -/datum/reagents/proc/get_data(reagent_id) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - return R.data - -/datum/reagents/proc/set_data(reagent_id, new_data) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - R.data = new_data - -/datum/reagents/proc/copy_data(datum/reagent/current_reagent) - if(!current_reagent || !current_reagent.data) - return null - if(!istype(current_reagent.data, /list)) - return current_reagent.data - - var/list/trans_data = current_reagent.data.Copy() - - // We do this so that introducing a virus to a blood sample - // doesn't automagically infect all other blood samples from - // the same donor. - // - // Technically we should probably copy all data lists, but - // that could possibly eat up a lot of memory needlessly - // if most data lists are read-only. - if(trans_data["viruses"]) - var/list/v = trans_data["viruses"] - trans_data["viruses"] = v.Copy() - - return trans_data - -/datum/reagents/proc/get_reagent(type) - var/list/cached_reagents = reagent_list - . = locate(type) in cached_reagents - -/datum/reagents/proc/generate_taste_message(minimum_percent=15) - // the lower the minimum percent, the more sensitive the message is. - var/list/out = list() - var/list/tastes = list() //descriptor = strength - if(minimum_percent <= 100) - for(var/datum/reagent/R in reagent_list) - if(!R.taste_mult) - continue - - if(istype(R, /datum/reagent/consumable/nutriment)) - var/list/taste_data = R.data - for(var/taste in taste_data) - var/ratio = taste_data[taste] - var/amount = ratio * R.taste_mult * R.volume - if(taste in tastes) - tastes[taste] += amount - else - tastes[taste] = amount - else - var/taste_desc = R.taste_description - var/taste_amount = R.volume * R.taste_mult - if(taste_desc in tastes) - tastes[taste_desc] += taste_amount - else - tastes[taste_desc] = taste_amount - //deal with percentages - // TODO it would be great if we could sort these from strong to weak - var/total_taste = counterlist_sum(tastes) - if(total_taste > 0) - for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue - var/intensity_desc = "a hint of" - if(percent > minimum_percent * 2 || percent == 100) - intensity_desc = "" - else if(percent > minimum_percent * 3) - intensity_desc = "the strong flavor of" - if(intensity_desc != "") - out += "[intensity_desc] [taste_desc]" - else - out += "[taste_desc]" - - return english_list(out, "something indescribable") - -/datum/reagents/proc/expose_temperature(var/temperature, var/coeff=0.02) - var/temp_delta = (temperature - chem_temp) * coeff - if(temp_delta > 0) - chem_temp = min(chem_temp + max(temp_delta, 1), temperature) - else - chem_temp = max(chem_temp + min(temp_delta, -1), temperature) - chem_temp = round(chem_temp) - handle_reactions() - -/////////////////////////////////////////////////////////////////////////////////// - - -// Convenience proc to create a reagents holder for an atom -// Max vol is maximum volume of holder -/atom/proc/create_reagents(max_vol) - if(reagents) - qdel(reagents) - reagents = new/datum/reagents(max_vol) - reagents.my_atom = src - -/proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents - var/static/list/random_reagents = list() - if(!random_reagents.len) - for(var/thing in subtypesof(/datum/reagent)) - var/datum/reagent/R = thing - if(initial(R.can_synth)) - random_reagents += initial(R.id) - var/picked_reagent = pick(random_reagents) - return picked_reagent diff --git a/code/modules/reagents/chemistry/holderbk3.dm b/code/modules/reagents/chemistry/holderbk3.dm deleted file mode 100644 index 6c2f5a9876..0000000000 --- a/code/modules/reagents/chemistry/holderbk3.dm +++ /dev/null @@ -1,962 +0,0 @@ - -/proc/build_chemical_reagent_list() - //Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id - - if(GLOB.chemical_reagents_list) - return - - var/paths = subtypesof(/datum/reagent) - GLOB.chemical_reagents_list = list() - - for(var/path in paths) - var/datum/reagent/D = new path() - GLOB.chemical_reagents_list[D.id] = D - -/proc/build_chemical_reactions_list() - //Chemical Reactions - Initialises all /datum/chemical_reaction into a list - // It is filtered into multiple lists within a list. - // For example: - // chemical_reaction_list["plasma"] is a list of all reactions relating to plasma - - if(GLOB.chemical_reactions_list) - return - - var/paths = subtypesof(/datum/chemical_reaction) - GLOB.chemical_reactions_list = list() - - for(var/path in paths) - - var/datum/chemical_reaction/D = new path() - var/list/reaction_ids = list() - - if(D.required_reagents && D.required_reagents.len) - for(var/reaction in D.required_reagents) - reaction_ids += reaction - - // Create filters based on each reagent id in the required reagents list - for(var/id in reaction_ids) - if(!GLOB.chemical_reactions_list[id]) - GLOB.chemical_reactions_list[id] = list() - GLOB.chemical_reactions_list[id] += D - break // Don't bother adding ourselves to other reagent ids, it is redundant - -/////////////////////////////////////////////////////////////////////////////////// - -/datum/reagents - var/list/datum/reagent/reagent_list = new/list() - var/total_volume = 0 - var/maximum_volume = 100 - var/atom/my_atom = null - var/chem_temp = 150 - var/pH = REAGENT_NORMAL_PH - var/last_tick = 1 - var/addiction_tick = 1 - var/list/datum/reagent/addiction_list = new/list() - var/reagents_holder_flags - -/datum/reagents/New(maximum=100) - maximum_volume = maximum - - //I dislike having these here but map-objects are initialised before world/New() is called. >_> - if(!GLOB.chemical_reagents_list) - build_chemical_reagent_list() - if(!GLOB.chemical_reactions_list) - build_chemical_reactions_list() - -/datum/reagents/Destroy() - . = ..() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - qdel(R) - cached_reagents.Cut() - cached_reagents = null - if(my_atom && my_atom.reagents == src) - my_atom.reagents = null - my_atom = null - -// Used in attack logs for reagents in pills and such -/datum/reagents/proc/log_list() - if(!length(reagent_list)) - return "no reagents" - - var/list/data = list() - for(var/r in reagent_list) //no reagents will be left behind - var/datum/reagent/R = r - data += "[R.id] ([round(R.volume, 0.1)]u)" - //Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals. - return english_list(data) - -/datum/reagents/proc/remove_any(amount = 1) - var/list/cached_reagents = reagent_list - var/total_transfered = 0 - var/current_list_element = 1 - - current_list_element = rand(1, cached_reagents.len) - - while(total_transfered != amount) - if(total_transfered >= amount) - break - if(total_volume <= 0 || !cached_reagents.len) - break - - if(current_list_element > cached_reagents.len) - current_list_element = 1 - - var/datum/reagent/R = cached_reagents[current_list_element] - remove_reagent(R.id, 1) - - current_list_element++ - total_transfered++ - update_total() - - handle_reactions() - return total_transfered - -/datum/reagents/proc/remove_all(amount = 1) - var/list/cached_reagents = reagent_list - if(total_volume > 0) - var/part = amount / total_volume - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - remove_reagent(R.id, R.volume * part) - - update_total() - handle_reactions() - return amount - -/datum/reagents/proc/get_master_reagent_name() - var/list/cached_reagents = reagent_list - var/name - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - name = R.name - - return name - -/datum/reagents/proc/get_master_reagent_id() - var/list/cached_reagents = reagent_list - var/id - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - id = R.id - - return id - -/datum/reagents/proc/get_master_reagent() - var/list/cached_reagents = reagent_list - var/datum/reagent/master - var/max_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume > max_volume) - max_volume = R.volume - master = R - - return master - -/datum/reagents/proc/trans_to(obj/target, amount=1, multiplier=1, preserve_data=1, no_react = 0)//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred. - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - if(amount < 0) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - amount = min(min(amount, src.total_volume), R.maximum_volume-R.total_volume) - var/part = amount / src.total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/transfer_amount = T.volume * part - if(preserve_data) - trans_data = copy_data(T) - - //fermichem Added ph TODO: add T.purity - R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - //R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, pH, T.purity, no_react = TRUE) //we only handle reaction after every reagent has been transfered. - remove_reagent(T.id, transfer_amount) - - update_total() - R.update_total() - if(!no_react) - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/copy_to(obj/target, amount=1, multiplier=1, preserve_data=1) - var/list/cached_reagents = reagent_list - if(!target || !total_volume) - return - - var/datum/reagents/R - if(istype(target, /datum/reagents)) - R = target - else - if(!target.reagents) - return - R = target.reagents - - if(amount < 0) - return - amount = min(min(amount, total_volume), R.maximum_volume-R.total_volume) - var/part = amount / total_volume - var/trans_data = null - for(var/reagent in cached_reagents) - var/datum/reagent/T = reagent - var/copy_amount = T.volume * part - if(preserve_data) - trans_data = T.data - R.add_reagent(T.id, copy_amount * multiplier, trans_data) - - src.update_total() - R.update_total() - R.handle_reactions() - src.handle_reactions() - return amount - -/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N - var/list/cached_reagents = reagent_list - if (!target) - return - if (!target.reagents || src.total_volume<=0 || !src.get_reagent_amount(reagent)) - return - if(amount < 0) - return - - var/datum/reagents/R = target.reagents - if(src.get_reagent_amount(reagent)= R.overdose_threshold && !R.overdosed) - R.overdosed = 1 - need_mob_update += R.overdose_start(C) - if(R.addiction_threshold) - if(R.volume >= R.addiction_threshold && !is_type_in_list(R, cached_addictions)) - var/datum/reagent/new_reagent = new R.type() - cached_addictions.Add(new_reagent) - if(R.overdosed) - need_mob_update += R.overdose_process(C) - if(is_type_in_list(R,cached_addictions)) - for(var/addiction in cached_addictions) - var/datum/reagent/A = addiction - if(istype(R, A)) - A.addiction_stage = -15 // you're satisfied for a good while. - need_mob_update += R.on_mob_life(C) - - if(can_overdose) - if(addiction_tick == 6) - addiction_tick = 1 - for(var/addiction in cached_addictions) - var/datum/reagent/R = addiction - if(C && R) - R.addiction_stage++ - if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end) - need_mob_update += R.addiction_act_stage1(C) - else if(R.addiction_stage1_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end) - need_mob_update += R.addiction_act_stage2(C) - else if(R.addiction_stage2_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end) - need_mob_update += R.addiction_act_stage3(C) - else if(R.addiction_stage3_end <= R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end) - need_mob_update += R.addiction_act_stage4(C) - else if(R.addiction_stage4_end <= R.addiction_stage) - to_chat(C, "You feel like you've gotten over your need for [R.name].") - SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.id]_addiction") - cached_addictions.Remove(R) - addiction_tick++ - if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates. - C.updatehealth() - C.update_canmove() - C.update_stamina() - update_total() - - -/datum/reagents/proc/set_reacting(react = TRUE) - if(react) - reagents_holder_flags &= ~(REAGENT_NOREACT) - else - reagents_holder_flags |= REAGENT_NOREACT - -/datum/reagents/proc/conditional_update_move(atom/A, Running = 0) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_move (A, Running) - update_total() - -/datum/reagents/proc/conditional_update(atom/A) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - R.on_update (A) - update_total() - -/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar - var/list/cached_reagents = reagent_list //a list of the reagents? - var/list/cached_reactions = GLOB.chemical_reactions_list //a list of the whole reactions? - var/datum/cached_my_atom = my_atom //It says my atom, but I didn't bring one with me!! - if(reagents_holder_flags & REAGENT_NOREACT) //Not sure on reagents_holder_flags, but I think it checks to see if theres a reaction with current stuff. - return //Yup, no reactions here. No siree. - - var/reaction_occurred = 0 // checks if reaction, binary variable - do //What does do do in byond? It sounds very redundant? is it a while loop? - var/list/possible_reactions = list() //init list - reaction_occurred = 0 // sets it back to 0? - for(var/reagent in cached_reagents) //for reagent in beaker/holder - var/datum/reagent/R = reagent //check to make sure that reagent is there for the reaction list - for(var/reaction in cached_reactions[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id - if(!reaction) - continue - - var/datum/chemical_reaction/C = reaction - var/list/cached_required_reagents = C.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 - var/list/cached_required_catalysts = C.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 - var/required_temp = C.required_temp - var/is_cold_recipe = C.is_cold_recipe - var/meets_temp_requirement = 0 - var/has_special_react = C.special_react - var/can_special_react = 0 - var/reactedVol = 0 - - for(var/B in cached_required_reagents) - if(!has_reagent(B, cached_required_reagents[B])) - break - total_matching_reagents++ - for(var/B in cached_required_catalysts) - if(!has_reagent(B, cached_required_catalysts[B])) - break - total_matching_catalysts++ - if(cached_my_atom) - if(!C.required_container) - matching_container = 1 - - else - if(cached_my_atom.type == C.required_container)//if the suspected container is a container - matching_container = 1 - if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs - return - if(!C.required_other)//Checks for other things required - matching_other = 1//binary check passes - - else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem - var/obj/item/slime_extract/M = cached_my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 - else - if(!C.required_container)//I'm not sure why this is here twice, I think if it's not a beaker? Oh, cyro. - matching_container = 1 - if(!C.required_other) - matching_other = 1 - - //FermiChem - /* - if (chem_temp > C.ExplodeTemp)//Check to see if reaction is too hot! - if (C.FermiExplode == TRUE) - //To be added! - else - FermiExplode() - //explode function!! - */ - - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! - meets_temp_requirement = 1//binary pass - - if(!has_special_react || C.check_special_react(src)) - can_special_react = 1 - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) - possible_reactions += C - - if(possible_reactions.len)//does list exist? - var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions)//why V, surely that would indicate volume? V is the reaction potential. - var/datum/chemical_reaction/competitor = V //competitor? I think this is theres two of them. Troubling..! - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. - if(competitor.required_temp <= selected_reaction.required_temp)//only returns with lower if reaction "is cold" var. - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor - var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list - var/list/cached_results = selected_reaction.results//resultant chemical list - var/special_react_result = selected_reaction.check_special_react(src) - var/list/multiplier = INFINITY //Wat - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. - //FermiChem relies on two additional properties; pH and impurity - //Temperature plays into a larger role too. - //BRANCH HERE - if(selected_reaction) - var/datum/chemical_reaction/C = selected_reaction - - if (C.FermiChem == TRUE) - message_admins("FermiChem Proc'd") - - while (reaction_occurred < 1) - reaction_occurred, reactedVol = FermiReact(selected_reaction, chem_temp, pH, multiplier) - CHECK_TICK - - //Standard reaction mechanics: - else - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log - add_reagent(P, cached_results[P]*multiplier, null, chem_temp)//add reagent function!! I THINK I can do this: - - - var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers - 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, 1) - - for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - - if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 - - while(reaction_occurred)//while do nothing? - update_total()//Don't know waht this does. - return 0//end! - -/datum/reagents/proc/FermiReact(selected_reaction, chem_temp, pH, totalVol) - var/datum/chemical_reaction/C = selected_reaction - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - var/ammoReacted = 0 - //get purity from combined beaker reactant purities HERE. - var/purity = 1 - //var/tempVol = totalVol - //var/list/multiplier = INFINITY - - message_admins("Loop beginning") - //Begin Parse - - //Check extremes first - if (chem_temp > C.ExplodeTemp) - //go to explode proc - message_admins("temperature is over limit: [C.ExplodeTemp] Current temperature: [chem_temp]") - FermiExplode() - - if (pH > 14 || pH < 0) - //Create chemical sludge eventually(for now just destroy the beaker I guess?) - //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) - message_admins("pH is lover limit, cur pH: [pH]") - FermiExplode() - - //For now, purity is handled elsewhere - - //Calculate DeltaT (Deviation of T from optimal) - if (chem_temp < C.OptimalTempMax && chem_temp >= C.OptimalTempMin) - deltaT = (((C.OptimalTempMin - chem_temp)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT)) - else if (chem_temp >= C.OptimalTempMax) - deltaT = 1 - else - deltaT = 0 - message_admins("calculating temperature factor, min: [C.OptimalTempMin], max: [C.OptimalTempMax], Exponential: [C.CurveSharpT], deltaT: [deltaT]") - - //Calculate DeltapH (Deviation of pH from optimal) - //Lower range - if (pH < C.OptimalpHMin) - if (pH < (C.OptimalpHMin - C.ReactpHLim)) - deltapH = 0 - else - deltapH = (((pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH)) - //Upper range - else if (pH > C.OptimalpHMin) - if (pH > (C.OptimalpHMin + C.ReactpHLim)) - deltapH = 0 - else - deltapH = ((C.ReactpHLim -(pH - (C.OptimalpHMax + C.ReactpHLim))+C.ReactpHLim)/(C.ReactpHLim**C.CurveSharppH)) - //Within mid range - else if (pH >= C.OptimalpHMin && pH <= C.OptimalpHMax) - deltapH = 1 - //This should never proc: - else - message_admins("Fermichem's pH broke!! Please let Fermis know!!") - WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])") - //TODO Add CatalystFact - message_admins("calculating pH factor(purity), pH: [pH], min: [C.OptimalpHMin]-[C.ReactpHLim], max: [C.OptimalpHMax]+[C.ReactpHLim], deltapH: [deltapH]") - - stepChemAmmount = tempVol * deltaT - if (stepChemAmmount > C.RateUpLim) - stepChemAmmount = C.RateUpLim - else if (stepChemAmmount < 0.01) - stepChemAmmount = 0.01 - - if (ammoReacted > 0) - purity = ((purity * ammoReacted) + (deltapH * stepChemAmmount)) /((ammoReacted + stepChemAmmount)) //This should add the purity to the product - else - purity = deltapH - message_admins("purity: [purity], purity of beaker") - message_admins("Temp before change: [chem_temp], pH after change: [pH]") - //Apply pH changes and thermal output of reaction to beaker - chem_temp += (C.ThermicConstant * stepChemAmmount) - pH += (C.HIonRelease * stepChemAmmount) - message_admins("Temp after change: [chem_temp], pH after change: [pH]") - - // End. - - selected_reaction.on_reaction(src, multiplier, special_react_result) - - for(var/B in cached_required_reagents) // - tempVol = min(totalVol, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - - - message_admins("cached_results: [cached_results], totalVol: [totalVol], stepChemAmmount [stepChemAmmount]") - for(var/B in cached_required_reagents) - message_admins("cached_required_reagents(B): [cached_required_reagents[B]], totalVol: [totalVol], base stepChemAmmount [stepChemAmmount]") - remove_reagent(B, (stepChemAmmount * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? - totalVol = max(totalVol, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmmount, P)//log - add_reagent(P, cached_results[P]*stepChemAmmount, null, chem_temp)//add reagent function!! I THINK I can do this: - - ammoReacted = ammoReacted + stepChemAmmount - - if ammoReacted = totalVol - reaction_occurred = 1 - SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", ammoReacted, C.id)//log - - CHECK_TICK - return (reaction_occurred, ammoReacted) - -/datum/reagents/proc/FermiExplode() - return - -/datum/reagents/proc/isolate_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id != reagent) - del_reagent(R.id) - update_total() - -/datum/reagents/proc/del_reagent(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if(R.id == reagent) - if(my_atom && isliving(my_atom)) - var/mob/living/M = my_atom - R.on_mob_delete(M) - qdel(R) - reagent_list -= R - update_total() - if(my_atom) - my_atom.on_reagent_change(DEL_REAGENT) - return 1 - -/datum/reagents/proc/update_total() - var/list/cached_reagents = reagent_list - total_volume = 0 - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.volume < 0.1) - del_reagent(R.id) - else - total_volume += R.volume - - return 0 - -/datum/reagents/proc/clear_reagents() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - del_reagent(R.id) - return 0 - -/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1) - var/react_type - if(isliving(A)) - react_type = "LIVING" - if(method == INGEST) - var/mob/living/L = A - L.taste(src) - else if(isturf(A)) - react_type = "TURF" - else if(isobj(A)) - react_type = "OBJ" - else - return - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - switch(react_type) - if("LIVING") - var/touch_protection = 0 - if(method == VAPOR) - var/mob/living/L = A - touch_protection = L.get_permeability_protection() - R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection) - if("TURF") - R.reaction_turf(A, R.volume * volume_modifier, show_message) - if("OBJ") - R.reaction_obj(A, R.volume * volume_modifier, show_message) - -/datum/reagents/proc/holder_full() - if(total_volume >= maximum_volume) - return TRUE - return FALSE - -//Returns the average specific heat for all reagents currently in this holder. -/datum/reagents/proc/specific_heat() - . = 0 - var/cached_amount = total_volume //cache amount - var/list/cached_reagents = reagent_list //cache reagents - for(var/I in cached_reagents) - var/datum/reagent/R = I - . += R.specific_heat * (R.volume / cached_amount) - -/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000) - var/S = specific_heat() - chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000) - -/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, pH = 7, no_react = 0)//EDIT HERE TOO ~FERMICHEM~ - if(!isnum(amount) || !amount) - return FALSE - - if(amount <= 0) - return FALSE - - var/datum/reagent/D = GLOB.chemical_reagents_list[reagent] - if(!D) - WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])") - return FALSE - - update_total() - var/cached_total = total_volume - if(cached_total + amount > maximum_volume) - amount = (maximum_volume - cached_total) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen. - if(amount <= 0) - return FALSE - var/new_total = cached_total + amount - var/cached_temp = chem_temp - var/list/cached_reagents = reagent_list - - //Equalize temperature - Not using specific_heat() because the new chemical isn't in yet. - var/specific_heat = 0 - var/thermal_energy = 0 - for(var/i in cached_reagents) - var/datum/reagent/R = i - specific_heat += R.specific_heat * (R.volume / new_total) - thermal_energy += R.specific_heat * R.volume * cached_temp - specific_heat += D.specific_heat * (amount / new_total) - thermal_energy += D.specific_heat * amount * reagtemp - chem_temp = thermal_energy / (specific_heat * new_total) - //// - - //add the reagent to the existing if it exists - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - R.volume += amount - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - R.on_merge(data, amount) - if(!no_react) - handle_reactions() - return TRUE - - //otherwise make a new one - var/datum/reagent/R = new D.type(data) - cached_reagents += R - R.holder = src - R.volume = amount - if(data) - R.data = data - R.on_new(data) - - if(isliving(my_atom)) - R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete - update_total() - if(my_atom) - my_atom.on_reagent_change(ADD_REAGENT) - if(!no_react) - handle_reactions() - return TRUE - -/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) - for(var/r_id in list_reagents) - var/amt = list_reagents[r_id] - add_reagent(r_id, amt, data) - -/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to - - if(isnull(amount)) - amount = 0 - CRASH("null amount passed to reagent code") - return FALSE - - if(!isnum(amount)) - return FALSE - - if(amount < 0) - return FALSE - - var/list/cached_reagents = reagent_list - - for(var/A in cached_reagents) - var/datum/reagent/R = A - if (R.id == reagent) - //clamp the removal amount to be between current reagent amount - //and zero, to prevent removing more than the holder has stored - amount = CLAMP(amount, 0, R.volume) - R.volume -= amount - update_total() - if(!safety)//So it does not handle reactions when it need not to - handle_reactions() - if(my_atom) - my_atom.on_reagent_change(REM_REAGENT) - return TRUE - - return FALSE - -/datum/reagents/proc/has_reagent(reagent, amount = -1) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - if(!amount) - return R - else - if(R.volume >= amount) - return R - else - return 0 - - return 0 - -/datum/reagents/proc/get_reagent_amount(reagent) - var/list/cached_reagents = reagent_list - for(var/_reagent in cached_reagents) - var/datum/reagent/R = _reagent - if (R.id == reagent) - return R.volume - - return 0 - -/datum/reagents/proc/get_reagents() - var/list/names = list() - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - names += R.name - - return jointext(names, ",") - -/datum/reagents/proc/remove_all_type(reagent_type, amount, strict = 0, safety = 1) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. - if(!isnum(amount)) - return 1 - var/list/cached_reagents = reagent_list - var/has_removed_reagent = 0 - - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - var/matches = 0 - // Switch between how we check the reagent type - if(strict) - if(R.type == reagent_type) - matches = 1 - else - if(istype(R, reagent_type)) - matches = 1 - // We found a match, proceed to remove the reagent. Keep looping, we might find other reagents of the same type. - if(matches) - // Have our other proc handle removement - has_removed_reagent = remove_reagent(R.id, amount, safety) - - return has_removed_reagent - -//two helper functions to preserve data across reactions (needed for xenoarch) -/datum/reagents/proc/get_data(reagent_id) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - return R.data - -/datum/reagents/proc/set_data(reagent_id, new_data) - var/list/cached_reagents = reagent_list - for(var/reagent in cached_reagents) - var/datum/reagent/R = reagent - if(R.id == reagent_id) - R.data = new_data - -/datum/reagents/proc/copy_data(datum/reagent/current_reagent) - if(!current_reagent || !current_reagent.data) - return null - if(!istype(current_reagent.data, /list)) - return current_reagent.data - - var/list/trans_data = current_reagent.data.Copy() - - // We do this so that introducing a virus to a blood sample - // doesn't automagically infect all other blood samples from - // the same donor. - // - // Technically we should probably copy all data lists, but - // that could possibly eat up a lot of memory needlessly - // if most data lists are read-only. - if(trans_data["viruses"]) - var/list/v = trans_data["viruses"] - trans_data["viruses"] = v.Copy() - - return trans_data - -/datum/reagents/proc/get_reagent(type) - var/list/cached_reagents = reagent_list - . = locate(type) in cached_reagents - -/datum/reagents/proc/generate_taste_message(minimum_percent=15) - // the lower the minimum percent, the more sensitive the message is. - var/list/out = list() - var/list/tastes = list() //descriptor = strength - if(minimum_percent <= 100) - for(var/datum/reagent/R in reagent_list) - if(!R.taste_mult) - continue - - if(istype(R, /datum/reagent/consumable/nutriment)) - var/list/taste_data = R.data - for(var/taste in taste_data) - var/ratio = taste_data[taste] - var/amount = ratio * R.taste_mult * R.volume - if(taste in tastes) - tastes[taste] += amount - else - tastes[taste] = amount - else - var/taste_desc = R.taste_description - var/taste_amount = R.volume * R.taste_mult - if(taste_desc in tastes) - tastes[taste_desc] += taste_amount - else - tastes[taste_desc] = taste_amount - //deal with percentages - // TODO it would be great if we could sort these from strong to weak - var/total_taste = counterlist_sum(tastes) - if(total_taste > 0) - for(var/taste_desc in tastes) - var/percent = tastes[taste_desc]/total_taste * 100 - if(percent < minimum_percent) - continue - var/intensity_desc = "a hint of" - if(percent > minimum_percent * 2 || percent == 100) - intensity_desc = "" - else if(percent > minimum_percent * 3) - intensity_desc = "the strong flavor of" - if(intensity_desc != "") - out += "[intensity_desc] [taste_desc]" - else - out += "[taste_desc]" - - return english_list(out, "something indescribable") - -/datum/reagents/proc/expose_temperature(var/temperature, var/coeff=0.02) - var/temp_delta = (temperature - chem_temp) * coeff - if(temp_delta > 0) - chem_temp = min(chem_temp + max(temp_delta, 1), temperature) - else - chem_temp = max(chem_temp + min(temp_delta, -1), temperature) - chem_temp = round(chem_temp) - handle_reactions() - -/////////////////////////////////////////////////////////////////////////////////// - - -// Convenience proc to create a reagents holder for an atom -// Max vol is maximum volume of holder -/atom/proc/create_reagents(max_vol) - if(reagents) - qdel(reagents) - reagents = new/datum/reagents(max_vol) - reagents.my_atom = src - -/proc/get_random_reagent_id() // Returns a random reagent ID minus blacklisted reagents - var/static/list/random_reagents = list() - if(!random_reagents.len) - for(var/thing in subtypesof(/datum/reagent)) - var/datum/reagent/R = thing - if(initial(R.can_synth)) - random_reagents += initial(R.id) - var/picked_reagent = pick(random_reagents) - return picked_reagent diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index f204494eac..5a704e6784 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -558,8 +558,8 @@ deltaResist /= phase//later phases require more resistance /datum/status_effect/chem/enthrall/proc/owner_say(message) //I can only hope this works - var/datum/status_effect/chem/enthrall/E = owner.has_status_effect(/datum/status_effect/chem/enthrall) - var/mob/living/master = E.master + //var/datum/status_effect/chem/enthrall/E = owner.has_status_effect(/datum/status_effect/chem/enthrall) + //var/mob/living/master = E.master var/static/regex/owner_words = regex("[master]") if(findtext(message, owner_words)) message = replacetext(lowertext(message), lowertext(master), "[enthrallGender]")