code:
/*
Recurring extracts:
	Generates a new charge every few seconds.
	If depleted of its' last charge, stops working.
*/
/obj/item/slimecross/recurring
	name = "recurring extract"
	desc = "A tiny, glowing core, wrapped in several layers of goo."
	effect = "recurring"
	icon_state = "recurring"
	var/extract_type
	var/obj/item/slime_extract/extract
	var/cooldown = 0
	var/max_cooldown = 10 // In seconds

/obj/item/slimecross/recurring/Initialize(mapload)
	. = ..()
	extract = new extract_type(src.loc)
	visible_message(span_notice("[src] wraps a layer of goo around itself!"))
	extract.name = name
	extract.desc = desc
	extract.icon = icon
	extract.icon_state = icon_state
	extract.color = color
	extract.recurring = TRUE
	src.forceMove(extract)
	START_PROCESSING(SSobj,src)

/obj/item/slimecross/recurring/process(delta_time)
	if(cooldown > 0)
		cooldown -= delta_time
	else if(extract.Uses < 10 && extract.Uses > 0)
		extract.Uses++
		cooldown = max_cooldown
	else if(extract.Uses <= 0)
		extract.visible_message(span_warning("The light inside [extract] flickers and dies out."))
		extract.desc = "A tiny, inert core, bleeding dark, cerulean-colored goo."
		extract.icon_state = "prismatic"
		qdel(src)

/obj/item/slimecross/recurring/Destroy()
	. = ..()
	STOP_PROCESSING(SSobj,src)

/obj/item/slimecross/recurring/grey
	extract_type = /obj/item/slime_extract/grey
	colour = "grey"

/obj/item/slimecross/recurring/orange
	extract_type = /obj/item/slime_extract/orange
	colour = "orange"

/obj/item/slimecross/recurring/purple
	extract_type = /obj/item/slime_extract/purple
	colour = "purple"

/obj/item/slimecross/recurring/blue
	extract_type = /obj/item/slime_extract/blue
	colour = "blue"

/obj/item/slimecross/recurring/metal
	extract_type = /obj/item/slime_extract/metal
	colour = "metal"
	max_cooldown = 20

/obj/item/slimecross/recurring/yellow
	extract_type = /obj/item/slime_extract/yellow
	colour = "yellow"
	max_cooldown = 20

/obj/item/slimecross/recurring/darkpurple
	extract_type = /obj/item/slime_extract/darkpurple
	colour = "dark purple"
	max_cooldown = 20

/obj/item/slimecross/recurring/darkblue
	extract_type = /obj/item/slime_extract/darkblue
	colour = "dark blue"

/obj/item/slimecross/recurring/silver
	extract_type = /obj/item/slime_extract/silver
	colour = "silver"

/obj/item/slimecross/recurring/bluespace
	extract_type = /obj/item/slime_extract/bluespace
	colour = "bluespace"

/obj/item/slimecross/recurring/sepia
	extract_type = /obj/item/slime_extract/sepia
	colour = "sepia"
	max_cooldown = 36 //No infinite timestop for you!

/obj/item/slimecross/recurring/cerulean
	extract_type = /obj/item/slime_extract/cerulean
	colour = "cerulean"

/obj/item/slimecross/recurring/pyrite
	extract_type = /obj/item/slime_extract/pyrite
	colour = "pyrite"

/obj/item/slimecross/recurring/red
	extract_type = /obj/item/slime_extract/red
	colour = "red"

/obj/item/slimecross/recurring/green
	extract_type = /obj/item/slime_extract/green
	colour = "green"

/obj/item/slimecross/recurring/pink
	extract_type = /obj/item/slime_extract/pink
	colour = "pink"

/obj/item/slimecross/recurring/gold
	extract_type = /obj/item/slime_extract/gold
	colour = "gold"
	max_cooldown = 30

/obj/item/slimecross/recurring/oil
	extract_type = /obj/item/slime_extract/oil
	colour = "oil" //Why would you want this?

/obj/item/slimecross/recurring/black
	extract_type = /obj/item/slime_extract/black
	colour = "black"

/obj/item/slimecross/recurring/lightpink
	extract_type = /obj/item/slime_extract/lightpink
	colour = "light pink"

/obj/item/slimecross/recurring/adamantine
	extract_type = /obj/item/slime_extract/adamantine
	colour = "adamantine"
	max_cooldown = 20

/obj/item/slimecross/recurring/rainbow
	extract_type = /obj/item/slime_extract/rainbow
	colour = "rainbow"
	max_cooldown = 40 //It's pretty powerful.


code:
/*
Regenerative extracts:
	Work like a legion regenerative core.
	Has a unique additional effect.
*/
/obj/item/slimecross/regenerative
	name = "regenerative extract"
	desc = "It's filled with a milky substance, and pulses like a heartbeat."
	effect = "regenerative"
	icon_state = "regenerative"

/obj/item/slimecross/regenerative/proc/core_effect(mob/living/carbon/human/target, mob/user)
	return
/obj/item/slimecross/regenerative/proc/core_effect_before(mob/living/carbon/human/target, mob/user)
	return

/obj/item/slimecross/regenerative/afterattack(atom/target,mob/user,prox)
	. = ..()
	if(!prox || !isliving(target))
		return
	var/mob/living/H = target
	if(H.stat == DEAD)
		to_chat(user, span_warning("[src] will not work on the dead!"))
		return
	if(H != user)
		user.visible_message(span_notice("[user] crushes [src] over [H], the milky goo quickly regenerating all of [H.p_their()] injuries!"),
			span_notice("You squeeze [src], and it bursts over [H], the milky goo regenerating [H.p_their()] injuries."))
	else
		user.visible_message(span_notice("[user] crushes [src] over [user.p_them()]self, the milky goo quickly regenerating all of [user.p_their()] injuries!"),
			span_notice("You squeeze [src], and it bursts in your hand, splashing you with milky goo which quickly regenerates your injuries!"))
	core_effect_before(H, user)
	H.revive(full_heal = TRUE, admin_revive = FALSE)
	core_effect(H, user)
	playsound(target, 'sound/effects/splat.ogg', 40, TRUE)
	qdel(src)

/obj/item/slimecross/regenerative/grey
	colour = "grey" //Has no bonus effect.
	effect_desc = "Fully heals the target and does nothing else."

/obj/item/slimecross/regenerative/orange
	colour = "orange"

/obj/item/slimecross/regenerative/orange/core_effect_before(mob/living/target, mob/user)
	target.visible_message(span_warning("The [src] boils over!"))
	for(var/turf/targetturf in RANGE_TURFS(1,target))
		if(!locate(/obj/effect/hotspot) in targetturf)
			new /obj/effect/hotspot(targetturf)

/obj/item/slimecross/regenerative/purple
	colour = "purple"
	effect_desc = "Fully heals the target and injects them with some regen jelly."

/obj/item/slimecross/regenerative/purple/core_effect(mob/living/target, mob/user)
	target.reagents.add_reagent(/datum/reagent/medicine/regen_jelly,10)

/obj/item/slimecross/regenerative/blue
	colour = "blue"
	effect_desc = "Fully heals the target and makes the floor wet."

/obj/item/slimecross/regenerative/blue/core_effect(mob/living/target, mob/user)
	if(isturf(target.loc))
		var/turf/open/T = get_turf(target)
		T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
		target.visible_message(span_warning("The milky goo in the extract gets all over the floor!"))

/obj/item/slimecross/regenerative/metal
	colour = "metal"
	effect_desc = "Fully heals the target and encases the target in a locker."

/obj/item/slimecross/regenerative/metal/core_effect(mob/living/target, mob/user)
	target.visible_message(span_warning("The milky goo hardens and reshapes itself, encasing [target]!"))
	var/obj/structure/closet/C = new /obj/structure/closet(target.loc)
	C.name = "slimy closet"
	C.desc = "Looking closer, it seems to be made of a sort of solid, opaque, metal-like goo."
	target.forceMove(C)

/obj/item/slimecross/regenerative/yellow
	colour = "yellow"
	effect_desc = "Fully heals the target and fully recharges a single item on the target."

/obj/item/slimecross/regenerative/yellow/core_effect(mob/living/target, mob/user)
	var/list/batteries = list()
	for(var/obj/item/stock_parts/cell/C in target.get_all_contents())
		if(C.charge < C.maxcharge)
			batteries += C
	if(batteries.len)
		var/obj/item/stock_parts/cell/ToCharge = pick(batteries)
		ToCharge.charge = ToCharge.maxcharge
		to_chat(target, span_notice("You feel a strange electrical pulse, and one of your electrical items was recharged."))

/obj/item/slimecross/regenerative/darkpurple
	colour = "dark purple"
	effect_desc = "Fully heals the target and gives them purple clothing if they are naked."

/obj/item/slimecross/regenerative/darkpurple/core_effect(mob/living/target, mob/user)
	var/equipped = 0
	equipped += target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/purple(null), ITEM_SLOT_FEET)
	equipped += target.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(null), ITEM_SLOT_ICLOTHING)
	equipped += target.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/purple(null), ITEM_SLOT_GLOVES)
	equipped += target.equip_to_slot_or_del(new /obj/item/clothing/head/soft/purple(null), ITEM_SLOT_HEAD)
	if(equipped > 0)
		target.visible_message(span_notice("The milky goo congeals into clothing!"))

/obj/item/slimecross/regenerative/darkblue
	colour = "dark blue"
	effect_desc = "Fully heals the target and fireproofs their clothes."

/obj/item/slimecross/regenerative/darkblue/core_effect(mob/living/target, mob/user)
	if(!ishuman(target))
		return
	var/mob/living/carbon/human/H = target
	var/fireproofed = FALSE
	if(H.get_item_by_slot(ITEM_SLOT_OCLOTHING))
		fireproofed = TRUE
		var/obj/item/clothing/C = H.get_item_by_slot(ITEM_SLOT_OCLOTHING)
		fireproof(C)
	if(H.get_item_by_slot(ITEM_SLOT_HEAD))
		fireproofed = TRUE
		var/obj/item/clothing/C = H.get_item_by_slot(ITEM_SLOT_HEAD)
		fireproof(C)
	if(fireproofed)
		target.visible_message(span_notice("Some of [target]'s clothing gets coated in the goo, and turns blue!"))

/obj/item/slimecross/regenerative/darkblue/proc/fireproof(obj/item/clothing/C)
	C.name = "fireproofed [C.name]"
	C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
	C.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY)
	C.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
	C.heat_protection = C.body_parts_covered
	C.resistance_flags |= FIRE_PROOF

/obj/item/slimecross/regenerative/silver
	colour = "silver"
	effect_desc = "Fully heals the target and makes their belly feel round and full."

/obj/item/slimecross/regenerative/silver/core_effect(mob/living/target, mob/user)
	target.set_nutrition(NUTRITION_LEVEL_FULL - 1)
	to_chat(target, span_notice("You feel satiated."))

/obj/item/slimecross/regenerative/bluespace
	colour = "bluespace"
	effect_desc = "Fully heals the target and teleports them to where this core was created."
	var/turf/open/T

/obj/item/slimecross/regenerative/bluespace/core_effect(mob/living/target, mob/user)
	var/turf/old_location = get_turf(target)
	if(do_teleport(target, T, channel = TELEPORT_CHANNEL_QUANTUM)) //despite being named a bluespace teleportation method the quantum channel is used to preserve precision teleporting with a bag of holding
		old_location.visible_message(span_warning("[target] disappears in a shower of sparks!"))
		to_chat(target, span_danger("The milky goo teleports you somewhere it remembers!"))

/obj/item/slimecross/regenerative/bluespace/Initialize(mapload)
	. = ..()
	T = get_turf(src)

/obj/item/slimecross/regenerative/sepia
	colour = "sepia"
	effect_desc = "Fully heals the target and stops time."

