code:
/datum/chemical_reaction/reagent_explosion
	var/strengthdiv = 10
	var/modifier = 0
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EXPLOSIVE | REACTION_TAG_MODERATE | REACTION_TAG_DANGEROUS
	required_temp = 0 //Prevent impromptu RPGs

/datum/chemical_reaction/reagent_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	default_explode(holder, created_volume, modifier, strengthdiv)

/datum/chemical_reaction/reagent_explosion/nitroglycerin
	results = list(/datum/reagent/nitroglycerin = 2)
	required_reagents = list(/datum/reagent/glycerol = 1, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/toxin/acid = 1)
	strengthdiv = 2

/datum/chemical_reaction/reagent_explosion/nitroglycerin/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)

	if(holder.has_reagent(/datum/reagent/exotic_stabilizer,round(created_volume / 25, CHEMICAL_QUANTISATION_LEVEL)))
		return
	holder.remove_reagent(/datum/reagent/nitroglycerin, created_volume*2)
	..()

/datum/chemical_reaction/reagent_explosion/nitroglycerin_explosion
	required_reagents = list(/datum/reagent/nitroglycerin = 1)
	required_temp = 474
	strengthdiv = 2

/datum/chemical_reaction/reagent_explosion/rdx
	results = list(/datum/reagent/rdx= 2)
	required_reagents = list(/datum/reagent/phenol = 2, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/acetone_oxide = 1 )
	required_catalysts = list(/datum/reagent/gold) //royal explosive
	required_temp = 404
	strengthdiv = 8

/datum/chemical_reaction/reagent_explosion/rdx/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	holder.remove_reagent(/datum/reagent/rdx, created_volume*2)
	..()

/datum/chemical_reaction/reagent_explosion/rdx_explosion
	required_reagents = list(/datum/reagent/rdx = 1)
	required_temp = 474
	strengthdiv = 7
	modifier = 2

/datum/chemical_reaction/reagent_explosion/rdx_explosion2 //makes rdx unique , on its own it is a good bomb, but when combined with liquid electricity it becomes truly destructive
	required_reagents = list(/datum/reagent/rdx = 1 , /datum/reagent/consumable/liquidelectricity = 1)
	strengthdiv = 3.5 //actually a decrease of 1 becaused of how explosions are calculated. This is due to the fact we require 2 reagents
	modifier = 4

/datum/chemical_reaction/reagent_explosion/rdx_explosion2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/fire_range = round(created_volume/30)
	var/turf/T = get_turf(holder.my_atom)
	for(var/turf/target as anything in RANGE_TURFS(fire_range,T))
		new /obj/effect/hotspot(target)
	holder.chem_temp = 500
	..()

/datum/chemical_reaction/reagent_explosion/rdx_explosion3
	required_reagents = list(/datum/reagent/rdx = 1 , /datum/reagent/teslium = 1)
	strengthdiv = 3.5 //actually a decrease of 1 becaused of how explosions are calculated. This is due to the fact we require 2 reagents
	modifier = 6

/datum/chemical_reaction/reagent_explosion/rdx_explosion3/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/fire_range = round(created_volume/20)
	var/turf/T = get_turf(holder.my_atom)
	for(var/turf/turf as anything in RANGE_TURFS(fire_range,T))
		new /obj/effect/hotspot(turf)
	holder.chem_temp = 750
	..()

/datum/chemical_reaction/reagent_explosion/tatp
	results = list(/datum/reagent/tatp= 1)
	required_reagents = list(/datum/reagent/acetone_oxide = 1, /datum/reagent/toxin/acid/nitracid = 1, /datum/reagent/pentaerythritol = 1 )
	required_temp = 450
	strengthdiv = 3

/datum/chemical_reaction/reagent_explosion/tatp/update_info()
	required_temp = 450 + rand(-49,49)  //this gets loaded only on round start

/datum/chemical_reaction/reagent_explosion/tatp/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/exotic_stabilizer,round(created_volume / 50, CHEMICAL_QUANTISATION_LEVEL))) // we like exotic stabilizer
		return
	holder.remove_reagent(/datum/reagent/tatp, created_volume)
	..()

/datum/chemical_reaction/reagent_explosion/tatp_explosion
	required_reagents = list(/datum/reagent/tatp = 1)
	required_temp = 550 // this makes making tatp before pyro nades, and extreme pain in the ass to make
	strengthdiv = 3

/datum/chemical_reaction/reagent_explosion/tatp_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/strengthdiv_adjust = created_volume / ( 2100 / initial(strengthdiv))
	strengthdiv = max(initial(strengthdiv) - strengthdiv_adjust + 1.5 ,1.5) //Slightly better than nitroglycerin
	. = ..()
	return

/datum/chemical_reaction/reagent_explosion/tatp_explosion/update_info()
	required_temp = 550 + rand(-49,49)

/datum/chemical_reaction/reagent_explosion/penthrite_explosion_epinephrine
	required_reagents = list(/datum/reagent/medicine/c2/penthrite = 1, /datum/reagent/medicine/epinephrine = 1)
	strengthdiv = 5

/datum/chemical_reaction/reagent_explosion/penthrite_explosion_atropine
	required_reagents = list(/datum/reagent/medicine/c2/penthrite = 1, /datum/reagent/medicine/atropine = 1)
	strengthdiv = 5
	modifier = 5

/datum/chemical_reaction/reagent_explosion/potassium_explosion
	required_reagents = list(/datum/reagent/water = 1, /datum/reagent/potassium = 1)
	strengthdiv = 20

/datum/chemical_reaction/reagent_explosion/holyboom
	required_reagents = list(/datum/reagent/water/holywater = 1, /datum/reagent/potassium = 1)
	strengthdiv = 20

/datum/chemical_reaction/reagent_explosion/holyboom/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(created_volume >= 150)
		strengthdiv = 8
		///turf where to play sound
		var/turf/T = get_turf(holder.my_atom)
		///special size for anti cult effect
		var/effective_size = round(created_volume/48)
		playsound(T, 'sound/effects/pray.ogg', 80, FALSE, effective_size)
		for(var/mob/living/simple_animal/revenant/R in get_hearers_in_view(7,T))
			var/deity
			if(GLOB.deity)
				deity = GLOB.deity
			else
				deity = "Christ"
			to_chat(R, span_userdanger("The power of [deity] compels you!"))
			R.stun(20)
			R.reveal(100)
			R.adjustHealth(50)
		for(var/mob/living/carbon/C in get_hearers_in_view(effective_size,T))
			if(IS_CULTIST(C))
				to_chat(C, span_userdanger("The divine explosion sears you!"))
				C.Paralyze(40)
				C.adjust_fire_stacks(5)
				C.IgniteMob()
	..()