/obj/item/slimecross/regenerative/sepia/core_effect_before(mob/living/target, mob/user)
	to_chat(target, "You try to forget how you feel.")
	target.AddComponent(/datum/component/dejavu)

/obj/item/slimecross/regenerative/cerulean
	colour = "cerulean"
	effect_desc = "Fully heals the target and makes a second regenerative core with no special effects."

/obj/item/slimecross/regenerative/cerulean/core_effect(mob/living/target, mob/user)
	src.forceMove(user.loc)
	var/obj/item/slimecross/X = new /obj/item/slimecross/regenerative(user.loc)
	X.name = name
	X.desc = desc
	user.put_in_active_hand(X)
	to_chat(user, span_notice("Some of the milky goo congeals in your hand!"))

/obj/item/slimecross/regenerative/pyrite
	colour = "pyrite"
	effect_desc = "Fully heals and randomly colors the target."

/obj/item/slimecross/regenerative/pyrite/core_effect(mob/living/target, mob/user)
	target.visible_message(span_warning("The milky goo coating [target] leaves [target.p_them()] a different color!"))
	target.add_atom_colour(rgb(rand(0,255),rand(0,255),rand(0,255)),WASHABLE_COLOUR_PRIORITY)

/obj/item/slimecross/regenerative/red
	colour = "red"
	effect_desc = "Fully heals the target and injects them with some ephedrine."

/obj/item/slimecross/regenerative/red/core_effect(mob/living/target, mob/user)
	to_chat(target, span_notice("You feel... faster."))
	target.reagents.add_reagent(/datum/reagent/medicine/ephedrine,3)

/obj/item/slimecross/regenerative/green
	colour = "green"
	effect_desc = "Fully heals the target and changes the spieces or color of a slime or jellyperson."

/obj/item/slimecross/regenerative/green/core_effect(mob/living/target, mob/user)
	if(isslime(target))
		target.visible_message(span_warning("The [target] suddenly changes color!"))
		var/mob/living/simple_animal/slime/S = target
		S.random_colour()
	if(isjellyperson(target))
		target.reagents.add_reagent(/datum/reagent/mutationtoxin/jelly,5)

/obj/item/slimecross/regenerative/pink
	colour = "pink"
	effect_desc = "Fully heals the target and injects them with some krokodil."

/obj/item/slimecross/regenerative/pink/core_effect(mob/living/target, mob/user)
	to_chat(target, span_notice("You feel more calm."))
	target.reagents.add_reagent(/datum/reagent/drug/krokodil,4)

/obj/item/slimecross/regenerative/gold
	colour = "gold"
	effect_desc = "Fully heals the target and produces a random coin."

/obj/item/slimecross/regenerative/gold/core_effect(mob/living/target, mob/user)
	var/newcoin = pick(/obj/item/coin/silver, /obj/item/coin/iron, /obj/item/coin/gold, /obj/item/coin/diamond, /obj/item/coin/plasma, /obj/item/coin/uranium)
	var/obj/item/coin/C = new newcoin(target.loc)
	playsound(C, 'sound/items/coinflip.ogg', 50, TRUE)
	target.put_in_hand(C)

/obj/item/slimecross/regenerative/oil
	colour = "oil"
	effect_desc = "Fully heals the target and flashes everyone in sight."

/obj/item/slimecross/regenerative/oil/core_effect(mob/living/target, mob/user)
	playsound(src, 'sound/weapons/flash.ogg', 100, TRUE)
	for(var/mob/living/L in view(user,7))
		L.flash_act()

/obj/item/slimecross/regenerative/black
	colour = "black"
	effect_desc = "Fully heals the target and creates an imperfect duplicate of them made of slime, that fakes their death."

/obj/item/slimecross/regenerative/black/core_effect_before(mob/living/target, mob/user)
	var/dummytype = target.type
	if(ismegafauna(target)) //Prevents megafauna duping in a lame way
		dummytype = /mob/living/simple_animal/slime
		to_chat(user, span_warning("The milky goo flows over [target], falling into a weak puddle."))
	var/mob/living/dummy = new dummytype(target.loc)
	to_chat(target, span_notice("The milky goo flows from your skin, forming an imperfect copy of you."))
	if(iscarbon(target))
		var/mob/living/carbon/T = target
		var/mob/living/carbon/D = dummy
		T.dna.transfer_identity(D)
		D.updateappearance(mutcolor_update=1)
		D.real_name = T.real_name
	dummy.adjustBruteLoss(target.getBruteLoss())
	dummy.adjustFireLoss(target.getFireLoss())
	dummy.adjustToxLoss(target.getToxLoss())
	dummy.death()

/obj/item/slimecross/regenerative/lightpink
	colour = "light pink"
	effect_desc = "Fully heals the target and also heals the user."

/obj/item/slimecross/regenerative/lightpink/core_effect(mob/living/target, mob/user)
	if(!isliving(user))
		return
	if(target == user)
		return
	var/mob/living/U = user
	U.revive(full_heal = TRUE, admin_revive = FALSE)
	to_chat(U, span_notice("Some of the milky goo sprays onto you, as well!"))

/obj/item/slimecross/regenerative/adamantine
	colour = "adamantine"
	effect_desc = "Fully heals the target and boosts their armor."

/obj/item/slimecross/regenerative/adamantine/core_effect(mob/living/target, mob/user) //WIP - Find out why this doesn't work.
	target.apply_status_effect(STATUS_EFFECT_SLIMESKIN)

/obj/item/slimecross/regenerative/rainbow
	colour = "rainbow"
	effect_desc = "Fully heals the target and temporarily makes them immortal, but pacifistic."

/obj/item/slimecross/regenerative/rainbow/core_effect(mob/living/target, mob/user)
	target.apply_status_effect(STATUS_EFFECT_RAINBOWPROTECTION)

repo_name: AnalWerewolf/sundown

license: mit


code:
/*
Reproductive extracts:
	When fed three monkey cubes, produces between
	1 and 4 normal slime extracts of the same colour.
*/

/obj/item/slimecross/reproductive
	name = "reproductive extract"
	desc = "It pulses with a strange hunger."
	icon_state = "reproductive"
	effect = "reproductive"
	effect_desc = "When fed monkey cubes it produces more extracts. Bio bag compatible as well."
	var/extract_type = /obj/item/slime_extract/
	var/cooldown = 3 SECONDS
	var/feedAmount = 3
	var/last_produce = 0
	var/datum/component/storage/concrete/extract_inventory/slimeStorage

/obj/item/slimecross/reproductive/examine()
	. = ..()
	. += span_danger("It appears to have eaten [length(contents)] Monkey Cube[p_s()]")

/obj/item/slimecross/reproductive/Initialize(mapload)
	. = ..()
	slimeStorage = AddComponent(/datum/component/storage/concrete/extract_inventory)

/obj/item/slimecross/reproductive/attackby(obj/item/O, mob/user)
	if((last_produce + cooldown) > world.time)
		to_chat(user, span_warning("[src] is still digesting!"))
		return

	if(length(contents) >= feedAmount) //if for some reason the contents are full, but it didnt digest, attempt to digest again
		to_chat(user, span_warning("[src] appears to be full but is not digesting! Maybe poking it stimulated it to digest."))
		slimeStorage.processCubes(src, user)
		return

	if(istype(O, /obj/item/storage/bag/bio))
		var/list/inserted = list()
		SEND_SIGNAL(O, COMSIG_TRY_STORAGE_TAKE_TYPE, /obj/item/food/monkeycube, src, feedAmount - length(contents), TRUE, FALSE, user, inserted)
		if(inserted.len)
			to_chat(user, span_notice("You feed [length(inserted)] Monkey Cube[p_s()] to [src], and it pulses gently."))
			playsound(src, 'sound/items/eatfood.ogg', 20, TRUE)
			slimeStorage.processCubes(src, user)
		else
			to_chat(user, span_warning("There are no monkey cubes in the bio bag!"))
		return

	else if(istype(O, /obj/item/food/monkeycube))
		slimeStorage.locked = FALSE //This weird unlock-then-lock nonsense brought to you courtesy of storage jank
		if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, O, user, TRUE))
			to_chat(user, span_notice("You feed 1 Monkey Cube to [src], and it pulses gently."))
			slimeStorage.processCubes(src, user)
			playsound(src, 'sound/items/eatfood.ogg', 20, TRUE)
			slimeStorage.locked = TRUE //relock once its done inserting
			return
		else
			slimeStorage.locked = TRUE //it couldnt insert for some reason, relock it
			to_chat(user, span_notice("The [src] rejects the Monkey Cube!")) //in case it fails to insert for whatever reason you get feedback

/obj/item/slimecross/reproductive/Destroy()
	slimeStorage = null
	return ..()

/obj/item/slimecross/reproductive/grey
	extract_type = /obj/item/slime_extract/grey
	colour = "grey"

/obj/item/slimecross/reproductive/orange
	extract_type = /obj/item/slime_extract/orange
	colour = "orange"

/obj/item/slimecross/reproductive/purple
	extract_type = /obj/item/slime_extract/purple
	colour = "purple"

/obj/item/slimecross/reproductive/blue
	extract_type = /obj/item/slime_extract/blue
	colour = "blue"

/obj/item/slimecross/reproductive/metal
	extract_type = /obj/item/slime_extract/metal
	colour = "metal"

/obj/item/slimecross/reproductive/yellow
	extract_type = /obj/item/slime_extract/yellow
	colour = "yellow"

/obj/item/slimecross/reproductive/darkpurple
	extract_type = /obj/item/slime_extract/darkpurple
	colour = "dark purple"

/obj/item/slimecross/reproductive/darkblue
	extract_type = /obj/item/slime_extract/darkblue
	colour = "dark blue"

/obj/item/slimecross/reproductive/silver
	extract_type = /obj/item/slime_extract/silver
	colour = "silver"

/obj/item/slimecross/reproductive/bluespace
	extract_type = /obj/item/slime_extract/bluespace
	colour = "bluespace"

/obj/item/slimecross/reproductive/sepia
	extract_type = /obj/item/slime_extract/sepia
	colour = "sepia"

/obj/item/slimecross/reproductive/cerulean
	extract_type = /obj/item/slime_extract/cerulean
	colour = "cerulean"

/obj/item/slimecross/reproductive/pyrite
	extract_type = /obj/item/slime_extract/pyrite
	colour = "pyrite"

/obj/item/slimecross/reproductive/red
	extract_type = /obj/item/slime_extract/red
	colour = "red"

/obj/item/slimecross/reproductive/green
	extract_type = /obj/item/slime_extract/green
	colour = "green"

/obj/item/slimecross/reproductive/pink
	extract_type = /obj/item/slime_extract/pink
	colour = "pink"

/obj/item/slimecross/reproductive/gold
	extract_type = /obj/item/slime_extract/gold
	colour = "gold"

/obj/item/slimecross/reproductive/oil
	extract_type = /obj/item/slime_extract/oil
	colour = "oil"

/obj/item/slimecross/reproductive/black
	extract_type = /obj/item/slime_extract/black
	colour = "black"

/obj/item/slimecross/reproductive/lightpink
	extract_type = /obj/item/slime_extract/lightpink
	colour = "light pink"

/obj/item/slimecross/reproductive/adamantine
	extract_type = /obj/item/slime_extract/adamantine
	colour = "adamantine"

/obj/item/slimecross/reproductive/rainbow
	extract_type = /obj/item/slime_extract/rainbow
	colour = "rainbow"


code:
/*
Self-sustaining extracts:
	Produces 4 extracts that do not need reagents.
*/
/obj/item/slimecross/selfsustaining
	name = "self-sustaining extract"
	effect = "self-sustaining"
	icon_state = "selfsustaining"
	var/extract_type = /obj/item/slime_extract

/obj/item/autoslime
	name = "autoslime"
	desc = "It resembles a normal slime extract, but seems filled with a strange, multi-colored fluid."
	var/obj/item/slime_extract/extract
	var/effect_desc = "A self-sustaining slime extract. When used, lets you choose which reaction you want."