/datum/chemical_reaction/gunpowder
	results = list(/datum/reagent/gunpowder = 3)
	required_reagents = list(/datum/reagent/saltpetre = 1, /datum/reagent/medicine/c2/multiver = 1, /datum/reagent/sulfur = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE

/datum/chemical_reaction/reagent_explosion/gunpowder_explosion
	required_reagents = list(/datum/reagent/gunpowder = 1)
	required_temp = 474
	strengthdiv = 10
	modifier = 5
	mix_message = "Sparks start flying around the gunpowder!"

/datum/chemical_reaction/reagent_explosion/gunpowder_explosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	addtimer(CALLBACK(src, .proc/default_explode, holder, created_volume), rand(5,10) SECONDS)

/datum/chemical_reaction/thermite
	results = list(/datum/reagent/thermite = 3)
	required_reagents = list(/datum/reagent/aluminium = 1, /datum/reagent/iron = 1, /datum/reagent/oxygen = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE | REACTION_TAG_OTHER

/datum/chemical_reaction/emp_pulse
	required_reagents = list(/datum/reagent/uranium = 1, /datum/reagent/iron = 1) // Yes, laugh, it's the best recipe I could think of that makes a little bit of sense
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/emp_pulse/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/location = get_turf(holder.my_atom)
	// 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes.
	// 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades.
	empulse(location, round(created_volume / 12), round(created_volume / 7), 1)
	holder.clear_reagents()

/datum/chemical_reaction/beesplosion
	required_reagents = list(/datum/reagent/consumable/honey = 1, /datum/reagent/medicine/strange_reagent = 1, /datum/reagent/uranium/radium = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/beesplosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/location = holder.my_atom.drop_location()
	if(created_volume < 5)
		playsound(location,'sound/effects/sparks1.ogg', 100, TRUE)
	else
		playsound(location,'sound/creatures/bee.ogg', 100, TRUE)
		var/list/beeagents = list()
		for(var/R in holder.reagent_list)
			if(required_reagents[R])
				continue
			beeagents += R
		var/bee_amount = round(created_volume * 0.2)
		for(var/i in 1 to bee_amount)
			var/mob/living/simple_animal/hostile/bee/short/new_bee = new(location)
			if(LAZYLEN(beeagents))
				new_bee.assign_reagent(pick(beeagents))

/datum/chemical_reaction/stabilizing_agent
	results = list(/datum/reagent/stabilizing_agent = 3)
	required_reagents = list(/datum/reagent/iron = 1, /datum/reagent/oxygen = 1, /datum/reagent/hydrogen = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_CHEMICAL | REACTION_TAG_PLANT

/datum/chemical_reaction/clf3
	results = list(/datum/reagent/clf3 = 4)
	required_reagents = list(/datum/reagent/chlorine = 1, /datum/reagent/fluorine = 3)
	required_temp = 424
	overheat_temp = 1050
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL | REACTION_TAG_DANGEROUS | REACTION_TAG_BURN

/datum/chemical_reaction/clf3/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	for(var/turf/target as anything in RANGE_TURFS(1,T))
		new /obj/effect/hotspot(target)
	holder.chem_temp = 1000 // hot as shit

/datum/chemical_reaction/reagent_explosion/methsplosion
	required_temp = 380 //slightly above the meth mix time.
	required_reagents = list(/datum/reagent/drug/methamphetamine = 1)
	strengthdiv = 12
	modifier = 5
	mob_react = FALSE

/datum/chemical_reaction/reagent_explosion/methsplosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	for(var/turf/target in RANGE_TURFS(1,T))
		new /obj/effect/hotspot(target)
	holder.chem_temp = 1000 // hot as shit
	..()

/datum/chemical_reaction/reagent_explosion/methsplosion/methboom2
	required_reagents = list(/datum/reagent/diethylamine = 1, /datum/reagent/iodine = 1, /datum/reagent/phosphorus = 1, /datum/reagent/hydrogen = 1) //diethylamine is often left over from mixing the ephedrine.
	required_temp = 300 //room temperature, chilling it even a little will prevent the explosion

/datum/chemical_reaction/sorium
	results = list(/datum/reagent/sorium = 4)
	required_reagents = list(/datum/reagent/mercury = 1, /datum/reagent/oxygen = 1, /datum/reagent/nitrogen = 1, /datum/reagent/carbon = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/sorium/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	holder.remove_reagent(/datum/reagent/sorium, created_volume*4)
	var/turf/T = get_turf(holder.my_atom)
	var/range = clamp(sqrt(created_volume*4), 1, 6)
	goonchem_vortex(T, 1, range)

/datum/chemical_reaction/sorium_vortex
	required_reagents = list(/datum/reagent/sorium = 1)
	required_temp = 474
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/sorium_vortex/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	var/range = clamp(sqrt(created_volume), 1, 6)
	goonchem_vortex(T, 1, range)

/datum/chemical_reaction/liquid_dark_matter
	results = list(/datum/reagent/liquid_dark_matter = 3)
	required_reagents = list(/datum/reagent/stable_plasma = 1, /datum/reagent/uranium/radium = 1, /datum/reagent/carbon = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/liquid_dark_matter/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	holder.remove_reagent(/datum/reagent/liquid_dark_matter, created_volume*3)
	var/turf/T = get_turf(holder.my_atom)
	var/range = clamp(sqrt(created_volume*3), 1, 6)
	goonchem_vortex(T, 0, range)

/datum/chemical_reaction/ldm_vortex
	required_reagents = list(/datum/reagent/liquid_dark_matter = 1)
	required_temp = 474
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/ldm_vortex/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	var/range = clamp(sqrt(created_volume/2), 1, 6)
	goonchem_vortex(T, 0, range)

/datum/chemical_reaction/flash_powder
	results = list(/datum/reagent/flash_powder = 3)
	required_reagents = list(/datum/reagent/aluminium = 1, /datum/reagent/potassium = 1, /datum/reagent/sulfur = 1 )
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/flash_powder/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	var/location = get_turf(holder.my_atom)
	do_sparks(2, TRUE, location)
	var/range = created_volume/3
	if(isatom(holder.my_atom))
		var/atom/A = holder.my_atom
		A.flash_lighting_fx(_range = (range + 2))
	for(var/mob/living/C in get_hearers_in_view(range, location))
		if(C.flash_act(affect_silicon = TRUE))
			if(get_dist(C, location) < 4)
				C.Paralyze(60)
			else
				C.Stun(100)
	holder.remove_reagent(/datum/reagent/flash_powder, created_volume*3)

/datum/chemical_reaction/flash_powder_flash
	required_reagents = list(/datum/reagent/flash_powder = 1)
	required_temp = 374
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/flash_powder_flash/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/location = get_turf(holder.my_atom)
	do_sparks(2, TRUE, location)
	var/range = created_volume/10
	if(isatom(holder.my_atom))
		var/atom/A = holder.my_atom
		A.flash_lighting_fx(_range = (range + 2))
	for(var/mob/living/C in get_hearers_in_view(range, location))
		if(C.flash_act(affect_silicon = TRUE))
			if(get_dist(C, location) < 4)
				C.Paralyze(60)
			else
				C.Stun(100)

/datum/chemical_reaction/smoke_powder
	results = list(/datum/reagent/smoke_powder = 3)
	required_reagents = list(/datum/reagent/potassium = 1, /datum/reagent/consumable/sugar = 1, /datum/reagent/phosphorus = 1)
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/smoke_powder/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	holder.remove_reagent(/datum/reagent/smoke_powder, created_volume*3)
	var/smoke_radius = round(sqrt(created_volume * 1.5), 1)
	var/location = get_turf(holder.my_atom)
	var/datum/effect_system/smoke_spread/chem/S = new
	S.attach(location)
	playsound(location, 'sound/effects/smoke.ogg', 50, TRUE, -3)
	if(S)
		S.set_up(holder, smoke_radius, location, 0)
		S.start()
	if(holder?.my_atom)
		holder.clear_reagents()

/datum/chemical_reaction/smoke_powder_smoke
	required_reagents = list(/datum/reagent/smoke_powder = 1)
	required_temp = 374
	mob_react = FALSE
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/smoke_powder_smoke/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/location = get_turf(holder.my_atom)
	var/smoke_radius = round(sqrt(created_volume / 2), 1)
	var/datum/effect_system/smoke_spread/chem/S = new
	S.attach(location)
	playsound(location, 'sound/effects/smoke.ogg', 50, TRUE, -3)
	if(S)
		S.set_up(holder, smoke_radius, location, 0)
		S.start()
	if(holder?.my_atom)
		holder.clear_reagents()

/datum/chemical_reaction/sonic_powder
	results = list(/datum/reagent/sonic_powder = 3)
	required_reagents = list(/datum/reagent/oxygen = 1, /datum/reagent/consumable/space_cola = 1, /datum/reagent/phosphorus = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/sonic_powder/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	holder.remove_reagent(/datum/reagent/sonic_powder, created_volume*3)
	var/location = get_turf(holder.my_atom)
	playsound(location, 'sound/effects/bang.ogg', 25, TRUE)
	for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/3, location))
		C.soundbang_act(1, 100, rand(0, 5))

/datum/chemical_reaction/sonic_powder_deafen
	required_reagents = list(/datum/reagent/sonic_powder = 1)
	required_temp = 374
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/sonic_powder_deafen/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/location = get_turf(holder.my_atom)
	playsound(location, 'sound/effects/bang.ogg', 25, TRUE)
	for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/10, location))
		C.soundbang_act(1, 100, rand(0, 5))

/datum/chemical_reaction/phlogiston
	results = list(/datum/reagent/phlogiston = 3)
	required_reagents = list(/datum/reagent/phosphorus = 1, /datum/reagent/toxin/acid = 1, /datum/reagent/stable_plasma = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/phlogiston/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(holder.has_reagent(/datum/reagent/stabilizing_agent))
		return
	var/turf/open/T = get_turf(holder.my_atom)
	if(istype(T))
		T.atmos_spawn_air("plasma=[created_volume];TEMP=1000")
	holder.clear_reagents()
	return

/datum/chemical_reaction/napalm
	results = list(/datum/reagent/napalm = 3)
	required_reagents = list(/datum/reagent/fuel/oil = 1, /datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol = 1 )
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_PLANT

#define CRYOSTYLANE_UNDERHEAT_TEMP 50
#define CRYOSTYLANE_IMPURE_TEMPERATURE_RANGE 200

/datum/chemical_reaction/cryostylane
	results = list(/datum/reagent/cryostylane = 3)
	required_reagents = list(/datum/reagent/consumable/ice = 1, /datum/reagent/stable_plasma = 1, /datum/reagent/nitrogen = 1)
	required_temp = -200
	optimal_temp = 300
	overheat_temp = NO_OVERHEAT //There is an overheat - 50 see reaction_step()
	optimal_ph_min = 4
	optimal_ph_max = 10
	determin_ph_range = 6
	temp_exponent_factor = 0.5
	ph_exponent_factor = 1
	thermic_constant = -7.5
	H_ion_release = 0
	rate_up_lim = 10
	purity_min = 0.2
	reaction_flags = REACTION_HEAT_ARBITARY
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE | REACTION_TAG_ORGAN

//Halve beaker temp on reaction
/datum/chemical_reaction/cryostylane/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/datum/reagent/oxygen = holder.has_reagent(/datum/reagent/oxygen) //If we have oxygen, bring in the old cooling effect
	if(oxygen)
		holder.chem_temp =  max(holder.chem_temp - (10 * oxygen.volume * 2),0)
		holder.remove_reagent(/datum/reagent/oxygen, oxygen.volume) // halves the temperature - tried to bring in some of the old effects at least!
	return

//purity != temp (above 50) - the colder you are the more impure it becomes
/datum/chemical_reaction/cryostylane/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol)
	. = ..()
	if(holder.chem_temp < CRYOSTYLANE_UNDERHEAT_TEMP)
		overheated(holder, reaction, step_reaction_vol)
	//Modify our purity by holder temperature
	var/step_temp = ((holder.chem_temp-CRYOSTYLANE_UNDERHEAT_TEMP)/CRYOSTYLANE_IMPURE_TEMPERATURE_RANGE)
	if(step_temp >= 1) //We're hotter than 300
		return
	reaction.delta_ph *= step_temp

/datum/chemical_reaction/cryostylane/reaction_finish(datum/reagents/holder, datum/equilibrium/reaction, react_vol)
	. = ..()
	if(holder.chem_temp < CRYOSTYLANE_UNDERHEAT_TEMP)
		overheated(holder, null, react_vol) //replace null with fix win 2.3 is merged

//Freezes the area around you!
/datum/chemical_reaction/cryostylane/overheated(datum/reagents/holder, datum/equilibrium/equilibrium, vol_added)
	var/datum/reagent/cryostylane/cryostylane = holder.has_reagent(/datum/reagent/cryostylane)
	if(!cryostylane)
		return ..()
	var/turf/local_turf = get_turf(holder.my_atom)
	playsound(local_turf, 'sound/magic/ethereal_exit.ogg', 50, 1)
	local_turf.visible_message("The reaction frosts over, releasing it's chilly contents!")
	freeze_radius(holder, null, holder.chem_temp*2, clamp(cryostylane.volume/30, 2, 6), 120 SECONDS, 2)
	clear_reactants(holder, 15)
	holder.chem_temp += 100

//Makes a snowman if you're too impure!
/datum/chemical_reaction/cryostylane/overly_impure(datum/reagents/holder, datum/equilibrium/equilibrium, vol_added)
	var/datum/reagent/cryostylane/cryostylane = holder.has_reagent(/datum/reagent/cryostylane)
	var/turf/local_turf = get_turf(holder.my_atom)
	playsound(local_turf, 'sound/magic/ethereal_exit.ogg', 50, 1)
	local_turf.visible_message("The reaction furiously freezes up as a snowman suddenly rises out of the [holder.my_atom.name]!")
	freeze_radius(holder, equilibrium, holder.chem_temp, clamp(cryostylane.volume/15, 3, 10), 180 SECONDS, 5)
	new /obj/structure/statue/snow/snowman(local_turf)
	clear_reactants(holder)
	clear_products(holder)

#undef CRYOSTYLANE_UNDERHEAT_TEMP
#undef CRYOSTYLANE_IMPURE_TEMPERATURE_RANGE

/datum/chemical_reaction/cryostylane_oxygen
	results = list(/datum/reagent/cryostylane = 1)
	required_reagents = list(/datum/reagent/cryostylane = 1, /datum/reagent/oxygen = 1)
	mob_react = FALSE
	is_cold_recipe = TRUE
	required_temp = 99999
	optimal_temp = 300
	overheat_temp = 0
	optimal_ph_min = 0
	optimal_ph_max = 14
	determin_ph_range = 0
	temp_exponent_factor = 1
	ph_exponent_factor = 1
	thermic_constant = -50 //This is the part that cools things down now
	H_ion_release = 0
	rate_up_lim = 4
	purity_min = 0.15
	reaction_flags = REACTION_HEAT_ARBITARY
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE

/datum/chemical_reaction/pyrosium_oxygen
	results = list(/datum/reagent/pyrosium = 1)
	required_reagents = list(/datum/reagent/pyrosium = 1, /datum/reagent/oxygen = 1)
	mob_react = FALSE
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE

/datum/chemical_reaction/pyrosium_oxygen/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	holder.chem_temp += 10*created_volume

/datum/chemical_reaction/pyrosium
	results = list(/datum/reagent/pyrosium = 3)
	required_reagents = list(/datum/reagent/stable_plasma = 1, /datum/reagent/uranium/radium = 1, /datum/reagent/phosphorus = 1)
	required_temp = 0
	optimal_temp = 20
	overheat_temp = NO_OVERHEAT
	temp_exponent_factor = 10
	thermic_constant = 0
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE

/datum/chemical_reaction/pyrosium/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	holder.chem_temp = 20 // also cools the fuck down
	return

/datum/chemical_reaction/teslium
	results = list(/datum/reagent/teslium = 3)
	required_reagents = list(/datum/reagent/stable_plasma = 1, /datum/reagent/silver = 1, /datum/reagent/gunpowder = 1)
	mix_message = "A jet of sparks flies from the mixture as it merges into a flickering slurry."
	required_temp = 400
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE

/datum/chemical_reaction/energized_jelly
	results = list(/datum/reagent/teslium/energized_jelly = 2)
	required_reagents = list(/datum/reagent/toxin/slimejelly = 1, /datum/reagent/teslium = 1)
	mix_message = "The slime jelly starts glowing intermittently."
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DANGEROUS | REACTION_TAG_HEALING | REACTION_TAG_OTHER

/datum/chemical_reaction/reagent_explosion/teslium_lightning
	required_reagents = list(/datum/reagent/teslium = 1, /datum/reagent/water = 1)
	strengthdiv = 100
	modifier = -100
	mix_message = "The teslium starts to spark as electricity arcs away from it!"
	mix_sound = 'sound/machines/defib_zap.ogg'
	var/zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_MOB_STUN | ZAP_LOW_POWER_GEN
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_EXPLOSIVE | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/T1 = created_volume * 20		//100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison.
	var/T2 = created_volume * 50
	var/T3 = created_volume * 120
	var/added_delay = 0.5 SECONDS
	if(created_volume >= 75)
		addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T1), added_delay)
		added_delay += 1.5 SECONDS
	if(created_volume >= 40)
		addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T2), added_delay)
		added_delay += 1.5 SECONDS
	if(created_volume >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
		addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T3), added_delay)
	addtimer(CALLBACK(src, .proc/default_explode, holder, created_volume), added_delay)

/datum/chemical_reaction/reagent_explosion/teslium_lightning/proc/zappy_zappy(datum/reagents/holder, power)
	if(QDELETED(holder.my_atom))
		return
	tesla_zap(holder.my_atom, 7, power, zap_flags)
	playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, TRUE)

/datum/chemical_reaction/reagent_explosion/teslium_lightning/heat
	required_temp = 474
	required_reagents = list(/datum/reagent/teslium = 1)

/datum/chemical_reaction/reagent_explosion/nitrous_oxide
	required_reagents = list(/datum/reagent/nitrous_oxide = 1)
	strengthdiv = 9
	required_temp = 575
	modifier = 1

/datum/chemical_reaction/reagent_explosion/nitrous_oxide/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	holder.remove_reagent(/datum/reagent/sorium, created_volume*2)
	var/turf/turfie = get_turf(holder.my_atom)
	//generally half as strong as sorium.
	var/range = clamp(sqrt(created_volume*2), 1, 6)
	//This first throws people away and then it explodes
	goonchem_vortex(turfie, 1, range)
	turfie.atmos_spawn_air("o2=[created_volume/2];TEMP=[575]")
	turfie.atmos_spawn_air("n2=[created_volume/2];TEMP=[575]")
	return ..()

/datum/chemical_reaction/firefighting_foam
	results = list(/datum/reagent/firefighting_foam = 3)
	required_reagents = list(/datum/reagent/stabilizing_agent = 1,/datum/reagent/fluorosurfactant = 1,/datum/reagent/carbon = 1)
	required_temp = 200
	is_cold_recipe = 1
	optimal_temp = 50
	overheat_temp = 5
	thermic_constant= -1
	H_ion_release = -0.02
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_UNIQUE

/datum/chemical_reaction/reagent_explosion/patriotism_overload
	required_reagents = list(/datum/reagent/consumable/ethanol/planet_cracker = 1, /datum/reagent/consumable/ethanol/triumphal_arch = 1)
	strengthdiv = 20
	mix_message = "The two patriotic drinks instantly reject each other!"


code:
/datum/chemical_reaction/basic_buffer
	results = list(/datum/reagent/reaction_agent/basic_buffer = 10)
	required_reagents = list(/datum/reagent/ammonia = 3, /datum/reagent/chlorine = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2) //vagely NH4OH + NH4Cl buffer
	mix_message = "The solution fizzes in the beaker."
	//FermiChem vars:
	required_temp = 250
	optimal_temp = 500
	overheat_temp = NO_OVERHEAT
	optimal_ph_min = 0
	optimal_ph_max = 14
	determin_ph_range = 0
	temp_exponent_factor = 4
	ph_exponent_factor = 0
	thermic_constant = 0
	H_ion_release = 0.01
	rate_up_lim = 15
	purity_min = 0
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL

/datum/chemical_reaction/acidic_buffer
	results = list(/datum/reagent/reaction_agent/acidic_buffer = 10)
	required_reagents = list(/datum/reagent/sodium = 2, /datum/reagent/hydrogen = 2, /datum/reagent/consumable/ethanol = 2, /datum/reagent/water = 2)
	mix_message = "The solution froths in the beaker."
	required_temp = 250
	optimal_temp = 500
	overheat_temp = NO_OVERHEAT
	optimal_ph_min = 0
	optimal_ph_max = 14
	determin_ph_range = 0
	temp_exponent_factor = 4
	ph_exponent_factor = 0
	thermic_constant = 0
	H_ion_release = -0.01
	rate_up_lim = 20
	purity_min = 0
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// Example competitive reaction (REACTION_COMPETITIVE)  //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/datum/chemical_reaction/prefactor_a
	results = list(/datum/reagent/prefactor_a = 5)
	required_reagents = list(/datum/reagent/phenol = 1, /datum/reagent/consumable/ethanol = 3, /datum/reagent/toxin/plasma = 1)
	mix_message = "The solution's viscosity increases."
	is_cold_recipe = TRUE
	required_temp = 800
	optimal_temp = 300
	overheat_temp = -1 //no overheat
	optimal_ph_min = 2
	optimal_ph_max = 12
	determin_ph_range = 5
	temp_exponent_factor = 1
	ph_exponent_factor = 0
	thermic_constant = -400
	H_ion_release = 0
	rate_up_lim = 4
	purity_min = 0.25
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL | REACTION_TAG_COMPETITIVE

/datum/chemical_reaction/prefactor_b
	results = list(/datum/reagent/prefactor_b = 5)
	required_reagents = list(/datum/reagent/prefactor_a = 5)
	mix_message = "The solution's viscosity decreases."
	mix_sound = 'sound/chemistry/bluespace.ogg' //Maybe use this elsewhere instead
	required_temp = 50
	optimal_temp = 500
	overheat_temp = 500
	optimal_ph_min = 5
	optimal_ph_max = 8
	determin_ph_range = 5
	temp_exponent_factor = 1
	ph_exponent_factor = 2
	thermic_constant = -800
	H_ion_release = -0.02
	rate_up_lim = 6
	purity_min = 0.35
	reaction_flags = REACTION_COMPETITIVE //Competes with /datum/chemical_reaction/prefactor_a/competitive
	reaction_tags = REACTION_TAG_MODERATE | REACTION_TAG_DANGEROUS | REACTION_TAG_CHEMICAL | REACTION_TAG_COMPETITIVE

/datum/chemical_reaction/prefactor_b/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol)
	. = ..()
	if(holder.has_reagent(/datum/reagent/bluespace))
		holder.remove_reagent(/datum/reagent/bluespace, 1)
		reaction.delta_t *= 5

/datum/chemical_reaction/prefactor_b/overheated(datum/reagents/holder, datum/equilibrium/equilibrium, step_volume_added)
	. = ..()
	explode_shockwave(holder, equilibrium)
	var/vol = max(20, holder.total_volume/5) //Not letting you have more than 5
	clear_reagents(holder, vol)//Lest we explode forever

/datum/chemical_reaction/prefactor_b/overly_impure(datum/reagents/holder, datum/equilibrium/equilibrium, step_volume_added)
	explode_fire(holder, equilibrium)
	var/vol = max(20, holder.total_volume/5) //Not letting you have more than 5
	clear_reagents(holder, vol)

/datum/chemical_reaction/prefactor_a/competitive //So we have a back and forth reaction
	results = list(/datum/reagent/prefactor_a = 5)
	required_reagents = list(/datum/reagent/prefactor_b = 5)
	rate_up_lim = 3
	reaction_flags = REACTION_COMPETITIVE //Competes with /datum/chemical_reaction/prefactor_b
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL | REACTION_TAG_COMPETITIVE

//The actual results
/datum/chemical_reaction/prefactor_a/purity_tester
	results = list(/datum/reagent/reaction_agent/purity_tester = 5)
	required_reagents = list(/datum/reagent/prefactor_a = 5, /datum/reagent/stable_plasma = 5)
	H_ion_release = 0.05
	thermic_constant = 0
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_CHEMICAL | REACTION_TAG_COMPETITIVE

/datum/chemical_reaction/prefactor_b/speed_agent
	results = list(/datum/reagent/reaction_agent/speed_agent = 5)
	required_reagents = list(/datum/reagent/prefactor_b = 5, /datum/reagent/stable_plasma = 5)
	H_ion_release = -0.15
	thermic_constant = 0
	reaction_tags = REACTION_TAG_HARD | REACTION_TAG_DANGEROUS | REACTION_TAG_CHEMICAL | REACTION_TAG_COMPETITIVE

////////////////////////////////End example/////////////////////////////////////////////////////////////////////////////

repo_name: AnalWerewolf/sundown

license: mit


code:
/datum/chemical_reaction/slime
	var/deletes_extract = TRUE
	reaction_flags = REACTION_INSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME

/datum/chemical_reaction/slime/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	use_slime_core(holder)

/datum/chemical_reaction/slime/proc/use_slime_core(datum/reagents/holder)
	SSblackbox.record_feedback("tally", "slime_cores_used", 1, "type")
	if(deletes_extract)
		delete_extract(holder)

/datum/chemical_reaction/slime/proc/delete_extract(datum/reagents/holder)
	var/obj/item/slime_extract/M = holder.my_atom
	if(M.Uses <= 0 && !results.len) //if the slime doesn't output chemicals
		qdel(M)

//Grey
/datum/chemical_reaction/slime/slimespawn
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/grey
	required_other = TRUE

/datum/chemical_reaction/slime/slimespawn/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/mob/living/simple_animal/slime/S = new(get_turf(holder.my_atom), "grey")
	S.visible_message(span_danger("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!"))
	..()

/datum/chemical_reaction/slime/slimeinaprov
	results = list(/datum/reagent/medicine/epinephrine = 3)
	required_reagents = list(/datum/reagent/water = 5)
	required_other = TRUE
	required_container = /obj/item/slime_extract/grey

/datum/chemical_reaction/slime/slimemonkey
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/grey
	required_other = TRUE

/datum/chemical_reaction/slime/slimemonkey/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	for(var/i in 1 to 3)
		new /obj/item/food/monkeycube(get_turf(holder.my_atom))
	..()

//Green
/datum/chemical_reaction/slime/slimemutate
	results = list(/datum/reagent/mutationtoxin/jelly = 1)
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/green