//Just divides into the actual item.
/obj/item/slimecross/selfsustaining/Initialize(mapload)
	..()
	visible_message(span_warning("The [src] shudders, and splits into four smaller extracts."))
	for(var/i = 0, i < 4, i++)
		var/obj/item/autoslime/A = new /obj/item/autoslime(src.loc)
		var/obj/item/slime_extract/X = new extract_type(A)
		A.extract = X
		A.icon = icon
		A.icon_state = icon_state
		A.color = color
		A.name = "self-sustaining " + colour + " extract"
	return INITIALIZE_HINT_QDEL

/obj/item/autoslime/Initialize(mapload)
	return ..()

/obj/item/autoslime/attack_self(mob/user)
	var/reagentselect = input(user, "Choose the reagent the extract will produce.", "Self-sustaining Reaction") as null|anything in sort_list(extract.activate_reagents, /proc/cmp_typepaths_asc)
	var/amount = 5
	var/secondary

	if (user.get_active_held_item() != src || user.stat != CONSCIOUS || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))
		return
	if(!reagentselect)
		return
	if(reagentselect == "lesser plasma")
		amount = 4
		reagentselect = /datum/reagent/toxin/plasma
	if(reagentselect == "holy water and uranium")
		reagentselect = /datum/reagent/water/holywater
		secondary = /datum/reagent/uranium
	extract.forceMove(user.drop_location())
	qdel(src)
	user.put_in_active_hand(extract)
	extract.reagents.add_reagent(reagentselect,amount)
	if(secondary)
		extract.reagents.add_reagent(secondary,amount)

/obj/item/autoslime/examine(mob/user)
	. = ..()
	if(effect_desc)
		. += span_notice("[effect_desc]")

//Different types.

/obj/item/slimecross/selfsustaining/grey
	extract_type = /obj/item/slime_extract/grey
	colour = "grey"

/obj/item/slimecross/selfsustaining/orange
	extract_type = /obj/item/slime_extract/orange
	colour = "orange"

/obj/item/slimecross/selfsustaining/purple
	extract_type = /obj/item/slime_extract/purple
	colour = "purple"

/obj/item/slimecross/selfsustaining/blue
	extract_type = /obj/item/slime_extract/blue
	colour = "blue"

/obj/item/slimecross/selfsustaining/metal
	extract_type = /obj/item/slime_extract/metal
	colour = "metal"

/obj/item/slimecross/selfsustaining/yellow
	extract_type = /obj/item/slime_extract/yellow
	colour = "yellow"

/obj/item/slimecross/selfsustaining/darkpurple
	extract_type = /obj/item/slime_extract/darkpurple
	colour = "dark purple"

/obj/item/slimecross/selfsustaining/darkblue
	extract_type = /obj/item/slime_extract/darkblue
	colour = "dark blue"

/obj/item/slimecross/selfsustaining/silver
	extract_type = /obj/item/slime_extract/silver
	colour = "silver"

/obj/item/slimecross/selfsustaining/bluespace
	extract_type = /obj/item/slime_extract/bluespace
	colour = "bluespace"

/obj/item/slimecross/selfsustaining/sepia
	extract_type = /obj/item/slime_extract/sepia
	colour = "sepia"

/obj/item/slimecross/selfsustaining/cerulean
	extract_type = /obj/item/slime_extract/cerulean
	colour = "cerulean"

/obj/item/slimecross/selfsustaining/pyrite
	extract_type = /obj/item/slime_extract/pyrite
	colour = "pyrite"

/obj/item/slimecross/selfsustaining/red
	extract_type = /obj/item/slime_extract/red
	colour = "red"

/obj/item/slimecross/selfsustaining/green
	extract_type = /obj/item/slime_extract/green
	colour = "green"

/obj/item/slimecross/selfsustaining/pink
	extract_type = /obj/item/slime_extract/pink
	colour = "pink"

/obj/item/slimecross/selfsustaining/gold
	extract_type = /obj/item/slime_extract/gold
	colour = "gold"

/obj/item/slimecross/selfsustaining/oil
	extract_type = /obj/item/slime_extract/oil
	colour = "oil"

/obj/item/slimecross/selfsustaining/black
	extract_type = /obj/item/slime_extract/black
	colour = "black"

/obj/item/slimecross/selfsustaining/lightpink
	extract_type = /obj/item/slime_extract/lightpink
	colour = "light pink"

/obj/item/slimecross/selfsustaining/adamantine
	extract_type = /obj/item/slime_extract/adamantine
	colour = "adamantine"

/obj/item/slimecross/selfsustaining/rainbow
	extract_type = /obj/item/slime_extract/rainbow
	colour = "rainbow"


code:
/*
Stabilized extracts:
	Provides a passive buff to the holder.
*/

//To add: Create an effect in crossbreeding/_status_effects.dm with the name "/datum/status_effect/stabilized/[color]"
//Status effect will automatically be applied while held, and lost on drop.

/obj/item/slimecross/stabilized
	name = "stabilized extract"
	desc = "It seems inert, but anything it touches glows softly..."
	effect = "stabilized"
	icon_state = "stabilized"
	var/datum/status_effect/linked_effect
	var/mob/living/owner

/obj/item/slimecross/stabilized/Initialize(mapload)
	. = ..()
	START_PROCESSING(SSobj,src)

/obj/item/slimecross/stabilized/Destroy()
	STOP_PROCESSING(SSobj,src)
	qdel(linked_effect)
	return ..()

/obj/item/slimecross/stabilized/process()
	var/humanfound = null
	if(ishuman(loc))
		humanfound = loc
	if(ishuman(loc.loc)) //Check if in backpack.
		humanfound = (loc.loc)
	if(!humanfound)
		return
	var/mob/living/carbon/human/H = humanfound
	var/effectpath = /datum/status_effect/stabilized
	var/static/list/effects = subtypesof(/datum/status_effect/stabilized)
	for(var/X in effects)
		var/datum/status_effect/stabilized/S = X
		if(initial(S.colour) == colour)
			effectpath = S
			break
	if(!H.has_status_effect(effectpath))
		var/datum/status_effect/stabilized/S = H.apply_status_effect(effectpath)
		owner = H
		S.linked_extract = src
		STOP_PROCESSING(SSobj,src)

//Colors and subtypes:
/obj/item/slimecross/stabilized/grey
	colour = "grey"
	effect_desc = "Makes slimes friendly to the owner"

/obj/item/slimecross/stabilized/orange
	colour = "orange"
	effect_desc = "Passively tries to increase or decrease the owner's body temperature to normal"

/obj/item/slimecross/stabilized/purple
	colour = "purple"
	effect_desc = "Provides a regeneration effect"

/obj/item/slimecross/stabilized/blue
	colour = "blue"
	effect_desc = "Makes the owner immune to slipping on water, soap or foam. Space lube and ice are still too slippery."

/obj/item/slimecross/stabilized/metal
	colour = "metal"
	effect_desc = "Every 30 seconds, adds a sheet of material to a random stack in the owner's backpack."

/obj/item/slimecross/stabilized/yellow
	colour = "yellow"
	effect_desc = "Every ten seconds it recharges a device on the owner by 10%."

/obj/item/slimecross/stabilized/darkpurple
	colour = "dark purple"
	effect_desc = "Gives you burning fingertips, automatically cooking any microwavable food you hold."

/obj/item/slimecross/stabilized/darkblue
	colour = "dark blue"
	effect_desc = "Slowly extinguishes the owner if they are on fire, also wets items like monkey cubes, creating a monkey."

/obj/item/slimecross/stabilized/silver
	colour = "silver"
	effect_desc = "Slows the rate at which the owner loses nutrition"

/obj/item/slimecross/stabilized/bluespace
	colour = "bluespace"
	effect_desc = "On a two minute cooldown, when the owner has taken enough damage, they are teleported to a safe place."

/obj/item/slimecross/stabilized/sepia
	colour = "sepia"
	effect_desc = "Randomly adjusts the owner's speed."

/obj/item/slimecross/stabilized/cerulean
	colour = "cerulean"
	effect_desc = "Creates a duplicate of the owner. If the owner dies they will take control of the duplicate, unless the death was from beheading or gibbing."

/obj/item/slimecross/stabilized/pyrite
	colour = "pyrite"
	effect_desc = "Randomly colors the owner every few seconds."

/obj/item/slimecross/stabilized/red
	colour = "red"
	effect_desc = "Nullifies all equipment based slowdowns."

/obj/item/slimecross/stabilized/green
	colour = "green"
	effect_desc = "Changes the owner's name and appearance while holding this extract."

/obj/item/slimecross/stabilized/pink
	colour = "pink"
	effect_desc = "As long as no creatures are harmed in the owner's presense, they will not attack you. If the peace is broken it takes two minutes to restore."

/obj/item/slimecross/stabilized/gold
	colour = "gold"
	effect_desc = "Creates a pet when held."
	var/mob_type
	var/datum/mind/saved_mind
	var/mob_name = "Familiar"

/obj/item/slimecross/stabilized/gold/proc/generate_mobtype()
	var/static/list/mob_spawn_pets = list()
	if(mob_spawn_pets.len <= 0)
		for(var/T in typesof(/mob/living/simple_animal))
			var/mob/living/simple_animal/SA = T
			switch(initial(SA.gold_core_spawnable))
				if(FRIENDLY_SPAWN)
					mob_spawn_pets += T
	mob_type = pick(mob_spawn_pets)

/obj/item/slimecross/stabilized/gold/Initialize(mapload)
	. = ..()
	generate_mobtype()

/obj/item/slimecross/stabilized/gold/attack_self(mob/user)
	var/choice = input(user, "Which do you want to reset?", "Familiar Adjustment") as null|anything in sort_list(list("Familiar Location", "Familiar Species", "Familiar Sentience", "Familiar Name"))
	if(!user.canUseTopic(src, BE_CLOSE))
		return
	if(isliving(user))
		var/mob/living/L = user
		if(L.has_status_effect(/datum/status_effect/stabilized/gold))
			L.remove_status_effect(/datum/status_effect/stabilized/gold)
	if(choice == "Familiar Location")
		to_chat(user, span_notice("You prod [src], and it shudders slightly."))
		START_PROCESSING(SSobj, src)
	if(choice == "Familiar Species")
		to_chat(user, span_notice("You squeeze [src], and a shape seems to shift around inside."))
		generate_mobtype()
		START_PROCESSING(SSobj, src)
	if(choice == "Familiar Sentience")
		to_chat(user, span_notice("You poke [src], and it lets out a glowing pulse."))
		saved_mind = null
		START_PROCESSING(SSobj, src)
	if(choice == "Familiar Name")
		var/newname = sanitize_name(stripped_input(user, "Would you like to change the name of [mob_name]", "Name change", mob_name, MAX_NAME_LEN))
		if(newname)
			mob_name = newname
		to_chat(user, span_notice("You speak softly into [src], and it shakes slightly in response."))
		START_PROCESSING(SSobj, src)

/obj/item/slimecross/stabilized/oil
	colour = "oil"
	effect_desc = "The owner will violently explode when they die while holding this extract."

/obj/item/slimecross/stabilized/black
	colour = "black"
	effect_desc = "While strangling someone, the owner's hands melt around their neck, draining their life in exchange for food and healing."

/obj/item/slimecross/stabilized/lightpink
	colour = "light pink"
	effect_desc = "The owner moves at high speeds while holding this extract, also stabilizes anyone in critical condition around you using Epinephrine."

/obj/item/slimecross/stabilized/adamantine
	colour = "adamantine"
	effect_desc = "Owner gains a slight boost in damage resistance to all types."

/obj/item/slimecross/stabilized/rainbow
	colour = "rainbow"
	effect_desc = "Accepts a regenerative extract and automatically uses it if the owner enters a critical condition."
	var/obj/item/slimecross/regenerative/regencore

/obj/item/slimecross/stabilized/rainbow/attackby(obj/item/O, mob/user)
	var/obj/item/slimecross/regenerative/regen = O
	if(istype(regen) && !regencore)
		to_chat(user, span_notice("You place [O] in [src], prepping the extract for automatic application!"))
		regencore = regen
		regen.forceMove(src)
		return
	return ..()


code:
///Tool capable of taking biological samples from mobs
/obj/item/biopsy_tool
	name = "biopsy tool"
	desc = "Don't worry, it won't sting."
	icon = 'icons/obj/xenobiology/vatgrowing.dmi'
	icon_state = "biopsy"

///Adds the swabbing component to the biopsy tool
/obj/item/biopsy_tool/Initialize(mapload)
	. = ..()
	AddComponent(/datum/component/swabbing, FALSE, FALSE, TRUE, CALLBACK(src, .proc/update_swab_icon), max_items = 1)

/obj/item/biopsy_tool/proc/update_swab_icon(list/swabbed_items)
	if(LAZYLEN(swabbed_items))
		icon_state = "biopsy_full"
	else
		icon_state = "biopsy"


code:
/obj/structure/microscope
	name = "Microscope"
	desc = "A simple microscope, allowing you to examine micro-organisms."
	icon = 'icons/obj/xenobiology/vatgrowing.dmi'
	icon_state = "microscope"
	var/obj/item/petri_dish/current_dish

/obj/structure/microscope/attacked_by(obj/item/I, mob/living/user)
	if(!istype(I, /obj/item/petri_dish))
		return ..()
	if(current_dish)
		to_chat(user, span_warning("There is already a petridish in \the [src]."))
		return
	to_chat(user, span_notice("You put [I] into \the [src]."))
	current_dish = I
	current_dish.forceMove(src)

/obj/structure/microscope/ui_interact(mob/user, datum/tgui/ui)
	ui = SStgui.try_update_ui(user, src, ui)
	if(!ui)
		ui = new(user, src, "Microscope", name)
		ui.open()

/obj/structure/microscope/ui_data(mob/user)
	var/list/data = list()

	data["has_dish"] = current_dish ? TRUE : FALSE
	data["cell_lines"] = list()
	data["viruses"] = list()

	if(!current_dish)
		return data
	if(!current_dish.sample)
		return data

	for(var/organism in current_dish.sample.micro_organisms) //All the microorganisms in the dish
		if(istype(organism, /datum/micro_organism/cell_line))
			var/datum/micro_organism/cell_line/cell_line = organism
			var/list/organism_data = list(
				type = "cell line",
				name = cell_line.name,
				desc = cell_line.desc,
				growth_rate = cell_line.growth_rate,
				suspectibility = cell_line.virus_suspectibility,
				requireds = get_reagent_list(cell_line.required_reagents),
				supplementaries = get_reagent_list(cell_line.supplementary_reagents),
				suppressives = get_reagent_list(cell_line.suppressive_reagents)
			)
			data["cell_lines"] += list(organism_data)

		if(istype(organism, /datum/micro_organism/virus))
			var/datum/micro_organism/virus/virus = organism
			var/list/virus_data = list(
				type = "virus",
				name = virus.name,
				desc = virus.desc
			)
			data["viruses"] += list(virus_data)

	return data

/obj/structure/microscope/proc/get_reagent_list(list/reagents)
	var/list/reagent_list = list()
	for(var/i in reagents) //Convert from assoc to normal. Yeah very shit.
		var/datum/reagent/reagent = i
		reagent_list += initial(reagent.name)
	return reagent_list.Join(", ")

/obj/structure/microscope/ui_act(action, params)
	. = ..()
	if(.)
		return
	switch(action)
		if("eject_petridish")
			if(!current_dish)
				return FALSE
			current_dish.forceMove(get_turf(src))
			current_dish = null
			. = TRUE
	update_appearance()


code:
///Holds a biological sample which can then be put into the growing vat
/obj/item/petri_dish
	name = "petri dish"
	desc = "This makes you feel well-cultured."
	icon = 'icons/obj/xenobiology/vatgrowing.dmi'
	icon_state = "petri_dish"
	w_class = WEIGHT_CLASS_TINY
	///The sample stored on the dish
	var/datum/biological_sample/sample

/obj/item/petri_dish/Destroy()
	. = ..()
	QDEL_NULL(sample)

/obj/item/petri_dish/examine(mob/user)
	. = ..()
	if(!sample)
		return
	. += span_notice("You can see the following micro-organisms:")
	for(var/i in sample.micro_organisms)
		var/datum/micro_organism/MO = i
		. += MO.get_details()

/obj/item/petri_dish/pre_attack(atom/A, mob/living/user, params)
	. = ..()
	if(!sample || !istype(A, /obj/structure/sink))
		return FALSE
	to_chat(user, span_notice("You wash the sample out of [src]."))
	sample = null

/obj/item/petri_dish/update_overlays()
	. = ..()
	if(!sample)
		return
	var/reagentcolor = sample.sample_color
	var/mutable_appearance/base_overlay = mutable_appearance(icon, "petri_dish_overlay")
	base_overlay.appearance_flags = RESET_COLOR
	base_overlay.color = reagentcolor
	. += base_overlay
	var/mutable_appearance/overlay2 = mutable_appearance(icon, "petri_dish_overlay2")
	. += overlay2

/obj/item/petri_dish/proc/deposit_sample(user, datum/biological_sample/deposited_sample)
	sample = deposited_sample
	to_chat(user, span_notice("You deposit a sample into [src]."))
	update_appearance()

/// Petri dish with random sample already in it.
/obj/item/petri_dish/random
	var/static/list/possible_samples = list(
		list(CELL_LINE_TABLE_CORGI, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5),
		list(CELL_LINE_TABLE_SNAKE, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5),
		list(CELL_LINE_TABLE_COCKROACH, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 7),
		list(CELL_LINE_TABLE_BLOBBERNAUT, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
	)

/obj/item/petri_dish/random/Initialize(mapload)
	. = ..()
	var/list/chosen = pick(possible_samples)
	sample = new
	sample.GenerateSample(chosen[1],chosen[2],chosen[3],chosen[4])
	update_appearance()


code:
///A single type of growth.
/datum/micro_organism
	///Name, shown on microscope
	var/name = "Unknown fluids"
	///Desc, shown by science goggles
	var/desc = "White fluid that tastes like salty coins and milk"

///Returns a short description of the cell line
/datum/micro_organism/proc/get_details(show_details)
	return span_notice("[desc]")

///A "mob" cell. Can grow into a mob in a growing vat.
/datum/micro_organism/cell_line
	///Our growth so far, needs to get up to 100
	var/growth = 0
	///All the reagent types required for letting this organism grow into whatever it should become
	var/list/required_reagents
	///Reagent types that further speed up growth, but aren't needed.  Assoc list of reagent datum type || bonus growth per tick
	var/list/supplementary_reagents
	///Reagent types that surpress growth. Assoc list of reagent datum type || lost growth per tick
	var/list/suppressive_reagents
	///This var modifies how much this micro_organism is affected by viruses. Higher is more slowdown
	var/virus_suspectibility = 1
	///This var defines how much % the organism grows per process(), without modifiers, if you have all required reagents
	var/growth_rate = 4
	///Resulting atoms from growing this cell line. List is assoc atom type || amount
	var/list/resulting_atoms = list()

///Handles growth of the micro_organism. This only runs if the micro organism is in the growing vat. Reagents is the growing vats reagents
/datum/micro_organism/cell_line/proc/handle_growth(obj/machinery/plumbing/growing_vat/vat)
	if(!try_eat(vat.reagents))
		return FALSE
	growth = max(growth, growth + calculate_growth(vat.reagents, vat.biological_sample)) //Prevent you from having minus growth.
	if(growth >= 100)
		finish_growing(vat)
	return TRUE

///Tries to consume the required reagents. Can only do this if all of them are available. Reagents is the growing vats reagents
/datum/micro_organism/cell_line/proc/try_eat(datum/reagents/reagents)
	for(var/i in required_reagents)
		if(!reagents.has_reagent(i))
			return FALSE
	for(var/i in required_reagents) //Delete the required reagents if used
		reagents.remove_reagent(i, REAGENTS_METABOLISM)
	return TRUE

///Apply modifiers on growth_rate based on supplementary and supressive reagents. Reagents is the growing vats reagents
/datum/micro_organism/cell_line/proc/calculate_growth(datum/reagents/reagents, datum/biological_sample/biological_sample)
	. = growth_rate

	//Handle growth based on supplementary reagents here.
	for(var/i in supplementary_reagents)
		if(!reagents.has_reagent(i, REAGENTS_METABOLISM))
			continue
		. += supplementary_reagents[i]
		reagents.remove_reagent(i, REAGENTS_METABOLISM)

	//Handle degrowth based on supressive reagents here.
	for(var/i in suppressive_reagents)
		if(!reagents.has_reagent(i, REAGENTS_METABOLISM))
			continue
		. += suppressive_reagents[i]
		reagents.remove_reagent(i, REAGENTS_METABOLISM)

	//Handle debuffing growth based on viruses here.
	for(var/datum/micro_organism/virus/active_virus in biological_sample.micro_organisms)
		if(reagents.has_reagent(/datum/reagent/medicine/spaceacillin, REAGENTS_METABOLISM))
			reagents.remove_reagent(/datum/reagent/medicine/spaceacillin, REAGENTS_METABOLISM)
			continue //This virus is stopped, We have antiviral stuff
		. -= virus_suspectibility

///Called once a cell line reaches 100 growth. Then we check if any cell_line is too far so we can perform an epic fail roll
/datum/micro_organism/cell_line/proc/finish_growing(obj/machinery/plumbing/growing_vat/vat)
	var/risk = 0 //Penalty for failure, goes up based on how much growth the other cell_lines have

	for(var/datum/micro_organism/cell_line/cell_line in vat.biological_sample.micro_organisms)
		if(cell_line == src) //well duh
			continue
		if(cell_line.growth >= VATGROWING_DANGER_MINIMUM)
			risk += cell_line.growth * 0.6 //60% per cell_line potentially. Kryson should probably tweak this
	playsound(vat, 'sound/effects/splat.ogg', 50, TRUE)
	if(rand(1, 100) < risk) //Fail roll!
		fuck_up_growing(vat)

		return FALSE
	succeed_growing(vat)
	return TRUE

/datum/micro_organism/cell_line/proc/fuck_up_growing(obj/machinery/plumbing/growing_vat/vat)
	vat.visible_message(span_warning("The biological sample in [vat] seems to have dissipated!"))
	if(prob(50))
		new /obj/effect/gibspawner/generic(get_turf(vat)) //Spawn some gibs.
	if(SEND_SIGNAL(vat.biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED) & SPARE_SAMPLE)
		return
	QDEL_NULL(vat.biological_sample)

/datum/micro_organism/cell_line/proc/succeed_growing(obj/machinery/plumbing/growing_vat/vat)
	var/datum/effect_system/smoke_spread/smoke = new
	smoke.set_up(0, vat.loc)
	smoke.start()
	for(var/created_thing in resulting_atoms)
		for(var/x in 1 to resulting_atoms[created_thing])
			var/atom/thing = new created_thing(get_turf(vat))
			ADD_TRAIT(thing, TRAIT_VATGROWN, "vatgrowing")
			vat.visible_message(span_nicegreen("[thing] pops out of [vat]!"))
	if(SEND_SIGNAL(vat.biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED) & SPARE_SAMPLE)
		return
	QDEL_NULL(vat.biological_sample)

///Overriden to show more info like needs, supplementary and supressive reagents and also growth.
/datum/micro_organism/cell_line/get_details(show_details)
	. += "[span_notice("[desc] - growth progress: [growth]%")]\n"
	if(show_details)
		. += return_reagent_text("It requires:", required_reagents)
		. += return_reagent_text("It likes:", supplementary_reagents)
		. += return_reagent_text("It hates:", suppressive_reagents)

///Return a nice list of all the reagents in a specific category with a specific prefix. This needs to be reworked because the formatting sucks ass.
/datum/micro_organism/cell_line/proc/return_reagent_text(prefix_text = "It requires:", list/reagentlist)
	if(!reagentlist.len)
		return
	var/all_reagents_text
	for(var/i in reagentlist)
		var/datum/reagent/reagent = i
		all_reagents_text += " - [initial(reagent.name)]\n"
	return span_notice("[prefix_text]\n[all_reagents_text]")


code:
///This datum is a simple holder for the micro_organisms in a sample.
/datum/biological_sample
	///List of all micro_organisms in the sample. These are instantiated
	var/list/micro_organisms = list()
	///Prevents someone from stacking too many layers onto a swabber
	var/sample_layers = 1
	///Picked from a specific group of colors, limited to a specific group.
	var/sample_color = COLOR_SAMPLE_YELLOW

///Generate a sample from a specific weighted list, and a specific amount of cell line with a chance for a virus
/datum/biological_sample/proc/GenerateSample(cell_line_define, virus_define, cell_line_amount, virus_chance)
	sample_color = pick(GLOB.xeno_sample_colors)

	var/list/temp_weight_list = GLOB.cell_line_tables[cell_line_define].Copy() //Temp list to prevent double picking
	for(var/i in 1 to cell_line_amount)
		var/datum/micro_organism/chosen_type = pick_weight(temp_weight_list)
		temp_weight_list -= chosen_type
		micro_organisms += new chosen_type
	if(prob(virus_chance))
		if(!GLOB.cell_virus_tables[virus_define])
			return
		var/datum/micro_organism/chosen_type = pick_weight(GLOB.cell_virus_tables[virus_define])
		micro_organisms += new chosen_type

///Takes another sample and merges it into use. This can cause one very big sample but we limit it to 3 layers.
/datum/biological_sample/proc/Merge(datum/biological_sample/other_sample)
	if(sample_layers >= 3)//No more than 3 layers, at that point you're entering danger zone.
		return FALSE
	micro_organisms += other_sample.micro_organisms
	qdel(other_sample)
	return TRUE

///Call handle_growth on all our microorganisms.
/datum/biological_sample/proc/handle_growth(obj/machinery/plumbing/growing_vat/vat)
	for(var/datum/micro_organism/cell_line/organism in micro_organisms) //Types because we don't grow viruses.
		organism.handle_growth(vat)

///resets the progress of all cell ines
/datum/biological_sample/proc/reset_sample()
	for(var/datum/micro_organism/cell_line/organism in micro_organisms) //Types because we don't grow viruses.
		organism.growth = 0


code:
#define VAT_GROWTH_RATE 4

////////////////////////////////
//// VERTEBRATES ////
////////////////////////////////

/datum/micro_organism/cell_line/mouse //nuisance cell line designed to complicate the growing of animal type cell lines.
	desc = "Murine cells"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)
	supplementary_reagents = list(
		/datum/reagent/growthserum = 2,
		/datum/reagent/liquidgibs = 2,
		/datum/reagent/consumable/cornoil = 2,
		/datum/reagent/consumable/nutriment = 1,
		/datum/reagent/consumable/nutriment/vitamin = 1,
		/datum/reagent/consumable/sugar = 1,
		/datum/reagent/consumable/cooking_oil = 1,
		/datum/reagent/consumable/rice = 1,
		/datum/reagent/consumable/eggyolk = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/heparin = -6,
		/datum/reagent/consumable/astrotame = -4, //Saccarin gives rats cancer.
		/datum/reagent/consumable/ethanol/rubberneck = -3,
		/datum/reagent/consumable/grey_bull = -1)

	virus_suspectibility = 2
	growth_rate = VAT_GROWTH_RATE
	resulting_atoms = list(/mob/living/simple_animal/mouse = 2)