/datum/chemical_reaction/slime/slimehuman
	results = list(/datum/reagent/mutationtoxin = 1)
	required_reagents = list(/datum/reagent/blood = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/green

/datum/chemical_reaction/slime/slimelizard
	results = list(/datum/reagent/mutationtoxin/lizard = 1)
	required_reagents = list(/datum/reagent/uranium/radium = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/green

//Metal
/datum/chemical_reaction/slime/slimemetal
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/metal
	required_other = TRUE

/datum/chemical_reaction/slime/slimemetal/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/location = get_turf(holder.my_atom)
	new /obj/item/stack/sheet/plasteel(location, 5)
	new /obj/item/stack/sheet/iron(location, 15)
	..()

/datum/chemical_reaction/slime/slimeglass
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/metal
	required_other = TRUE

/datum/chemical_reaction/slime/slimeglass/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/location = get_turf(holder.my_atom)
	new /obj/item/stack/sheet/rglass(location, 5)
	new /obj/item/stack/sheet/glass(location, 15)
	..()

//Gold
/datum/chemical_reaction/slime/slimemobspawn
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/gold
	required_other = TRUE
	deletes_extract = FALSE //we do delete, but we don't do so instantly
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/slime/slimemobspawn/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	summon_mobs(holder, T)
	var/obj/item/slime_extract/M = holder.my_atom
	deltimer(M.qdel_timer)
	..()
	M.qdel_timer = addtimer(CALLBACK(src, .proc/delete_extract, holder), 55, TIMER_STOPPABLE)

/datum/chemical_reaction/slime/slimemobspawn/proc/summon_mobs(datum/reagents/holder, turf/T)
	T.visible_message(span_danger("The slime extract begins to vibrate violently!"))
	addtimer(CALLBACK(src, .proc/chemical_mob_spawn, holder, 5, "Gold Slime", HOSTILE_SPAWN), 50)

/datum/chemical_reaction/slime/slimemobspawn/lesser
	required_reagents = list(/datum/reagent/blood = 1)

/datum/chemical_reaction/slime/slimemobspawn/lesser/summon_mobs(datum/reagents/holder, turf/T)
	T.visible_message(span_danger("The slime extract begins to vibrate violently!"))
	addtimer(CALLBACK(src, .proc/chemical_mob_spawn, holder, 3, "Lesser Gold Slime", HOSTILE_SPAWN, "neutral"), 50)

/datum/chemical_reaction/slime/slimemobspawn/friendly
	required_reagents = list(/datum/reagent/water = 1)

/datum/chemical_reaction/slime/slimemobspawn/friendly/summon_mobs(datum/reagents/holder, turf/T)
	T.visible_message(span_danger("The slime extract begins to vibrate adorably!"))
	addtimer(CALLBACK(src, .proc/chemical_mob_spawn, holder, 1, "Friendly Gold Slime", FRIENDLY_SPAWN, "neutral"), 50)

/datum/chemical_reaction/slime/slimemobspawn/spider
	required_reagents = list(/datum/reagent/spider_extract = 1)
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/slime/slimemobspawn/spider/summon_mobs(datum/reagents/holder, turf/T)
	T.visible_message(span_danger("The slime extract begins to vibrate crikey-ingly!"))
	addtimer(CALLBACK(src, .proc/chemical_mob_spawn, holder, 3, "Traitor Spider Slime", /mob/living/simple_animal/hostile/giant_spider/midwife, "neutral", FALSE), 50)

//Silver
/datum/chemical_reaction/slime/slimebork
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/silver
	required_other = TRUE

/datum/chemical_reaction/slime/slimebork/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	//BORK BORK BORK
	var/turf/T = get_turf(holder.my_atom)

	playsound(T, 'sound/effects/phasein.ogg', 100, TRUE)

	for(var/mob/living/carbon/C in viewers(T, null))
		C.flash_act()

	for(var/i in 1 to 4 + rand(1,2))
		var/chosen = getbork()
		var/obj/item/food_item = new chosen(T)
		if(prob(5))//Fry it!
			var/obj/item/food/deepfryholder/fried
			fried = new(T, food_item)
			fried.fry() // actually set the name and colour it
		if(prob(50))
			for(var/j in 1 to rand(1, 3))
				step(food_item, pick(NORTH,SOUTH,EAST,WEST))
	..()

/datum/chemical_reaction/slime/slimebork/proc/getbork()
	return get_random_food()

/datum/chemical_reaction/slime/slimebork/drinks
	required_reagents = list(/datum/reagent/water = 1)

/datum/chemical_reaction/slime/slimebork/drinks/getbork()
	return get_random_drink()

//Blue
/datum/chemical_reaction/slime/slimefrost
	results = list(/datum/reagent/consumable/frostoil = 10)
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/blue
	required_other = TRUE

/datum/chemical_reaction/slime/slimestabilizer
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/blue
	required_other = TRUE

/datum/chemical_reaction/slime/slimestabilizer/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/stabilizer(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimefoam
	required_reagents = list(/datum/reagent/water = 5)
	required_container = /obj/item/slime_extract/blue
	required_other = TRUE

/datum/chemical_reaction/slime/slimefoam/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	holder.create_foam(/datum/effect_system/foam_spread,80, span_danger("[src] spews out foam!"))

//Dark Blue
/datum/chemical_reaction/slime/slimefreeze
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/darkblue
	required_other = TRUE
	deletes_extract = FALSE

/datum/chemical_reaction/slime/slimefreeze/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	T.visible_message(span_danger("The slime extract starts to feel extremely cold!"))
	addtimer(CALLBACK(src, .proc/freeze, holder), 50)
	var/obj/item/slime_extract/M = holder.my_atom
	deltimer(M.qdel_timer)
	..()
	M.qdel_timer = addtimer(CALLBACK(src, .proc/delete_extract, holder), 55, TIMER_STOPPABLE)

/datum/chemical_reaction/slime/slimefreeze/proc/freeze(datum/reagents/holder)
	if(holder?.my_atom)
		var/turf/open/T = get_turf(holder.my_atom)
		if(istype(T))
			var/datum/gas/gastype = /datum/gas/nitrogen
			T.atmos_spawn_air("[initial(gastype.id)]=50;TEMP=2.7")

/datum/chemical_reaction/slime/slimefireproof
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/darkblue
	required_other = TRUE

/datum/chemical_reaction/slime/slimefireproof/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/fireproof(get_turf(holder.my_atom))
	..()

//Orange
/datum/chemical_reaction/slime/slimecasp
	results = list(/datum/reagent/consumable/capsaicin = 10)
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/orange
	required_other = TRUE

/datum/chemical_reaction/slime/slimefire
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/orange
	required_other = TRUE
	deletes_extract = FALSE

/datum/chemical_reaction/slime/slimefire/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	T.visible_message(span_danger("The slime extract begins to vibrate adorably!"))
	addtimer(CALLBACK(src, .proc/slime_burn, holder), 50)
	var/obj/item/slime_extract/M = holder.my_atom
	deltimer(M.qdel_timer)
	..()
	M.qdel_timer = addtimer(CALLBACK(src, .proc/delete_extract, holder), 55, TIMER_STOPPABLE)

/datum/chemical_reaction/slime/slimefire/proc/slime_burn(datum/reagents/holder)
	if(holder?.my_atom)
		var/turf/open/T = get_turf(holder.my_atom)
		if(istype(T))
			T.atmos_spawn_air("plasma=50;TEMP=1000")

/datum/chemical_reaction/slime/slimesmoke
	results = list(/datum/reagent/phosphorus = 10, /datum/reagent/potassium = 10, /datum/reagent/consumable/sugar = 10)
	required_reagents = list(/datum/reagent/water = 5)
	required_container = /obj/item/slime_extract/orange
	required_other = TRUE

//Yellow
/datum/chemical_reaction/slime/slimeoverload
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/yellow
	required_other = TRUE
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/slime/slimeoverload/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	empulse(get_turf(holder.my_atom), 3, 7)
	..()

/datum/chemical_reaction/slime/slimecell
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/yellow
	required_other = TRUE

/datum/chemical_reaction/slime/slimecell/on_reaction(datum/reagents/holder, created_volume)
	new /obj/item/stock_parts/cell/emproof/slime(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimeglow
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/yellow
	required_other = TRUE

/datum/chemical_reaction/slime/slimeglow/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	T.visible_message(span_danger("The slime begins to emit a soft light. Squeezing it will cause it to grow brightly."))
	new /obj/item/flashlight/slime(T)
	..()

//Purple
/datum/chemical_reaction/slime/slimepsteroid
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/purple
	required_other = TRUE

/datum/chemical_reaction/slime/slimepsteroid/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/steroid(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimeregen
	results = list(/datum/reagent/medicine/regen_jelly = 5)
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/purple
	required_other = TRUE

//Dark Purple
/datum/chemical_reaction/slime/slimeplasma
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/darkpurple
	required_other = TRUE

/datum/chemical_reaction/slime/slimeplasma/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/stack/sheet/mineral/plasma(get_turf(holder.my_atom), 3)
	..()

//Red
/datum/chemical_reaction/slime/slimemutator
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/red
	required_other = TRUE

/datum/chemical_reaction/slime/slimemutator/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/mutator(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimebloodlust
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/red
	required_other = TRUE
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/slime/slimebloodlust/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	for(var/mob/living/simple_animal/slime/slime in viewers(get_turf(holder.my_atom), null))
		if(slime.docile) //Undoes docility, but doesn't make rabid.
			slime.visible_message(span_danger("[slime] forgets its training, becoming wild once again!"))
			slime.docile = FALSE
			slime.update_name()
			continue
		slime.rabid = 1
		slime.visible_message(span_danger("The [slime] is driven into a frenzy!"))
	..()

/datum/chemical_reaction/slime/slimespeed
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/red
	required_other = TRUE

/datum/chemical_reaction/slime/slimespeed/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/speed(get_turf(holder.my_atom))
	..()

//Pink
/datum/chemical_reaction/slime/docility
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/pink
	required_other = TRUE

/datum/chemical_reaction/slime/docility/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/docility(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/gender
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/pink
	required_other = TRUE

/datum/chemical_reaction/slime/gender/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/genderchange(get_turf(holder.my_atom))
	..()

//Black
/datum/chemical_reaction/slime/slimemutate2
	results = list(/datum/reagent/aslimetoxin = 1)
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/black

//Oil
/datum/chemical_reaction/slime/slimeexplosion
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/oil
	required_other = TRUE
	deletes_extract = FALSE
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_SLIME | REACTION_TAG_DANGEROUS

/datum/chemical_reaction/slime/slimeexplosion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	var/lastkey = holder.my_atom.fingerprintslast
	var/touch_msg = "N/A"
	if(lastkey)
		var/mob/toucher = get_mob_by_key(lastkey)
		touch_msg = "[ADMIN_LOOKUPFLW(toucher)]."
	message_admins("Slime Explosion reaction started at [ADMIN_VERBOSEJMP(T)]. Last Fingerprint: [touch_msg]")
	log_game("Slime Explosion reaction started at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"].")
	T.visible_message(span_danger("The slime extract begins to vibrate violently !"))
	addtimer(CALLBACK(src, .proc/boom, holder), 50)
	var/obj/item/slime_extract/M = holder.my_atom
	deltimer(M.qdel_timer)
	..()
	M.qdel_timer = addtimer(CALLBACK(src, .proc/delete_extract, holder), 55, TIMER_STOPPABLE)

/datum/chemical_reaction/slime/slimeexplosion/proc/boom(datum/reagents/holder)
	if(holder?.my_atom)
		explosion(holder.my_atom, devastation_range = 1, heavy_impact_range = 3, light_impact_range = 6, explosion_cause = src)

/datum/chemical_reaction/slime/slimecornoil
	results = list(/datum/reagent/consumable/cornoil = 10)
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/oil
	required_other = TRUE

//Light Pink
/datum/chemical_reaction/slime/slimepotion2
	required_container = /obj/item/slime_extract/lightpink
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_other = TRUE

/datum/chemical_reaction/slime/slimepotion2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/sentience(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/renaming
	required_container = /obj/item/slime_extract/lightpink
	required_reagents = list(/datum/reagent/water = 1)
	required_other = TRUE

/datum/chemical_reaction/slime/renaming/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/renaming(holder.my_atom.drop_location())
	..()

//Adamantine
/datum/chemical_reaction/slime/adamantine
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/adamantine
	required_other = TRUE

/datum/chemical_reaction/slime/adamantine/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/stack/sheet/mineral/adamantine(get_turf(holder.my_atom))
	..()

//Bluespace
/datum/chemical_reaction/slime/slimefloor2
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/bluespace
	required_other = TRUE

/datum/chemical_reaction/slime/slimefloor2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/stack/tile/bluespace(get_turf(holder.my_atom), 25)
	..()

/datum/chemical_reaction/slime/slimecrystal
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/bluespace
	required_other = TRUE

/datum/chemical_reaction/slime/slimecrystal/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/obj/item/stack/ore/bluespace_crystal/BC = new (get_turf(holder.my_atom))
	BC.visible_message(span_notice("The [BC.name] appears out of thin air!"))
	..()

/datum/chemical_reaction/slime/slimeradio
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/bluespace
	required_other = TRUE

/datum/chemical_reaction/slime/slimeradio/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/slime/slimeradio(get_turf(holder.my_atom))
	..()

//Cerulean
/datum/chemical_reaction/slime/slimepsteroid2
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/cerulean
	required_other = TRUE

/datum/chemical_reaction/slime/slimepsteroid2/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slime_territory
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/cerulean
	required_other = TRUE

/datum/chemical_reaction/slime/slime_territory/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/areaeditor/blueprints/slime(get_turf(holder.my_atom))
	..()

//Sepia
/datum/chemical_reaction/slime/slimestop
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/sepia
	required_other = TRUE

/datum/chemical_reaction/slime/slimestop/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	addtimer(CALLBACK(src, .proc/slime_stop, holder), 5 SECONDS)

/datum/chemical_reaction/slime/slimestop/proc/slime_stop(datum/reagents/holder)
	var/obj/item/slime_extract/sepia/extract = holder.my_atom
	var/turf/T = get_turf(holder.my_atom)
	new /obj/effect/timestop(T, null, null, null)
	if(istype(extract))
		if(extract.Uses > 0)
			var/mob/lastheld = get_mob_by_key(holder.my_atom.fingerprintslast)
			if(lastheld && !lastheld.equip_to_slot_if_possible(extract, ITEM_SLOT_HANDS, disable_warning = TRUE))
				extract.forceMove(get_turf(lastheld))
	use_slime_core(holder)

/datum/chemical_reaction/slime/slimecamera
	required_reagents = list(/datum/reagent/water = 1)
	required_container = /obj/item/slime_extract/sepia
	required_other = TRUE

/datum/chemical_reaction/slime/slimecamera/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/camera(get_turf(holder.my_atom))
	new /obj/item/camera_film(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimefloor
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/sepia
	required_other = TRUE

/datum/chemical_reaction/slime/slimefloor/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/stack/tile/sepia(get_turf(holder.my_atom), 25)
	..()

//Pyrite
/datum/chemical_reaction/slime/slimepaint
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_container = /obj/item/slime_extract/pyrite
	required_other = TRUE

/datum/chemical_reaction/slime/slimepaint/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/chosen = pick(subtypesof(/obj/item/paint))
	new chosen(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/slimecrayon
	required_reagents = list(/datum/reagent/blood = 1)
	required_container = /obj/item/slime_extract/pyrite
	required_other = TRUE

/datum/chemical_reaction/slime/slimecrayon/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/chosen = pick(difflist(subtypesof(/obj/item/toy/crayon),typesof(/obj/item/toy/crayon/spraycan)))
	new chosen(get_turf(holder.my_atom))
	..()

//Rainbow :o)
/datum/chemical_reaction/slime/slime_rng
	required_reagents = list(/datum/reagent/toxin/plasma = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/rainbow

/datum/chemical_reaction/slime/slime_rng/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	if(created_volume >= 5)
		var/obj/item/grenade/clusterbuster/slime/S = new (get_turf(holder.my_atom))
		S.visible_message(span_danger("Infused with plasma, the core begins to expand uncontrollably!"))
		S.icon_state = "[S.base_state]_active"
		S.active = TRUE
		addtimer(CALLBACK(S, /obj/item/grenade.proc/detonate), rand(15,60))
	else
		var/mob/living/simple_animal/slime/random/S = new (get_turf(holder.my_atom))
		S.visible_message(span_danger("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!"))
	..()

/datum/chemical_reaction/slime/slimebomb
	required_reagents = list(/datum/reagent/toxin/slimejelly = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/rainbow

/datum/chemical_reaction/slime/slimebomb/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	var/turf/T = get_turf(holder.my_atom)
	var/obj/item/grenade/clusterbuster/slime/volatile/S = new (T)
	S.visible_message(span_danger("Infused with slime jelly, the core begins to expand uncontrollably!"))
	S.icon_state = "[S.base_state]_active"
	S.active = TRUE
	addtimer(CALLBACK(S, /obj/item/grenade.proc/detonate), rand(15,60))
	var/lastkey = holder.my_atom.fingerprintslast
	var/touch_msg = "N/A"
	if(lastkey)
		var/mob/toucher = get_mob_by_key(lastkey)
		touch_msg = "[ADMIN_LOOKUPFLW(toucher)]."
	message_admins("Brorble Brorble primed at [ADMIN_VERBOSEJMP(T)]. Last Fingerprint: [touch_msg]")
	log_game("Brorble Brorble primed at [AREACOORD(T)]. Last Fingerprint: [lastkey ? lastkey : "N/A"].")
	..()

/datum/chemical_reaction/slime/slime_transfer
	required_reagents = list(/datum/reagent/blood = 1)
	required_other = TRUE
	required_container = /obj/item/slime_extract/rainbow

/datum/chemical_reaction/slime/slime_transfer/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/slimepotion/transference(get_turf(holder.my_atom))
	..()

/datum/chemical_reaction/slime/flight_potion
	required_reagents = list(/datum/reagent/water/holywater = 5, /datum/reagent/uranium = 5)
	required_other = TRUE
	required_container = /obj/item/slime_extract/rainbow

/datum/chemical_reaction/slime/flight_potion/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume)
	new /obj/item/reagent_containers/glass/bottle/potion/flight(get_turf(holder.my_atom))
	..()


code:
GLOBAL_LIST_INIT(food_reagents, build_reagents_to_food()) //reagentid = related food types
GLOBAL_LIST_INIT(medicine_reagents, build_medicine_reagents())

/proc/build_reagents_to_food()
	. = list()
	for (var/type in subtypesof(/obj/item/reagent_containers/food))
		var/obj/item/reagent_containers/food/item = new type()
		for(var/r in item.list_reagents)
			if (!.[r])
				.[r] = list()
			.[r] += type
		qdel(item)
	//dang plant snowflake
	for (var/type in subtypesof(/obj/item/seeds))
		var/obj/item/seeds/item = new type()
		for(var/r in item.reagents_add)
			if (!.[r])
				.[r] = list()
			.[r] += type
		qdel(item)

///Just grab every craftable medicine you can think off
/proc/build_medicine_reagents()
	. = list()

	for(var/A in subtypesof(/datum/reagent/medicine))
		var/datum/reagent/R = A
		if(initial(R.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED)
			. += R

#define RNGCHEM_INPUT "input"
#define RNGCHEM_CATALYSTS "catalysts"
#define RNGCHEM_OUTPUT "output"

/datum/chemical_reaction/randomized

	//Increase default leniency because these are already hard enough
	optimal_ph_min = 1
	optimal_ph_max = 13
	temp_exponent_factor = 0
	ph_exponent_factor = 1
	H_ion_release = 0

	var/persistent = FALSE
	var/persistence_period = 7 //Will reset every x days
	var/created //creation timestamp

	var/randomize_container = FALSE
	var/list/possible_containers = list()

	var/randomize_req_temperature = TRUE
	var/min_temp = 1
	var/max_temp = 600
	///If the reaction can be exothermic or endothermic randomly too
	var/exo_or_endothermic = FALSE

	///If pH is randomised
	var/randomize_req_ph = FALSE
	///Lowest pH value possible
	var/min_ph = 0
	///Highest pH value possible
	var/max_ph = 14
	///How much the range can deviate, and also affects impure range
	var/inoptimal_range_ph = 3

	///If the impurity failure threshold is randomized between 0 - 0.4
	var/randomize_impurity_minimum = FALSE
	///If the impure/inverse/failure reagents are randomized
	var/randomize_impurity_reagents = FALSE

	var/randomize_inputs = TRUE
	var/min_input_reagent_amount = 1
	var/max_input_reagent_amount = 10
	var/min_input_reagents = 2
	var/max_input_reagents = 5
	var/list/possible_reagents = list()
	var/min_catalysts = 0
	var/max_catalysts = 2
	var/list/possible_catalysts = list()

	var/randomize_results = FALSE
	var/min_output_reagent_amount = 1
	var/max_output_reagent_amount = 5
	var/min_result_reagents = 1
	var/max_result_reagents = 1
	var/list/possible_results = list()

/datum/chemical_reaction/randomized/proc/GenerateRecipe()
	created = world.realtime
	if(randomize_container)
		required_container = pick(possible_containers)
	if(randomize_req_temperature)
		is_cold_recipe = pick(TRUE,FALSE)
		if(is_cold_recipe)
			required_temp = rand(min_temp+50, max_temp)
			optimal_temp = rand(min_temp+25, required_temp-10)
			overheat_temp = rand(min_temp, optimal_temp-10)
			if(overheat_temp >= 200) //Otherwise it can disappear when you're mixing and I don't want this to happen here
				overheat_temp = 200
			if(exo_or_endothermic)
				thermic_constant = (rand(-200, 200))
		else
			required_temp = rand(min_temp, max_temp-50)
			optimal_temp = rand(required_temp+10, max_temp-25)
			overheat_temp = rand(optimal_temp, max_temp+50)
			if(overheat_temp <= 400)
				overheat_temp = 400
			if(exo_or_endothermic)
				thermic_constant = (rand(-200, 200))

	if(randomize_req_ph)
		optimal_ph_min = min_ph + rand(0, inoptimal_range_ph)
		optimal_ph_max = max((max_ph + rand(0, inoptimal_range_ph)), (min_ph + 1)) //Always ensure we've a window of 1
		determin_ph_range = inoptimal_range_ph
		H_ion_release = (rand(0, 25)/100)// 0 - 0.25

	if(randomize_impurity_minimum)
		purity_min = (rand(0, 4)/10)

	if(randomize_impurity_reagents)
		for(var/rid in required_reagents)
			var/datum/reagent/R = GLOB.chemical_reagents_list[rid]
			R.impure_chem = get_random_reagent_id()
			R.inverse_chem = get_random_reagent_id()
			R.failed_chem = get_random_reagent_id()

	if(randomize_results)
		results = list()
		var/list/remaining_possible_results = GetPossibleReagents(RNGCHEM_OUTPUT)
		var/out_reagent_count = min(rand(min_result_reagents,max_result_reagents),remaining_possible_results.len)
		for(var/i in 1 to out_reagent_count)
			var/r_id = pick_n_take(remaining_possible_results)
			results[r_id] = rand(min_output_reagent_amount,max_output_reagent_amount)

	if(randomize_inputs)
		var/list/remaining_possible_reagents = GetPossibleReagents(RNGCHEM_INPUT)
		var/list/remaining_possible_catalysts = GetPossibleReagents(RNGCHEM_CATALYSTS)
		//We're going to assume we're not doing any weird partial reactions for now.
		for(var/reagent_type in results)
			remaining_possible_catalysts -= reagent_type
			remaining_possible_reagents -= reagent_type

		var/in_reagent_count = min(rand(min_input_reagents,max_input_reagents),remaining_possible_reagents.len)
		if(in_reagent_count <= 0)
			return FALSE

		required_reagents = list()
		for(var/i in 1 to in_reagent_count)
			var/r_id = pick_n_take(remaining_possible_reagents)
			required_reagents[r_id] = rand(min_input_reagent_amount,max_input_reagent_amount)
			remaining_possible_catalysts -= r_id //Can't have same reagents both as catalyst and reagent. Or can we ?

		required_catalysts = list()
		var/in_catalyst_count = min(rand(min_catalysts,max_catalysts),remaining_possible_catalysts.len)
		for(var/i in 1 to in_catalyst_count)
			var/r_id = pick_n_take(remaining_possible_catalysts)
			required_catalysts[r_id] = rand(min_input_reagent_amount,max_input_reagent_amount)

	return TRUE

/datum/chemical_reaction/randomized/proc/GetPossibleReagents(kind)
	switch(kind)
		if(RNGCHEM_INPUT)
			return possible_reagents.Copy()
		if(RNGCHEM_CATALYSTS)
			return possible_catalysts.Copy()
		if(RNGCHEM_OUTPUT)
			return possible_results.Copy()

/datum/chemical_reaction/randomized/proc/HasConflicts()
	for(var/x in required_reagents)
		for(var/datum/chemical_reaction/R in GLOB.chemical_reactions_list_reactant_index[x])
			if(chem_recipes_do_conflict(R,src))
				return TRUE
	return FALSE

/datum/chemical_reaction/randomized/proc/unwrap_reagent_list(list/textreagents)
	. = list()
	for(var/R in textreagents)
		var/pathR = text2path(R)
		if(!pathR)
			return null
		.[pathR] = textreagents[R]

/datum/chemical_reaction/randomized/proc/LoadOldRecipe(recipe_data)
	created = text2num(recipe_data["timestamp"])

	var/req_reag = unwrap_reagent_list(recipe_data["required_reagents"])
	if(!req_reag)
		return FALSE
	required_reagents = req_reag

	var/req_catalysts = unwrap_reagent_list(recipe_data["required_catalysts"])
	if(!req_catalysts)
		return FALSE
	required_catalysts = req_catalysts

	is_cold_recipe = recipe_data["is_cold_recipe"]
	required_temp = recipe_data["required_temp"]
	optimal_temp = recipe_data["optimal_temp"]
	overheat_temp = recipe_data["overheat_temp"]
	thermic_constant = recipe_data["thermic_constant"]

	optimal_ph_min = recipe_data["optimal_ph_min"]
	optimal_ph_max = recipe_data["optimal_ph_max"]
	determin_ph_range = recipe_data["determin_ph_range"]
	H_ion_release = recipe_data["H_ion_release"]

	purity_min = recipe_data["purity_min"]

	var/temp_results = unwrap_reagent_list(recipe_data["results"])
	if(!temp_results)
		return FALSE
	results = temp_results
	var/raw_container_path = recipe_data["required_container"]
	if(raw_container_path)
		var/containerpath = text2path(raw_container_path)
		if(!containerpath)
			return FALSE
		required_container =  containerpath
	return TRUE

/datum/chemical_reaction/randomized/secret_sauce
	persistent = TRUE
	persistence_period = 7 //Reset every week
	randomize_container = TRUE
	possible_containers = list(/obj/item/reagent_containers/glass/bucket) //easy way to ensure no common conflicts
	randomize_req_temperature = TRUE
	results = list(/datum/reagent/consumable/secretsauce=1)

/datum/chemical_reaction/randomized/secret_sauce/GetPossibleReagents(kind)
	switch(kind)
		if(RNGCHEM_INPUT,RNGCHEM_CATALYSTS)
			var/food_reagent_ids = list()
			for(var/key in GLOB.food_reagents)
				food_reagent_ids += key
			return food_reagent_ids
	return ..()

///Random recipe for meme chem metalgen. Always requires wittel and resets every 3 days
/datum/chemical_reaction/randomized/metalgen
	persistent = TRUE
	persistence_period = 3 //Resets every three days. It's the ultimate meme and is best not worn out
	randomize_req_temperature = TRUE
	possible_catalysts = list(/datum/reagent/wittel)
	min_catalysts = 1
	max_catalysts = 1
	results = list(/datum/reagent/metalgen=20)

/datum/chemical_reaction/randomized/metalgen/GetPossibleReagents(kind)
	switch(kind)
		if(RNGCHEM_INPUT)
			return GLOB.medicine_reagents
	return ..()

/obj/item/paper/secretrecipe
	name = "old recipe"

	///List of possible recipes we could display
	var/list/possible_recipes = list(/datum/chemical_reaction/randomized/secret_sauce, /datum/chemical_reaction/randomized/metalgen)
	///The one we actually end up displaying
	var/recipe_id = null

/obj/item/paper/secretrecipe/Initialize(mapload)
	. = ..()

	recipe_id = pick(possible_recipes)

	if(SSpersistence.initialized)
		UpdateInfo()
	else
		SSticker.OnRoundstart(CALLBACK(src,.proc/UpdateInfo))

/obj/item/paper/secretrecipe/ui_static_data(mob/living/user)
	. = ..()
	if(!istype(user) || user.stat == DEAD)
		.["text"] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \
		sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \
		Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris \
		nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in \
		reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \
		pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa \
		qui officia deserunt mollit anim id est laborum."

/obj/item/paper/secretrecipe/proc/UpdateInfo()
	var/datum/chemical_reaction/recipe = get_chemical_reaction(recipe_id)
	if(!recipe)
		info = "This recipe is illegible."
		return
	var/list/dat = list("
")
	for(var/rid in recipe.required_reagents)
		var/datum/reagent/R = GLOB.chemical_reagents_list[rid]
		dat += "
[recipe.required_reagents[rid]]u of [R.name]
"
	dat += "
"
	if(recipe.required_catalysts.len)
		dat += "With following present:
"
		for(var/rid in recipe.required_catalysts)
			var/datum/reagent/R = GLOB.chemical_reagents_list[rid]
			dat += "
[recipe.required_catalysts[rid]]u of [R.name]
"
		dat += "
"
	dat += "
Mix slowly
"
	if(recipe.required_container)
		var/obj/item/I = recipe.required_container
		dat += "
 in a [initial(I.name)]
"
	if(recipe.required_temp != 0)
		if(recipe.is_cold_recipe)
			dat += "
cooling it below [recipe.required_temp] degrees"
			dat += " but not below [recipe.overheat_temp] degrees
"
		else
			dat += "
heating it above [recipe.required_temp] degrees"
			dat += " but not above [recipe.overheat_temp] degrees"
		if(recipe.thermic_constant > 0)
			dat += "
 taking care of it's exothermic nature
"
		else if(recipe.thermic_constant < 0)
			dat += "
 taking care of it's endothermic nature
"
	var/datum/chemical_reaction/randomized/random_recipe = recipe
	if(random_recipe)
		if(random_recipe.randomize_req_ph)
			dat += "
 keeping your pH between [recipe.optimal_ph_min] and [recipe.optimal_ph_max]
"
		if(random_recipe.randomize_impurity_minimum)
			dat += "
 and your purity above [recipe.purity_min]
"
	dat += "
"
	dat += "."
	info = dat.Join("")
	update_appearance()


code:
/datum/chemical_reaction/formaldehyde
	results = list(/datum/reagent/toxin/formaldehyde = 3)
	required_reagents = list(/datum/reagent/consumable/ethanol = 1, /datum/reagent/oxygen = 1, /datum/reagent/silver = 1)
	mix_message = "The mixture fizzles and gives off a fierce smell."
	is_cold_recipe = FALSE
	required_temp = 420
	optimal_temp = 520
	overheat_temp = 900
	optimal_ph_min = 0
	optimal_ph_max = 7
	determin_ph_range = 2
	temp_exponent_factor = 2
	ph_exponent_factor = 1.2
	thermic_constant = 200
	H_ion_release = -3
	rate_up_lim = 15
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_CHEMICAL | REACTION_TAG_BRUTE | REACTION_TAG_TOXIN

/datum/chemical_reaction/fentanyl
	results = list(/datum/reagent/toxin/fentanyl = 1)
	required_reagents = list(/datum/reagent/drug/space_drugs = 1)
	mix_message = "The mixture turns cloudy, then becomes clear again."
	is_cold_recipe = FALSE
	required_temp = 674
	optimal_temp = 774
	overheat_temp = 874
	optimal_ph_min = 7
	optimal_ph_max = 11
	determin_ph_range = 3
	temp_exponent_factor = 0.7
	ph_exponent_factor = 10
	thermic_constant = 50
	H_ion_release = 3
	rate_up_lim = 5
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_ORGAN | REACTION_TAG_TOXIN

/datum/chemical_reaction/cyanide
	results = list(/datum/reagent/toxin/cyanide = 3)
	required_reagents = list(/datum/reagent/fuel/oil = 1, /datum/reagent/ammonia = 1, /datum/reagent/oxygen = 1)
	mix_message = "The mixture emits the faint smell of almonds."
	is_cold_recipe = FALSE
	required_temp = 380
	optimal_temp = 420
	overheat_temp = NO_OVERHEAT
	optimal_ph_min = 9
	optimal_ph_max = 11
	determin_ph_range = 3
	temp_exponent_factor = 0.7
	ph_exponent_factor = 2
	thermic_constant = -300
	H_ion_release = 3.2
	rate_up_lim = 10
	purity_min = 0.4
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OXY | REACTION_TAG_TOXIN

/datum/chemical_reaction/itching_powder
	results = list(/datum/reagent/toxin/itching_powder = 3)
	required_reagents = list(/datum/reagent/fuel = 1, /datum/reagent/ammonia = 1, /datum/reagent/medicine/c2/multiver = 1)
	mix_message = "The mixture emits nose-irritating fumes."
	is_cold_recipe = FALSE
	required_temp = 280
	optimal_temp = 360
	overheat_temp = 700
	optimal_ph_min = 5
	optimal_ph_max = 9
	determin_ph_range = 4
	temp_exponent_factor = 0.7
	ph_exponent_factor = 1.5
	thermic_constant = -200
	H_ion_release = 5.7
	rate_up_lim = 20
	purity_min = 0.3
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_BRUTE

/datum/chemical_reaction/facid
	results = list(/datum/reagent/toxin/acid/fluacid = 4)
	required_reagents = list(/datum/reagent/toxin/acid = 1, /datum/reagent/fluorine = 1, /datum/reagent/hydrogen = 1, /datum/reagent/potassium = 1)
	mix_message = "The mixture bubbles fiercly."
	is_cold_recipe = FALSE
	required_temp = 380
	optimal_temp = 680
	overheat_temp = 800
	optimal_ph_min = 0
	optimal_ph_max = 2
	determin_ph_range = 5
	temp_exponent_factor = 2
	ph_exponent_factor = 10
	thermic_constant = -200
	H_ion_release = -25
	rate_up_lim = 20
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_PLANT | REACTION_TAG_BURN | REACTION_TAG_TOXIN

/datum/chemical_reaction/nitracid
	results = list(/datum/reagent/toxin/acid/nitracid = 2)
	required_reagents = list(/datum/reagent/toxin/acid/fluacid = 1, /datum/reagent/nitrogen = 1,  /datum/reagent/hydrogen_peroxide = 1)
	mix_message = "The mixture bubbles fiercly and gives off a pungent smell."
	is_cold_recipe = FALSE
	required_temp = 480
	optimal_temp = 680
	overheat_temp = 900
	optimal_ph_min = 0
	optimal_ph_max = 4.1
	determin_ph_range = 5
	temp_exponent_factor = 2
	ph_exponent_factor = 10
	thermic_constant = -200
	H_ion_release = -20
	rate_up_lim = 20
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_BURN | REACTION_TAG_TOXIN

/datum/chemical_reaction/sulfonal
	results = list(/datum/reagent/toxin/sulfonal = 3)
	required_reagents = list(/datum/reagent/acetone = 1, /datum/reagent/diethylamine = 1, /datum/reagent/sulfur = 1)
	mix_message = "The mixture changes color and becomes clear."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 4
	optimal_ph_max = 9
	determin_ph_range = 2
	temp_exponent_factor = 1.5
	ph_exponent_factor = 1.5
	thermic_constant = 200
	H_ion_release = 5
	rate_up_lim = 10
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_TOXIN | REACTION_TAG_OTHER

/datum/chemical_reaction/lipolicide
	results = list(/datum/reagent/toxin/lipolicide = 3)
	required_reagents = list(/datum/reagent/mercury = 1, /datum/reagent/diethylamine = 1, /datum/reagent/medicine/ephedrine = 1)
	mix_message = "The mixture becomes cloudy."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 4
	optimal_ph_max = 8.5
	determin_ph_range = 2
	temp_exponent_factor = 1
	ph_exponent_factor = 0.2
	thermic_constant = 500
	H_ion_release = 2.5
	rate_up_lim = 10
	purity_min = 0.7
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/mutagen
	results = list(/datum/reagent/toxin/mutagen = 3)
	required_reagents = list(/datum/reagent/uranium/radium = 1, /datum/reagent/phosphorus = 1, /datum/reagent/chlorine = 1)
	mix_message = "The mixture glows faintly, then stops."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 3
	optimal_ph_max = 9
	determin_ph_range = 1
	temp_exponent_factor = 2
	ph_exponent_factor = 5
	thermic_constant = 350
	H_ion_release = 0.1
	rate_up_lim = 10
	purity_min = 0.7
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_PLANT | REACTION_TAG_OTHER

/datum/chemical_reaction/lexorin
	results = list(/datum/reagent/toxin/lexorin = 3)
	required_reagents = list(/datum/reagent/toxin/plasma = 1, /datum/reagent/hydrogen = 1, /datum/reagent/medicine/salbutamol = 1)
	mix_message = "The mixture turns clear and stops reacting."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 1.8
	optimal_ph_max = 7
	determin_ph_range = 3
	temp_exponent_factor = 2
	ph_exponent_factor = 5
	thermic_constant = -400
	H_ion_release = 0.1
	rate_up_lim = 25
	purity_min = 0.4
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OXY

/datum/chemical_reaction/hot_ice_melt
	results = list(/datum/reagent/toxin/plasma = 12) //One sheet of hot ice makes 200m of plasma
	required_reagents = list(/datum/reagent/toxin/hot_ice = 1)
	required_temp = T0C + 30 //Don't burst into flames when you melt
	thermic_constant = -200//Counter the heat
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_CHEMICAL | REACTION_TAG_TOXIN

/datum/chemical_reaction/chloralhydrate
	results = list(/datum/reagent/toxin/chloralhydrate = 1)
	required_reagents = list(/datum/reagent/consumable/ethanol = 1, /datum/reagent/chlorine = 3, /datum/reagent/water = 1)
	mix_message = "The mixture turns deep blue."
	is_cold_recipe = FALSE
	required_temp = 200
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 7
	optimal_ph_max = 9
	determin_ph_range = 2
	temp_exponent_factor = 2
	ph_exponent_factor = 2
	thermic_constant = 250
	H_ion_release = 2
	rate_up_lim = 10
	purity_min = 0.6
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/mutetoxin //i'll just fit this in here snugly between other unfun chemicals :v
	results = list(/datum/reagent/toxin/mutetoxin = 2)
	required_reagents = list(/datum/reagent/uranium = 2, /datum/reagent/water = 1, /datum/reagent/carbon = 1)
	mix_message = "The mixture calms down."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 6
	optimal_ph_max = 14
	determin_ph_range = 2
	temp_exponent_factor = 3
	ph_exponent_factor = 1
	thermic_constant = -250
	H_ion_release = -0.2
	rate_up_lim = 15
	purity_min = 0.4
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/zombiepowder
	results = list(/datum/reagent/toxin/zombiepowder = 2)
	required_reagents = list(/datum/reagent/toxin/carpotoxin = 5, /datum/reagent/medicine/morphine = 5, /datum/reagent/copper = 5)
	mix_message = "The mixture turns into a strange green powder."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 5
	optimal_ph_max = 14
	determin_ph_range = 2
	temp_exponent_factor = 3
	ph_exponent_factor = 1
	thermic_constant = 150
	H_ion_release = -0.25
	rate_up_lim = 15
	purity_min = 0.3
	reaction_flags = REACTION_CLEAR_IMPURE
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/ghoulpowder
	results = list(/datum/reagent/toxin/ghoulpowder = 2)
	required_reagents = list(/datum/reagent/toxin/zombiepowder = 1, /datum/reagent/medicine/epinephrine = 1)
	mix_message = "The mixture turns into a strange brown powder."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 5
	optimal_ph_max = 14
	determin_ph_range = 2
	temp_exponent_factor = 3
	ph_exponent_factor = 1
	thermic_constant = 150
	H_ion_release = -0.25
	rate_up_lim = 15
	purity_min = 0.4
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/mindbreaker
	results = list(/datum/reagent/toxin/mindbreaker = 5)
	required_reagents = list(/datum/reagent/silicon = 1, /datum/reagent/hydrogen = 1, /datum/reagent/medicine/c2/multiver = 1)
	mix_message = "The mixture turns into a vivid red liquid."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 6
	optimal_ph_max = 14
	determin_ph_range = 3
	temp_exponent_factor = 2.5
	ph_exponent_factor = 2
	thermic_constant = 150
	H_ion_release = -0.06
	rate_up_lim = 15
	purity_min = 0.4
	reaction_flags = REACTION_CLEAR_IMPURE
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/heparin
	results = list(/datum/reagent/toxin/heparin = 4)
	required_reagents = list(/datum/reagent/toxin/formaldehyde = 1, /datum/reagent/sodium = 1, /datum/reagent/chlorine = 1, /datum/reagent/lithium = 1)
	mix_message = "The mixture thins and loses all color."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 800
	optimal_ph_min = 5
	optimal_ph_max = 9.5
	determin_ph_range = 3
	temp_exponent_factor = 2.5
	ph_exponent_factor = 2
	thermic_constant = 375
	H_ion_release = -0.6
	rate_up_lim = 10
	purity_min = 0.6
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/rotatium
	results = list(/datum/reagent/toxin/rotatium = 3)
	required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/teslium = 1, /datum/reagent/toxin/fentanyl = 1)
	mix_message = "After sparks, fire, and the smell of mindbreaker, the mix is constantly spinning with no stop in sight."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 3
	optimal_ph_max = 9
	determin_ph_range = 2.5
	temp_exponent_factor = 2.5
	ph_exponent_factor = 2
	thermic_constant = -425
	H_ion_release = 4
	rate_up_lim = 15
	purity_min = 0.6
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_TOXIN | REACTION_TAG_OTHER

/datum/chemical_reaction/anacea
	results = list(/datum/reagent/toxin/anacea = 3)
	required_reagents = list(/datum/reagent/medicine/haloperidol = 1, /datum/reagent/impedrezene = 1, /datum/reagent/uranium/radium = 1)
	mix_message = "The mixture turns into a strange green ooze."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 6
	optimal_ph_max = 9
	determin_ph_range = 4
	temp_exponent_factor = 1.6
	ph_exponent_factor = 2.4
	thermic_constant = 250
	H_ion_release = 3
	rate_up_lim = 10
	purity_min = 0.7
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_TOXIN | REACTION_TAG_OTHER

/datum/chemical_reaction/mimesbane
	results = list(/datum/reagent/toxin/mimesbane = 3)
	required_reagents = list(/datum/reagent/uranium/radium = 1, /datum/reagent/toxin/mutetoxin = 1, /datum/reagent/consumable/nothing = 1)
	mix_message = "The mixture turns into an indescribable white."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 0
	optimal_ph_max = 8
	determin_ph_range = 4
	temp_exponent_factor = 1.5
	ph_exponent_factor = 3
	thermic_constant = -400
	H_ion_release = -2
	rate_up_lim = 15
	purity_min = 0.5
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER

/datum/chemical_reaction/bonehurtingjuice
	results = list(/datum/reagent/toxin/bonehurtingjuice = 5)
	required_reagents = list(/datum/reagent/toxin/mutagen = 1, /datum/reagent/toxin/itching_powder = 3, /datum/reagent/consumable/milk = 1)
	mix_message = "The mixture suddenly becomes clear and looks a lot like water. You feel a strong urge to drink it."
	is_cold_recipe = FALSE
	required_temp = 100
	optimal_temp = 450
	overheat_temp = 900
	optimal_ph_min = 5
	optimal_ph_max = 9
	determin_ph_range = 3
	temp_exponent_factor = 0.5
	ph_exponent_factor = 1
	thermic_constant = -400
	H_ion_release = -0.4
	rate_up_lim = 15
	purity_min = 0.4
	reaction_flags = REACTION_PH_VOL_CONSTANT
	reaction_tags = REACTION_TAG_EASY | REACTION_TAG_DAMAGING | REACTION_TAG_OTHER


code:
/obj/item/reagent_containers
	name = "Container"
	desc = "..."
	icon = 'icons/obj/chemical.dmi'
	icon_state = null
	w_class = WEIGHT_CLASS_TINY
	var/amount_per_transfer_from_this = 5
	var/list/possible_transfer_amounts = list(5,10,15,20,25,30)
	/// Where we are in the possible transfer amount list.
	var/amount_list_position = 1
	var/volume = 30
	var/reagent_flags
	var/list/list_reagents = null
	var/spawned_disease = null
	var/disease_amount = 20
	var/spillable = FALSE
	var/list/fill_icon_thresholds = null
	var/fill_icon_state = null // Optional custom name for reagent fill icon_state prefix

/obj/item/reagent_containers/Initialize(mapload, vol)
	. = ..()
	if(isnum(vol) && vol > 0)
		volume = vol
	create_reagents(volume, reagent_flags)
	if(spawned_disease)
		var/datum/disease/F = new spawned_disease()
		var/list/data = list("viruses"= list(F))
		reagents.add_reagent(/datum/reagent/blood, disease_amount, data)

	add_initial_reagents()

/obj/item/reagent_containers/examine()
	. = ..()
	if(possible_transfer_amounts.len > 1)
		. += span_notice("Left-click or right-click in-hand to increase or decrease its transfer amount.")
	else if(possible_transfer_amounts.len)
		. += span_notice("Left-click or right-click in-hand to view its transfer amount.")

/obj/item/reagent_containers/create_reagents(max_vol, flags)
	. = ..()
	RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change)
	RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del)

/obj/item/reagent_containers/attack(mob/living/M, mob/living/user, params)
	//if (!user.combat_mode) //SEPTIC EDIT REMOVAL
	//SEPTIC EDIT BEGIN
	if(IS_HELP_INTENT(user, params2list(params)))
	//SEPTIC EDIT END
		return
	return ..()

/obj/item/reagent_containers/proc/on_reagents_del(datum/reagents/reagents)
	SIGNAL_HANDLER
	UnregisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_PARENT_QDELETING))
	return NONE

/obj/item/reagent_containers/proc/add_initial_reagents()
	if(list_reagents)
		reagents.add_reagent_list(list_reagents)

/obj/item/reagent_containers/attack_self(mob/user)
	change_transfer_amount(user, FORWARD)

/obj/item/reagent_containers/attack_self_secondary(mob/user)
	change_transfer_amount(user, BACKWARD)

/obj/item/reagent_containers/proc/mode_change_message(mob/user)
	return

/obj/item/reagent_containers/proc/change_transfer_amount(mob/user, direction = FORWARD)
	var/list_len = length(possible_transfer_amounts)
	if(!list_len)
		return
	switch(direction)
		if(FORWARD)
			amount_list_position = (amount_list_position % list_len) + 1
		if(BACKWARD)
			amount_list_position = (amount_list_position - 1) || list_len
		else
			CRASH("change_transfer_amount() called with invalid direction value")
	amount_per_transfer_from_this = possible_transfer_amounts[amount_list_position]
	balloon_alert(user, "transferring [amount_per_transfer_from_this]u")
	mode_change_message(user)

/obj/item/reagent_containers/pre_attack_secondary(atom/target, mob/living/user, params)
	if(HAS_TRAIT(target, DO_NOT_SPLASH))
		return ..()
	if (try_splash(user, target))
		return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN

	return ..()

/// Tries to splash the target. Used on both right-click and normal click when in combat mode.
/obj/item/reagent_containers/proc/try_splash(mob/user, atom/target)
	if (!spillable)
		return FALSE

	if (!reagents?.total_volume)
		return FALSE

	var/punctuation = ismob(target) ? "!" : "."

	var/reagent_text
	user.visible_message(
		span_danger("[user] splashes the contents of [src] onto [target][punctuation]"),
		span_danger("You splash the contents of [src] onto [target][punctuation]"),
		ignored_mobs = target,
	)

	if (ismob(target))
		var/mob/target_mob = target
		target_mob.show_message(
			span_userdanger("[user] splash the contents of [src] onto you!"),
			MSG_VISUAL,
			span_userdanger("You feel drenched!"),
		)

	for(var/datum/reagent/reagent as anything in reagents.reagent_list)
		reagent_text += "[reagent] ([num2text(reagent.volume)]),"

	var/mob/thrown_by = thrownby?.resolve()
	if(isturf(target) && reagents.reagent_list.len && thrown_by)
		log_combat(thrown_by, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
		message_admins("[ADMIN_LOOKUPFLW(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")

	reagents.expose(target, TOUCH)
	log_combat(user, target, "splashed", reagent_text)
	reagents.clear_reagents()

	return TRUE

/obj/item/reagent_containers/proc/canconsume(mob/eater, mob/user)
	if(!iscarbon(eater))
		return FALSE
	var/mob/living/carbon/C = eater
	var/covered = ""
	if(C.is_mouth_covered(head_only = 1))
		covered = "headgear"
	else if(C.is_mouth_covered(mask_only = 1))
		covered = "mask"
	if(covered)
		var/who = (isnull(user) || eater == user) ? "your" : "[eater.p_their()]"
		to_chat(user, span_warning("You have to remove [who] [covered] first!"))
		return FALSE
	return TRUE

/*
 * On accidental consumption, transfer a portion of the reagents to the eater and the item it's in, then continue to the base proc (to deal with shattering glass containers)
 */
/obj/item/reagent_containers/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item,  discover_after = TRUE)
	M.losebreath += 2
	reagents?.trans_to(M, min(15, reagents.total_volume / rand(5,10)), transfered_by = user, methods = INGEST)
	if(source_item?.reagents)
		reagents.trans_to(source_item, min(source_item.reagents.total_volume / 2, reagents.total_volume / 5), transfered_by = user, methods = TOUCH)

	return ..()

/obj/item/reagent_containers/ex_act(severity)
	if(reagents)
		for(var/datum/reagent/R in reagents.reagent_list)
			R.on_ex_act(severity)
	if(!QDELETED(src))
		return ..()

/obj/item/reagent_containers/fire_act(exposed_temperature, exposed_volume)
	reagents.expose_temperature(exposed_temperature)
	..()

/obj/item/reagent_containers/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
	. = ..()
	SplashReagents(hit_atom, TRUE)

/obj/item/reagent_containers/proc/bartender_check(atom/target)
	. = FALSE
	var/mob/thrown_by = thrownby?.resolve()
	if(target.CanPass(src, get_dir(target, src)) && thrown_by && HAS_TRAIT(thrown_by, TRAIT_BOOZE_SLIDER))
		. = TRUE

/obj/item/reagent_containers/proc/SplashReagents(atom/target, thrown = FALSE, override_spillable = FALSE)
	if(!reagents || !reagents.total_volume || (!spillable && !override_spillable))
		return
	var/mob/thrown_by = thrownby?.resolve()

	if(ismob(target) && target.reagents)
		if(thrown)
			reagents.total_volume *= rand(5,10) * 0.1 //Not all of it makes contact with the target
		var/mob/M = target
		var/R
		target.visible_message(span_danger("[M] is splashed with something!"), \
						span_userdanger("[M] is splashed with something!"))
		for(var/datum/reagent/A in reagents.reagent_list)
			R += "[A.type]  ([num2text(A.volume)]),"

		if(thrown_by)
			log_combat(thrown_by, M, "splashed", R)
		reagents.expose(target, TOUCH)

	else if(bartender_check(target) && thrown)
		visible_message(span_notice("[src] lands onto the [target.name] without spilling a single drop."))
		return

	else
		if(isturf(target) && reagents.reagent_list.len && thrown_by)
			log_combat(thrown_by, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]")
			log_game("[key_name(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [AREACOORD(target)].")
			message_admins("[ADMIN_LOOKUPFLW(thrown_by)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] in [ADMIN_VERBOSEJMP(target)].")
		visible_message(span_notice("[src] spills its contents all over [target]."))
		reagents.expose(target, TOUCH)
		if(QDELETED(src))
			return

	reagents.clear_reagents()

/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
	reagents.expose_temperature(1000)
	..()

/obj/item/reagent_containers/fire_act(temperature, volume)
	reagents.expose_temperature(temperature)

/// Updates the icon of the container when the reagents change. Eats signal args
/obj/item/reagent_containers/proc/on_reagent_change(datum/reagents/holder, ...)
	SIGNAL_HANDLER
	update_appearance()
	return NONE

/obj/item/reagent_containers/update_overlays()
	. = ..()
	if(!fill_icon_thresholds)
		return
	if(!reagents.total_volume)
		return

	var/fill_name = fill_icon_state? fill_icon_state : icon_state
	var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "[fill_name][fill_icon_thresholds[1]]")

	var/percent = round((reagents.total_volume / volume) * 100)
	for(var/i in 1 to fill_icon_thresholds.len)
		var/threshold = fill_icon_thresholds[i]
		var/threshold_end = (i == fill_icon_thresholds.len)? INFINITY : fill_icon_thresholds[i+1]
		if(threshold <= percent && percent < threshold_end)
			filling.icon_state = "[fill_name][fill_icon_thresholds[i]]"

	filling.color = mix_color_from_reagents(reagents.reagent_list)
	. += filling


code:
/obj/item/reagent_containers/blood
	name = "blood pack"
	desc = "Contains blood used for transfusion. Must be attached to an IV drip."
	icon = 'icons/obj/bloodpack.dmi'
	icon_state = "bloodpack"
	volume = 200
	var/blood_type = null
	var/unique_blood = null
	var/labelled = FALSE
	fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)

/obj/item/reagent_containers/blood/Initialize(mapload)
	. = ..()
	if(blood_type != null)
		reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null))
		update_appearance()

/// Handles updating the container when the reagents change.
/obj/item/reagent_containers/blood/on_reagent_change(datum/reagents/holder, ...)
	var/datum/reagent/blood/new_reagent = holder.has_reagent(/datum/reagent/blood)
	if(new_reagent && new_reagent.data && new_reagent.data["blood_type"])
		blood_type = new_reagent.data["blood_type"]
	else if(holder.has_reagent(/datum/reagent/consumable/liquidelectricity))
		blood_type = "LE"
	else
		blood_type = null
	return ..()

/obj/item/reagent_containers/blood/update_name(updates)
	. = ..()
	if(labelled)
		return
	name = "blood pack[blood_type ? " - [blood_type]" : null]"

/obj/item/reagent_containers/blood/random
	icon_state = "random_bloodpack"

/obj/item/reagent_containers/blood/random/Initialize(mapload)
	icon_state = "bloodpack"
	blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L")
	return ..()

/obj/item/reagent_containers/blood/a_plus
	blood_type = "A+"

/obj/item/reagent_containers/blood/a_minus
	blood_type = "A-"

/obj/item/reagent_containers/blood/b_plus
	blood_type = "B+"

/obj/item/reagent_containers/blood/b_minus
	blood_type = "B-"

/obj/item/reagent_containers/blood/o_plus
	blood_type = "O+"

/obj/item/reagent_containers/blood/o_minus
	blood_type = "O-"

/obj/item/reagent_containers/blood/lizard
	blood_type = "L"

/obj/item/reagent_containers/blood/ethereal
	blood_type = "LE"
	unique_blood = /datum/reagent/consumable/liquidelectricity

/obj/item/reagent_containers/blood/universal
	blood_type = "U"

/obj/item/reagent_containers/blood/attackby(obj/item/tool, mob/user, params)
	if (istype(tool, /obj/item/pen) || istype(tool, /obj/item/toy/crayon))
		if(!user.is_literate())
			to_chat(user, span_notice("You scribble illegibly on the label of [src]!"))
			return
		var/custom_label = stripped_input(user, "What would you like to label the blood pack?", name, null, 53)
		if(!user.canUseTopic(src, BE_CLOSE))
			return
		if(user.get_active_held_item() != tool)
			return
		if(custom_label)
			labelled = TRUE
			name = "blood pack - [custom_label]"
			balloon_alert(user, "new label set")
		else
			labelled = FALSE
			update_name()
	else
		return ..()