/datum/micro_organism/cell_line/chicken //basic cell line designed as a good source of protein and eggyolk.
	desc = "Galliform skin cells."
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)

	supplementary_reagents = list(
		/datum/reagent/consumable/rice = 4,
		/datum/reagent/growthserum = 3,
		/datum/reagent/consumable/eggyolk = 1,
		/datum/reagent/consumable/nutriment/vitamin = 2)

	suppressive_reagents = list(
		/datum/reagent/fuel/oil = -4,
		/datum/reagent/toxin = -2)

	virus_suspectibility = 1
	growth_rate = VAT_GROWTH_RATE
	resulting_atoms = list(/mob/living/simple_animal/chicken = 1)

/datum/micro_organism/cell_line/cow
	desc = "Bovine stem cells"
	required_reagents = list(
	/datum/reagent/consumable/nutriment/protein,
	/datum/reagent/consumable/nutriment,
	/datum/reagent/cellulose)

	supplementary_reagents = list(
	/datum/reagent/growthserum = 4,
	/datum/reagent/consumable/nutriment/vitamin = 2,
	/datum/reagent/consumable/rice = 2,
	/datum/reagent/consumable/flour = 1)

	suppressive_reagents = list(/datum/reagent/toxin = -2,
	/datum/reagent/toxin/carpotoxin = -5)

	virus_suspectibility = 1
	resulting_atoms = list(/mob/living/basic/cow = 1)

/datum/micro_organism/cell_line/moonicorn
	desc = "Fairyland Bovine stem cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/nutriment,
		/datum/reagent/drug/mushroomhallucinogen,
	)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 4,
		/datum/reagent/consumable/tinlux = 2,
		/datum/reagent/consumable/vitfro = 2,
		/datum/reagent/consumable/astrotame = 1,
	)

	suppressive_reagents = list(
		/datum/reagent/toxin = -2,
		/datum/reagent/toxin/carpotoxin = -5,
		/datum/reagent/consumable/coffee = -3,
		/datum/reagent/consumable/triple_citrus = -5,
	)

	virus_suspectibility = 1
	resulting_atoms = list(/mob/living/basic/cow/moonicorn = 1)

/datum/micro_organism/cell_line/cat
	desc = "Feliform cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/liquidgibs)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 3,
		/datum/reagent/consumable/nutriment/vitamin = 2,
		/datum/reagent/medicine/oculine = 2,
		/datum/reagent/consumable/milk = 1) //milkies

	suppressive_reagents = list(
		/datum/reagent/consumable/coco = -4,
		/datum/reagent/consumable/hot_coco = -2,
		/datum/reagent/consumable/chocolatepudding = -2,
		/datum/reagent/consumable/milk/chocolate_milk = -1)

	virus_suspectibility = 1.5
	resulting_atoms = list(/mob/living/simple_animal/pet/cat = 1) //The basic cat mobs are all male, so you mightt need a gender swap potion if you want to fill the fortress with kittens.

/datum/micro_organism/cell_line/corgi
	desc = "Canid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/liquidgibs)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 3,
		/datum/reagent/barbers_aid = 3,
		/datum/reagent/consumable/nutriment/vitamin = 2)

	suppressive_reagents = list(
		/datum/reagent/consumable/garlic = -2,
		/datum/reagent/consumable/tearjuice = -3,
		/datum/reagent/consumable/coco = -2)

	virus_suspectibility = 1
	resulting_atoms = list(/mob/living/simple_animal/pet/dog/corgi = 1)

/datum/micro_organism/cell_line/pug
	desc = "Squat canid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/liquidgibs)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 2,
		/datum/reagent/consumable/nutriment/vitamin = 3)

	suppressive_reagents = list(
		/datum/reagent/consumable/garlic = -2,
		/datum/reagent/consumable/tearjuice = -3,
		/datum/reagent/consumable/coco = -2)

	virus_suspectibility = 3
	resulting_atoms = list(/mob/living/simple_animal/pet/dog/pug = 1)

/datum/micro_organism/cell_line/bear //bears can't really compete directly with more powerful creatures, so i made it possible to grow them real fast.
	desc = "Ursine cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/liquidgibs,
		/datum/reagent/medicine/c2/synthflesh) //Nuke this if the dispenser becomes xenobio meta.

	supplementary_reagents = list(
		/datum/reagent/consumable/honey = 8, //Hunny.
		/datum/reagent/growthserum = 5,
		/datum/reagent/medicine/morphine = 4, //morphine is a vital nutrient for space bears, but it is better as a supplemental for gameplay reasons.
		/datum/reagent/consumable/nutriment/vitamin = 3)

	suppressive_reagents = list(
		/datum/reagent/consumable/condensedcapsaicin = -4, //bear mace, steal it from the sec checkpoint.
		/datum/reagent/toxin/carpotoxin = -2,
		/datum/reagent/medicine/insulin = -2) //depletes hunny.

	virus_suspectibility = 2
	resulting_atoms = list(/mob/living/simple_animal/hostile/bear = 1)

/datum/micro_organism/cell_line/carp
	desc = "Cyprinid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/nutriment)

	supplementary_reagents = list(
		/datum/reagent/consumable/cornoil = 4, //Carp are oily fish
		/datum/reagent/toxin/carpotoxin = 3,
		/datum/reagent/consumable/cooking_oil = 2,
		/datum/reagent/consumable/nutriment/vitamin = 2)

	suppressive_reagents = list(
		/datum/reagent/toxin/bungotoxin = -6,
		/datum/reagent/mercury = -4,
		/datum/reagent/oxygen = -3)

	virus_suspectibility = 2
	resulting_atoms = list(/mob/living/simple_animal/hostile/carp = 1)

/datum/micro_organism/cell_line/megacarp
	desc = "Cartilaginous cyprinid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/medicine/c2/synthflesh,
		/datum/reagent/consumable/nutriment)

	supplementary_reagents = list(
		/datum/reagent/consumable/cornoil = 4,
		/datum/reagent/growthserum = 3,
		/datum/reagent/toxin/carpotoxin = 2,
		/datum/reagent/consumable/cooking_oil = 2,
		/datum/reagent/consumable/nutriment/vitamin = 2)

	suppressive_reagents = list(
		/datum/reagent/toxin/bungotoxin = -6,
		/datum/reagent/oxygen = -3)

	virus_suspectibility = 1
	resulting_atoms = list(/mob/living/simple_animal/hostile/carp/megacarp = 1)

/datum/micro_organism/cell_line/snake
	desc = "Ophidic cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/liquidgibs)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 3,
		/datum/reagent/consumable/nutriment/peptides = 3,
		/datum/reagent/consumable/eggyolk = 2,
		/datum/reagent/consumable/nutriment/vitamin = 2)

	suppressive_reagents = list(
		/datum/reagent/consumable/corn_syrup = -6,
		/datum/reagent/sulfur = -3) //sulfur repels snakes according to professor google.

	resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/snake = 1)

///////////////////////////////////////////
/// SLIMES, OOZES & BLOBS ///
//////////////////////////////////////////

/datum/micro_organism/cell_line/slime
	desc = "Slime particles"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)

	supplementary_reagents = list(
		/datum/reagent/toxin/slimejelly = 2,
		/datum/reagent/liquidgibs = 2,
		/datum/reagent/consumable/enzyme = 1)

	suppressive_reagents = list(
		/datum/reagent/consumable/frostoil = -4,
		/datum/reagent/cryostylane = -4,
		/datum/reagent/medicine/morphine = -2,
		/datum/reagent/consumable/ice = -2) //Brrr!

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/slime = 1)

/datum/micro_organism/cell_line/blob_spore //shitty cell line to dilute the pool, feel free to make easier to grow if it doesn't interfer with growing the powerful mobs enough.
	desc = "Immature blob spores"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)

	supplementary_reagents = list(
		/datum/reagent/consumable/nutriment/vitamin = 3,
		/datum/reagent/liquidgibs = 2,
		/datum/reagent/sulfur = 2)

	suppressive_reagents = list(
		/datum/reagent/consumable/tinlux = -6,
		/datum/reagent/napalm = -4)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/blob/blobspore/independent = 2) //These are useless so we might as well spawn 2.

/datum/micro_organism/cell_line/blobbernaut
	desc = "Blobular myocytes"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/medicine/c2/synthflesh,
		/datum/reagent/sulfur) //grind flares to get this

	supplementary_reagents = list(
		/datum/reagent/growthserum = 3,
		/datum/reagent/consumable/nutriment/vitamin = 2,
		/datum/reagent/liquidgibs = 2,
		/datum/reagent/consumable/eggyolk = 2,
		/datum/reagent/consumable/shamblers = 1)

	suppressive_reagents = list(/datum/reagent/consumable/tinlux = -6)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/blob/blobbernaut/independent = 1)

/datum/micro_organism/cell_line/gelatinous_cube
	desc = "Cubic ooze particles"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/toxin/slimejelly,
		/datum/reagent/yuck,
		/datum/reagent/consumable/enzyme) //Powerful enzymes helps the cube digest prey.

	supplementary_reagents = list(
		/datum/reagent/water/hollowwater = 4,
		/datum/reagent/consumable/corn_syrup = 3,
		/datum/reagent/gold = 2, //This is why they eat so many adventurers.
		/datum/reagent/consumable/nutriment/peptides = 2,
		/datum/reagent/consumable/potato_juice = 1,
		/datum/reagent/liquidgibs = 1,
		/datum/reagent/consumable/nutriment/vitamin = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/minttoxin = -3,
		/datum/reagent/consumable/frostoil = -2,
		/datum/reagent/consumable/ice = -1)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/ooze/gelatinous = 1)

/datum/micro_organism/cell_line/sholean_grapes
	desc = "Globular ooze particles"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/toxin/slimejelly,
		/datum/reagent/yuck,
		/datum/reagent/consumable/vitfro)

	supplementary_reagents = list(
		/datum/reagent/medicine/omnizine = 4,
		/datum/reagent/consumable/nutriment/peptides = 3,
		/datum/reagent/consumable/corn_syrup = 2,
		/datum/reagent/consumable/ethanol/squirt_cider = 2,
		/datum/reagent/consumable/doctor_delight = 1,
		/datum/reagent/medicine/salglu_solution = 1,
		/datum/reagent/liquidgibs = 1,
		/datum/reagent/consumable/nutriment/vitamin = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/carpotoxin = -3,
		/datum/reagent/toxin/coffeepowder = -2,
		/datum/reagent/consumable/frostoil = -2,
		/datum/reagent/consumable/ice = -1)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/ooze/grapes = 1)

////////////////////
//// MISC ////
////////////////////
/datum/micro_organism/cell_line/cockroach //nuisance cell line designed to complicate the growing of slime type cell lines.
	desc = "Blattodeoid anthropod cells"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)
	supplementary_reagents = list(
		/datum/reagent/yuck = 4,
		/datum/reagent/growthserum = 2,
		/datum/reagent/toxin/slimejelly = 2,
		/datum/reagent/consumable/nutriment/vitamin = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/pestkiller = -2,
		/datum/reagent/consumable/poisonberryjuice = -4,
		/datum/reagent/consumable/ethanol/bug_spray = -4)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/basic/cockroach = 5)

/datum/micro_organism/cell_line/pine
	desc = "Coniferous plant cells"
	required_reagents = list(
		/datum/reagent/ammonia,
		/datum/reagent/ash,
		/datum/reagent/plantnutriment/robustharvestnutriment) //A proper source of phosphorous like would be thematically more appropriate but this is what we have.

	supplementary_reagents = list(
		/datum/reagent/saltpetre = 5,
		/datum/reagent/carbondioxide = 2,
		/datum/reagent/consumable/nutriment = 2,
		/datum/reagent/consumable/space_cola = 2, //A little extra phosphorous
		/datum/reagent/water/holywater = 2,
		/datum/reagent/water = 1,
		/datum/reagent/cellulose = 1)

	suppressive_reagents = list(/datum/reagent/toxin/plantbgone = -8)

	virus_suspectibility = 1
	resulting_atoms = list(/mob/living/simple_animal/hostile/tree = 1)

/datum/micro_organism/cell_line/vat_beast
	desc = "Hypergenic xenocytes"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/nutriment/vitamin,
		/datum/reagent/consumable/nutriment/peptides,
		/datum/reagent/consumable/liquidelectricity/enriched,
		/datum/reagent/growthserum,
		/datum/reagent/yuck)

	supplementary_reagents = list(
		/datum/reagent/medicine/rezadone = 3,
		/datum/reagent/consumable/entpoly = 3,
		/datum/reagent/consumable/red_queen = 2,
		/datum/reagent/consumable/peachjuice = 2,
		/datum/reagent/uranium = 1,
		/datum/reagent/liquidgibs = 1)

	suppressive_reagents = list(
		/datum/reagent/consumable/salt = -3,
		/datum/reagent/medicine/c2/syriniver = -2)

	virus_suspectibility = 0.5
	resulting_atoms = list(/mob/living/simple_animal/hostile/vatbeast = 1)

/datum/micro_organism/cell_line/vat_beast/succeed_growing(obj/machinery/plumbing/growing_vat/vat)
	. = ..()
	qdel(vat)

//randomizes from the netherworld pool!
/datum/micro_organism/cell_line/netherworld
	desc = "Aberrant residue"
	required_reagents = list(//theme here: very odd requirements
		/datum/reagent/water/hollowwater,//geyser reagent, so plentiful when found
		/datum/reagent/consumable/ethanol/wizz_fizz, //EZ bartender drink, like brainless
		/datum/reagent/yuck) //since the other two are easy to make tons of, this is kind of a limiter

	supplementary_reagents = list( //all of these are just geyser stuff, rated by their rarity
		/datum/reagent/wittel = 10, //stupid rare
		/datum/reagent/medicine/omnizine/protozine = 5,
		/datum/reagent/plasma_oxide = 3,
		/datum/reagent/clf3 = 1)//since this is also chemistry it's worth near nothing

	suppressive_reagents = list(//generics you would regularly put in a vat kill abberant residue
		/datum/reagent/consumable/nutriment/peptides = -6,
		/datum/reagent/consumable/nutriment/protein = -4,
		/datum/reagent/consumable/nutriment = -3,
		/datum/reagent/liquidgibs = -2)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/netherworld = 1)

/datum/micro_organism/cell_line/netherworld/succeed_growing(obj/machinery/plumbing/growing_vat/vat)
	var/random_result = pick(typesof(/mob/living/simple_animal/hostile/netherworld)) //i looked myself, pretty much all of them are reasonably strong and somewhat on the same level. except migo is the jackpot and the blank body is whiff.
	resulting_atoms = list()
	resulting_atoms[random_result] = 1
	return ..()

/datum/micro_organism/cell_line/clown/fuck_up_growing(obj/machinery/plumbing/growing_vat/vat)
	vat.visible_message(span_warning("The biological sample in [vat] seems to have created something horrific!"))

	var/mob/selected_mob = pick(list(/mob/living/simple_animal/hostile/retaliate/clown/mutant/slow, /mob/living/simple_animal/hostile/retaliate/clown/fleshclown))

	new selected_mob(get_turf(vat))
	if(SEND_SIGNAL(vat.biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED) & SPARE_SAMPLE)
		return
	QDEL_NULL(vat.biological_sample)

/datum/micro_organism/cell_line/clown/bananaclown
	desc = "Clown bits with banana chunks"

	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/banana)

	supplementary_reagents = list(
		/datum/reagent/saltpetre = 4,
		/datum/reagent/ammonia = 3,
		/datum/reagent/carbondioxide = 3,
		/datum/reagent/medicine/coagulant/banana_peel = 2,
		/datum/reagent/plantnutriment/robustharvestnutriment = 1)

	suppressive_reagents = list(
		/datum/reagent/consumable/clownstears = -8,
		/datum/reagent/toxin/plantbgone = -4,
		/datum/reagent/consumable/ethanol/silencer = -3,
		/datum/reagent/consumable/nothing = -2,
		/datum/reagent/fuel/oil = -1)

	resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/banana = 1)

/datum/micro_organism/cell_line/clown/glutton
	desc = "hyperadipogenic clown stem cells"

	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/banana,
		/datum/reagent/medicine/c2/synthflesh)
	//r/chonkers
	supplementary_reagents = list(
		/datum/reagent/consumable/vanillapudding = 8,
		/datum/reagent/growthserum = 6,
		/datum/reagent/consumable/nutriment/peptides = 4,
		/datum/reagent/consumable/cornoil = 3,
		/datum/reagent/consumable/cooking_oil = 1,
		/datum/reagent/consumable/space_cola = 1)

	suppressive_reagents = list(
		/datum/reagent/consumable/clownstears = -8,
		/datum/reagent/toxin/minttoxin = -6,
		/datum/reagent/consumable/ethanol/silencer = -3,
		/datum/reagent/consumable/ethanol/fernet = -3,
		/datum/reagent/toxin/lipolicide = -3,
		/datum/reagent/consumable/nothing = -2,
		/datum/reagent/toxin/bad_food = -1)

	resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/mutant/glutton = 1)

/datum/micro_organism/cell_line/clown/longclown
	desc = "long clown bits"

	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/banana)

	supplementary_reagents = list(
		/datum/reagent/drug/happiness = 5,
		/datum/reagent/toxin/mimesbane = 4,
		/datum/reagent/consumable/laughter = 3,
		/datum/reagent/nitrous_oxide = 2)

	suppressive_reagents = list(
		/datum/reagent/consumable/clownstears = -8,
		/datum/reagent/consumable/ethanol/beepsky_smash = -3,
		/datum/reagent/consumable/ethanol/silencer = -3,
		/datum/reagent/toxin/mutetoxin = -3,
		/datum/reagent/consumable/nothing = -2,
		/datum/reagent/sulfur = -1)

	resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/clown/longface = 1)

/datum/micro_organism/cell_line/frog
	desc = "amphibian cells"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)

	supplementary_reagents = list(
		/datum/reagent/ants = 3,
		/datum/reagent/consumable/eggwhite= 2,
		/datum/reagent/consumable/nutriment/vitamin = 1,)

	suppressive_reagents = list(
		/datum/reagent/toxin/carpotoxin = -3,
		/datum/reagent/toxin/bungotoxin = -3,
		/datum/reagent/toxin/spore = -3,
		/datum/reagent/toxin/plantbgone = -2, //GAY FROGS
		/datum/reagent/drying_agent = -2,
		/datum/reagent/consumable/mold = -2,
		/datum/reagent/toxin = -1)

	virus_suspectibility = 0.5
	resulting_atoms = list(/mob/living/simple_animal/hostile/retaliate/frog = 1)

/datum/micro_organism/cell_line/walking_mushroom
	desc = "motile fungal hyphae"
	required_reagents = list(/datum/reagent/consumable/nutriment/protein)

	supplementary_reagents = list(
		/datum/reagent/toxin/polonium = 6,
		/datum/reagent/consumable/corn_syrup = 3,
		/datum/reagent/consumable/mushroom_tea = 3,
		/datum/reagent/toxin/coffeepowder = 2,
		/datum/reagent/consumable/nuka_cola = 2,
		/datum/reagent/consumable/mold = 2,
		/datum/reagent/consumable/sugar = 1,
		/datum/reagent/cellulose = 1)

	suppressive_reagents = list(
		/datum/reagent/lead = -4,
		/datum/reagent/consumable/garlic = -3,
		/datum/reagent/toxin/plasma = -2,
		/datum/reagent/flash_powder = -2,
		/datum/reagent/pax = -2,
		/datum/reagent/copper = -1)

	virus_suspectibility = 0
	resulting_atoms = list(/mob/living/simple_animal/hostile/mushroom = 1)

/datum/micro_organism/cell_line/queen_bee
	desc = "aphid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/consumable/corn_syrup)

	supplementary_reagents = list(
		/datum/reagent/consumable/honey = 4,
		/datum/reagent/consumable/korta_nectar = 3,
		/datum/reagent/consumable/red_queen =  3,
		/datum/reagent/consumable/ethanol/champagne = 2,
		/datum/reagent/consumable/ethanol/sugar_rush = 2,
		/datum/reagent/consumable/sugar = 1,
		/datum/reagent/consumable/lemonade = 1,
		/datum/reagent/consumable/nutriment/vitamin = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/carpotoxin = -3,
		/datum/reagent/toxin/pestkiller = -2,
		/datum/reagent/consumable/potato_juice = -2,
		/datum/reagent/drug/nicotine = -1)

	virus_suspectibility = 0
	resulting_atoms = list(/obj/item/queen_bee = 1)

/datum/micro_organism/cell_line/queen_bee/fuck_up_growing(obj/machinery/plumbing/growing_vat/vat) //we love job hazards
	vat.visible_message(span_warning("You hear angry buzzing coming from the inside of the vat!"))
	for(var/i in 1 to 5)
		new /mob/living/simple_animal/hostile/bee(get_turf(vat))
	if(SEND_SIGNAL(vat.biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED) & SPARE_SAMPLE)
		return
	QDEL_NULL(vat.biological_sample)

/datum/micro_organism/cell_line/leaper
	desc = "atypical amphibian cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/ants,
		/datum/reagent/consumable/eggyolk,
		/datum/reagent/medicine/c2/synthflesh)

	supplementary_reagents = list(
		/datum/reagent/growthserum = 4,
		/datum/reagent/drug/blastoff = 3,
		/datum/reagent/drug/space_drugs = 2,
		/datum/reagent/consumable/ethanol/eggnog = 2,
		/datum/reagent/consumable/vanilla = 2,
		/datum/reagent/consumable/banana = 1,
		/datum/reagent/consumable/nutriment/vitamin = 1)

	suppressive_reagents = list(
		/datum/reagent/toxin/cyanide = -5,
		/datum/reagent/consumable/mold = -2,
		/datum/reagent/toxin/spore = -1)

	resulting_atoms = list(/mob/living/simple_animal/hostile/jungle/leaper = 1)

/datum/micro_organism/cell_line/mega_arachnid
	desc = "pseudoarachnoid cells"
	required_reagents = list(
		/datum/reagent/consumable/nutriment/protein,
		/datum/reagent/ants,
		/datum/reagent/medicine/omnizine)

	supplementary_reagents  = list(
		/datum/reagent/toxin/venom = 6,
		/datum/reagent/drug/kronkaine = 4,
		/datum/reagent/consumable/nutriment/peptides = 3,
		/datum/reagent/consumable/ethanol/squirt_cider = 2,
		/datum/reagent/consumable/nutraslop = 2,
		/datum/reagent/consumable/nutriment/vitamin = 1,
		/datum/reagent/toxin/plasma = 1,
		/datum/reagent/consumable/nutriment/organ_tissue = 1,
		/datum/reagent/liquidgibs = 1,
		/datum/reagent/consumable/enzyme = 1)

	suppressive_reagents = list(
		/datum/reagent/consumable/ethanol/bug_spray = -3,
		/datum/reagent/drug/nicotine = -1,
		/datum/reagent/toxin/pestkiller = -1)

	resulting_atoms = list(/mob/living/simple_animal/hostile/jungle/mega_arachnid = 1)

#undef VAT_GROWTH_RATE


code:
///A micro_organism that supports the ability to be converted to a real virus, allowing virology to get new symptoms
/datum/micro_organism/virus
	desc = "A virus of unknown origin"


code:
///Tool capable of taking biological samples from mobs
/obj/item/swab
	name = "swab"
	desc = "Some men use these for different reasons."
	icon = 'icons/obj/xenobiology/vatgrowing.dmi'
	icon_state = "swab"
	w_class = WEIGHT_CLASS_TINY

///Adds the swabbing component to the biopsy tool
/obj/item/swab/Initialize(mapload)
	. = ..()
	AddComponent(/datum/component/swabbing, TRUE, TRUE, FALSE, null, CALLBACK(src, .proc/update_swab_icon), max_items = 1)

/obj/item/swab/proc/update_swab_icon(overlays, list/swabbed_items)
	if(LAZYLEN(swabbed_items))
		var/datum/biological_sample/sample = LAZYACCESS(swabbed_items, 1) //Use the first one as our target
		var/mutable_appearance/swab_overlay = mutable_appearance(icon, "swab_[sample.sample_color]")
		swab_overlay.appearance_flags = RESET_COLOR
		overlays += swab_overlay


code:
///Used to make mobs from microbiological samples. Grow grow grow.
/obj/machinery/plumbing/growing_vat
	name = "growing vat"
	desc = "Tastes just like the chef's soup."
	icon_state = "growing_vat"
	buffer = 300
	///List of all microbiological samples in this soup.
	var/datum/biological_sample/biological_sample
	///If the vat will restart the sample upon completion
	var/resampler_active = FALSE

///Add that sexy demnand component
/obj/machinery/plumbing/growing_vat/Initialize(mapload, bolt)
	. = ..()
	AddComponent(/datum/component/plumbing/simple_demand, bolt)

/obj/machinery/plumbing/growing_vat/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)

/// Handles properly detaching signal hooks.
/obj/machinery/plumbing/growing_vat/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

///When we process, we make use of our reagents to try and feed the samples we have.
/obj/machinery/plumbing/growing_vat/process()
	if(!is_operational)
		return
	if(!biological_sample)
		return
	if(biological_sample.handle_growth(src))
		if(!prob(10))
			return
		playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
		audible_message(pick(list(span_notice("[src] grumbles!"), span_notice("[src] makes a splashing noise!"), span_notice("[src] sloshes!"))))

///Handles the petri dish depositing into the vat.
/obj/machinery/plumbing/growing_vat/attacked_by(obj/item/I, mob/living/user)
	if(!istype(I, /obj/item/petri_dish))
		return ..()

	var/obj/item/petri_dish/petri = I

	if(!petri.sample)
		return ..()

	if(biological_sample)
		to_chat(user, span_warning("There is already a sample in the vat!"))
		return
	deposit_sample(user, petri)

///Creates a clone of the supplied sample and puts it in the vat
/obj/machinery/plumbing/growing_vat/proc/deposit_sample(mob/user, obj/item/petri_dish/petri)
	biological_sample = new
	for(var/datum/micro_organism/m in petri.sample.micro_organisms)
		biological_sample.micro_organisms += new m.type()
	biological_sample.sample_layers = petri.sample.sample_layers
	biological_sample.sample_color = petri.sample.sample_color
	to_chat(user, span_warning("You put some of the sample in the vat!"))
	playsound(src, 'sound/effects/bubbles.ogg', 50, TRUE)
	update_appearance()
	RegisterSignal(biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED, .proc/on_sample_growth_completed)

///Adds text for when there is a sample in the vat
/obj/machinery/plumbing/growing_vat/examine(mob/user)
	. = ..()
	if(!biological_sample)
		return
	. += span_notice("It seems to have a sample in it!")
	for(var/i in biological_sample.micro_organisms)
		var/datum/micro_organism/MO = i
		. += MO.get_details(user.research_scanner)

/obj/machinery/plumbing/growing_vat/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
	. = ..()
	QDEL_NULL(biological_sample)

/// Call update icon when reagents change to update the reagent content icons. Eats signal args.
/obj/machinery/plumbing/growing_vat/proc/on_reagent_change(datum/reagents/holder, ...)
	SIGNAL_HANDLER
	update_appearance()
	return NONE

///Adds overlays to show the reagent contents
/obj/machinery/plumbing/growing_vat/update_overlays()
	. = ..()
	var/static/image/on_overlay
	var/static/image/off_overlay
	var/static/image/emissive_overlay
	if(isnull(on_overlay))
		on_overlay = iconstate2appearance(icon, "growing_vat_on")
		off_overlay = iconstate2appearance(icon, "growing_vat_off")
		emissive_overlay = emissive_appearance(icon, "growing_vat_glow", alpha = src.alpha)
	. += emissive_overlay
	if(is_operational)
		if(resampler_active)
			. += on_overlay
		else
			. += off_overlay
	if(!reagents.total_volume)
		return
	var/reagentcolor = mix_color_from_reagents(reagents.reagent_list)
	var/mutable_appearance/base_overlay = mutable_appearance(icon, "vat_reagent")
	base_overlay.appearance_flags = RESET_COLOR
	base_overlay.color = reagentcolor
	. += base_overlay
	if(biological_sample && is_operational)
		var/mutable_appearance/bubbles_overlay = mutable_appearance(icon, "vat_bubbles")
		. += bubbles_overlay

/obj/machinery/plumbing/growing_vat/attack_hand(mob/living/user, list/modifiers)
	. = ..()
	playsound(src, 'sound/machines/click.ogg', 30, TRUE)
	if(obj_flags & EMAGGED)
		return
	resampler_active = !resampler_active
	balloon_alert_to_viewers("resampler [resampler_active ? "activated" : "deactivated"]")
	update_appearance()

/obj/machinery/plumbing/growing_vat/emag_act(mob/user)
	if(obj_flags & EMAGGED)
		return
	obj_flags |= EMAGGED
	playsound(src, "sparks", 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
	to_chat(user, span_warning("You overload [src]'s resampling circuit."))
	flick("growing_vat_emagged", src)

/obj/machinery/plumbing/growing_vat/proc/on_sample_growth_completed()
	SIGNAL_HANDLER
	if(resampler_active)
		addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(src), 'sound/effects/servostep.ogg', 100, 1), 1.5 SECONDS)
		biological_sample.reset_sample()
		return SPARE_SAMPLE
	UnregisterSignal(biological_sample, COMSIG_SAMPLE_GROWTH_COMPLETED)


code:
//Xenobio control console
/mob/camera/ai_eye/remote/xenobio
	visible_icon = TRUE
	icon = 'icons/mob/cameramob.dmi'
	icon_state = "generic_camera"
	var/allowed_area = null

/mob/camera/ai_eye/remote/xenobio/Initialize(mapload)
	var/area/A = get_area(loc)
	allowed_area = A.name
	. = ..()

/mob/camera/ai_eye/remote/xenobio/setLoc(destination)
	var/area/new_area = get_area(destination)
	if(new_area && new_area.name == allowed_area || new_area && (new_area.area_flags & XENOBIOLOGY_COMPATIBLE))
		return ..()
	else
		return

/obj/machinery/computer/camera_advanced/xenobio
	name = "Slime management console"
	desc = "A computer used for remotely handling slimes."
	networks = list("ss13")
	circuit = /obj/item/circuitboard/computer/xenobiology
	var/datum/action/innate/slime_place/slime_place_action
	var/datum/action/innate/slime_pick_up/slime_up_action
	var/datum/action/innate/feed_slime/feed_slime_action
	var/datum/action/innate/monkey_recycle/monkey_recycle_action
	var/datum/action/innate/slime_scan/scan_action
	var/datum/action/innate/feed_potion/potion_action
	var/datum/action/innate/hotkey_help/hotkey_help

	var/obj/machinery/monkey_recycler/connected_recycler
	var/list/stored_slimes
	var/obj/item/slimepotion/slime/current_potion
	var/max_slimes = 5
	var/monkeys = 0

	icon_screen = "slime_comp"
	icon_keyboard = "rd_key"

	light_color = LIGHT_COLOR_PINK

/obj/machinery/computer/camera_advanced/xenobio/Initialize(mapload)
	. = ..()
	slime_place_action = new
	slime_up_action = new
	feed_slime_action = new
	monkey_recycle_action = new
	scan_action = new
	potion_action = new
	hotkey_help = new
	stored_slimes = list()
	for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
		if(get_area(recycler.loc) == get_area(loc))
			connected_recycler = recycler
			connected_recycler.connected += src

/obj/machinery/computer/camera_advanced/xenobio/Destroy()
	QDEL_NULL(current_potion)
	for(var/thing in stored_slimes)
		var/mob/living/simple_animal/slime/S = thing
		S.forceMove(drop_location())
	stored_slimes.Cut()
	if(connected_recycler)
		connected_recycler.connected -= src
	connected_recycler = null
	return ..()

/obj/machinery/computer/camera_advanced/xenobio/handle_atom_del(atom/A)
	if(A == current_potion)
		current_potion = null
	if(A in stored_slimes)
		stored_slimes -= A
	return ..()

/obj/machinery/computer/camera_advanced/xenobio/CreateEye()
	eyeobj = new /mob/camera/ai_eye/remote/xenobio(get_turf(src))
	eyeobj.origin = src
	eyeobj.visible_icon = TRUE
	eyeobj.icon = 'icons/mob/cameramob.dmi'
	eyeobj.icon_state = "generic_camera"

/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user)
	..()

	if(slime_up_action)
		slime_up_action.target = src
		slime_up_action.Grant(user)
		actions += slime_up_action

	if(slime_place_action)
		slime_place_action.target = src
		slime_place_action.Grant(user)
		actions += slime_place_action

	if(feed_slime_action)
		feed_slime_action.target = src
		feed_slime_action.Grant(user)
		actions += feed_slime_action

	if(monkey_recycle_action)
		monkey_recycle_action.target = src
		monkey_recycle_action.Grant(user)
		actions += monkey_recycle_action

	if(scan_action)
		scan_action.target = src
		scan_action.Grant(user)
		actions += scan_action

	if(potion_action)
		potion_action.target = src
		potion_action.Grant(user)
		actions += potion_action

	if(hotkey_help)
		hotkey_help.target = src
		hotkey_help.Grant(user)
		actions += hotkey_help

	RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl)
	RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl)
	RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl)
	RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt)
	RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift)
	RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift)

	//Checks for recycler on every interact, prevents issues with load order on certain maps.
	if(!connected_recycler)
		for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
			if(get_area(recycler.loc) == get_area(loc))
				connected_recycler = recycler
				connected_recycler.connected += src

/obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user)
	UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL)
	UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL)
	UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL)
	UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT)
	UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT)
	UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT)
	..()

/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params)
	if(istype(O, /obj/item/food/monkeycube))
		monkeys++
		to_chat(user, span_notice("You feed [O] to [src]. It now has [monkeys] monkey cubes stored."))
		qdel(O)
		return
	else if(istype(O, /obj/item/storage/bag))
		var/obj/item/storage/P = O
		var/loaded = FALSE
		for(var/obj/G in P.contents)
			if(istype(G, /obj/item/food/monkeycube))
				loaded = TRUE
				monkeys++
				qdel(G)
		if(loaded)
			to_chat(user, span_notice("You fill [src] with the monkey cubes stored in [O]. [src] now has [monkeys] monkey cubes stored."))
		return
	else if(istype(O, /obj/item/slimepotion/slime))
		var/replaced = FALSE
		if(user && !user.transferItemToLoc(O, src))
			return
		if(!QDELETED(current_potion))
			current_potion.forceMove(drop_location())
			replaced = TRUE
		current_potion = O
		to_chat(user, span_notice("You load [O] in the console's potion slot[replaced ? ", replacing the one that was there before" : ""]."))
		return
	..()

/obj/machinery/computer/camera_advanced/xenobio/multitool_act(mob/living/user, obj/item/multitool/I)
	. = ..()
	if (istype(I) && istype(I.buffer,/obj/machinery/monkey_recycler))
		to_chat(user, span_notice("You link [src] with [I.buffer] in [I] buffer."))
		connected_recycler = I.buffer
		connected_recycler.connected += src
		return TRUE

/datum/action/innate/slime_place
	name = "Place Slimes"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "slime_down"

/datum/action/innate/slime_place/Activate()
	if(!target || !isliving(owner))
		return
	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = target

	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
			S.forceMove(remote_eye.loc)
			S.visible_message(span_notice("[S] warps in!"))
			X.stored_slimes -= S
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/slime_pick_up
	name = "Pick up Slime"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "slime_up"

/datum/action/innate/slime_pick_up/Activate()
	if(!target || !isliving(owner))
		return
	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = target

	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
			if(X.stored_slimes.len >= X.max_slimes)
				break
			if(!S.ckey)
				if(S.buckled)
					S.Feedstop(silent = TRUE)
				S.visible_message(span_notice("[S] vanishes in a flash of light!"))
				S.forceMove(X)
				X.stored_slimes += S
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/feed_slime
	name = "Feed Slimes"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "monkey_down"

/datum/action/innate/feed_slime/Activate()
	if(!target || !isliving(owner))
		return
	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = target

	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		if(X.monkeys >= 1)
			var/mob/living/carbon/human/species/monkey/food = new /mob/living/carbon/human/species/monkey(remote_eye.loc, TRUE, owner)
			if (!QDELETED(food))
				food.LAssailant = WEAKREF(C)
				X.monkeys--
				X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
				to_chat(owner, span_notice("[X] now has [X.monkeys] monkeys stored."))
		else
			to_chat(owner, span_warning("[X] needs to have at least 1 monkey stored. Currently has [X.monkeys] monkeys stored."))
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/monkey_recycle
	name = "Recycle Monkeys"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "monkey_up"

/datum/action/innate/monkey_recycle/Activate()
	if(!target || !isliving(owner))
		return
	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = target
	var/obj/machinery/monkey_recycler/recycler = X.connected_recycler

	if(!recycler)
		to_chat(owner, span_warning("There is no connected monkey recycler. Use a multitool to link one."))
		return
	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		for(var/mob/living/carbon/human/M in remote_eye.loc)
			if(!ismonkey(M))
				continue
			if(M.stat)
				M.visible_message(span_notice("[M] vanishes as [M.p_theyre()] reclaimed for recycling!"))
				recycler.use_power(500)
				X.monkeys += recycler.cube_production
				X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
				qdel(M)
				to_chat(owner, span_notice("[X] now has [X.monkeys] monkeys available."))
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/slime_scan
	name = "Scan Slime"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "slime_scan"

/datum/action/innate/slime_scan/Activate()
	if(!target || !isliving(owner))
		return
	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control

	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
			slime_scan(S, C)
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/feed_potion
	name = "Apply Potion"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "slime_potion"

/datum/action/innate/feed_potion/Activate()
	if(!target || !isliving(owner))
		return

	var/mob/living/C = owner
	var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = target

	if(QDELETED(X.current_potion))
		to_chat(owner, span_warning("No potion loaded."))
		return

	if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
		for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
			X.current_potion.attack(S, C)
			break
	else
		to_chat(owner, span_warning("Target is not near a camera. Cannot proceed."))

/datum/action/innate/hotkey_help
	name = "Hotkey Help"
	icon_icon = 'icons/mob/actions/actions_silicon.dmi'
	button_icon_state = "hotkey_help"

/datum/action/innate/hotkey_help/Activate()
	if(!target || !isliving(owner))
		return
	to_chat(owner, "<b>Click shortcuts:</b>")
	to_chat(owner, "Shift-click a slime to pick it up, or the floor to drop all held slimes.")
	to_chat(owner, "Ctrl-click a slime to scan it.")
	to_chat(owner, "Alt-click a slime to feed it a potion.")
	to_chat(owner, "Ctrl-click or a dead monkey to recycle it, or the floor to place a new monkey.")

//
// Alternate clicks for slime, monkey and open turf if using a xenobio console

//Feeds a potion to slime
/mob/living/simple_animal/slime/AltClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_ALT, src)
	..()

//Picks up slime
/mob/living/simple_animal/slime/ShiftClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_SHIFT, src)
	..()

//Place slimes
/turf/open/ShiftClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_SHIFT, src)
	..()

//scans slimes
/mob/living/simple_animal/slime/CtrlClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_CTRL, src)
	..()

//picks up dead monkies
/mob/living/carbon/human/species/monkey/CtrlClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src)
	..()

//places monkies
/turf/open/CtrlClick(mob/user)
	SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_CTRL, src)
	..()

// Scans slime
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/simple_animal/slime/S)
	SIGNAL_HANDLER
	if(!GLOB.cameranet.checkTurfVis(S.loc))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/area/mobarea = get_area(S.loc)
	if(mobarea.name == E.allowed_area || (mobarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		slime_scan(S, C)

//Feeds a potion to slime
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/simple_animal/slime/S)
	SIGNAL_HANDLER
	if(!GLOB.cameranet.checkTurfVis(S.loc))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
	var/area/mobarea = get_area(S.loc)
	if(QDELETED(X.current_potion))
		to_chat(C, span_warning("No potion loaded."))
		return
	if(mobarea.name == E.allowed_area || (mobarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		INVOKE_ASYNC(X.current_potion, /obj/item/slimepotion/slime.proc/attack, S, C)

//Picks up slime
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/simple_animal/slime/S)
	SIGNAL_HANDLER
	if(!GLOB.cameranet.checkTurfVis(S.loc))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
	var/area/mobarea = get_area(S.loc)
	if(mobarea.name == E.allowed_area || (mobarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		if(X.stored_slimes.len >= X.max_slimes)
			to_chat(C, span_warning("Slime storage is full."))
			return
		if(S.ckey)
			to_chat(C, span_warning("The slime wiggled free!"))
			return
		if(S.buckled)
			S.Feedstop(silent = TRUE)
		S.visible_message(span_notice("[S] vanishes in a flash of light!"))
		S.forceMove(X)
		X.stored_slimes += S

//Place slimes
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickShift(mob/living/user, turf/open/T)
	SIGNAL_HANDLER

	if(!GLOB.cameranet.checkTurfVis(T))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
	var/area/turfarea = get_area(T)
	if(turfarea.name == E.allowed_area || (turfarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
			S.forceMove(T)
			S.visible_message(span_notice("[S] warps in!"))
			X.stored_slimes -= S

//Place monkey
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickCtrl(mob/living/user, turf/open/T)
	SIGNAL_HANDLER
	if(!GLOB.cameranet.checkTurfVis(T))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
	var/area/turfarea = get_area(T)
	if(turfarea.name == E.allowed_area || (turfarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		if(X.monkeys >= 1)
			var/mob/living/carbon/human/food = new /mob/living/carbon/human/species/monkey(T, TRUE, C)
			if (!QDELETED(food))
				food.LAssailant = WEAKREF(C)
				X.monkeys--
				X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
				to_chat(C, span_notice("[X] now has [X.monkeys] monkeys stored."))
		else
			to_chat(C, span_warning("[X] needs to have at least 1 monkey stored. Currently has [X.monkeys] monkeys stored."))

//Pick up monkey
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/human/M)
	SIGNAL_HANDLER
	if(!ismonkey(M))
		return
	if(!isturf(M.loc) || !GLOB.cameranet.checkTurfVis(M.loc))
		to_chat(user, span_warning("Target is not near a camera. Cannot proceed."))
		return
	var/mob/living/C = user
	var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
	var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
	var/area/mobarea = get_area(M.loc)
	if(!X.connected_recycler)
		to_chat(C, span_warning("There is no connected monkey recycler. Use a multitool to link one."))
		return
	if(mobarea.name == E.allowed_area || (mobarea.area_flags & XENOBIOLOGY_COMPATIBLE))
		if(!M.stat)
			return
		M.visible_message(span_notice("[M] vanishes as [p_theyre()] reclaimed for recycling!"))
		X.connected_recycler.use_power(500)
		X.monkeys += connected_recycler.cube_production
		X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
		qdel(M)
		to_chat(C, span_notice("[X] now has [X.monkeys] monkeys available."))