code:
#define INJECTOR_TIMEOUT 300
#define REJUVENATORS_INJECT 15
#define REJUVENATORS_MAX 90
#define NUMBER_OF_BUFFERS 3

#define RADIATION_STRENGTH_MAX 15
#define RADIATION_STRENGTH_MULTIPLIER 1			//larger has a more range

#define RADIATION_DURATION_MAX 30
#define RADIATION_ACCURACY_MULTIPLIER 3			//larger is less accurate

#define RADIATION_IRRADIATION_MULTIPLIER 0.2	//multiplier for how much radiation a test subject recieves

#define BAD_MUTATION_DIFFICULTY 2
#define GOOD_MUTATION_DIFFICULTY 4
#define OP_MUTATION_DIFFICULTY 5
/////////////////////////// DNA DATUM
/datum/dna
	var/unique_enzymes
	var/struc_enzymes
	var/uni_identity
	var/blood_type
	var/datum/species/species = new /datum/species/human() //The type of mutant race the player is if applicable (i.e. potato-man)
	var/mutant_color = "FFF"		 // What color you are if you have certain speciess
	var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings,
	var/list/mutations = list()   //All mutations are from now on here
	var/mob/living/carbon/holder

/datum/dna/New(mob/living/carbon/new_holder)
	if(new_holder && istype(new_holder))
		holder = new_holder

/datum/dna/proc/transfer_identity(mob/living/carbon/destination)
	if(check_dna_integrity(destination))
		destination.dna.unique_enzymes = unique_enzymes
		destination.dna.uni_identity = uni_identity
		destination.dna.blood_type = blood_type
		hardset_dna(destination, null, null, null, null, species.type)
		destination.dna.real_name = real_name
		destination.dna.mutations = mutations

/datum/dna/proc/add_mutation(mutation_name)
	var/datum/mutation/human/HM = mutations_list[mutation_name]
	HM.on_acquiring(holder)

/datum/dna/proc/remove_mutation(mutation_name)
	var/datum/mutation/human/HM = mutations_list[mutation_name]
	HM.on_losing(holder)

/datum/dna/proc/check_mutation(mutation_name)
	var/datum/mutation/human/HM = mutations_list[mutation_name]
	return mutations.Find(HM)

/datum/dna/proc/remove_all_mutations()
	remove_mutation_group(mutations)

/datum/dna/proc/remove_mutation_group(list/group)
	if(!group)	return
	for(var/datum/mutation/human/HM in group)
		HM.force_lose(holder)

/datum/dna/proc/generate_uni_identity(mob/living/carbon/character)
	. = ""
	var/list/L = new /list(DNA_UNI_IDENTITY_BLOCKS)
	if(istype(character))
		L[DNA_GENDER_BLOCK] = construct_block((character.gender!=MALE)+1, 2)
		if(istype(character, /mob/living/carbon/human))
			var/mob/living/carbon/human/H = character
			if(!H.dna.species)
				hardset_dna(H, null, null, null, null, /datum/species/human)
			if(!hair_styles_list.len)
				init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, hair_styles_list, hair_styles_male_list, hair_styles_female_list)
			L[DNA_HAIR_STYLE_BLOCK] = construct_block(hair_styles_list.Find(H.hair_style), hair_styles_list.len)
			L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color)
			if(!facial_hair_styles_list.len)
				init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, facial_hair_styles_list, facial_hair_styles_male_list, facial_hair_styles_female_list)
			L[DNA_FACIAL_HAIR_STYLE_BLOCK] = construct_block(facial_hair_styles_list.Find(H.facial_hair_style), facial_hair_styles_list.len)
			L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color)
			L[DNA_SKIN_TONE_BLOCK] = construct_block(skin_tones.Find(H.skin_tone), skin_tones.len)
			L[DNA_EYE_COLOR_BLOCK] = sanitize_hexcolor(H.eye_color)

	for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
		if(L[i])	. += L[i]
		else		. += random_string(DNA_BLOCK_SIZE,hex_characters)
	return .

/datum/dna/proc/generate_struc_enzymes(mob/living/carbon/character)
	var/list/L = list("0","1","2","3","4","5","6")
	var/list/sorting = new /list(DNA_STRUC_ENZYMES_BLOCKS)
	var/result = ""
	for(var/datum/mutation/human/A in good_mutations + bad_mutations + not_good_mutations)
		if(A.name == RACEMUT && istype(character,/mob/living/carbon/monkey))
			sorting[A.dna_block] = num2hex(A.lowest_value + rand(0, 256 * 6), DNA_BLOCK_SIZE)
			character.dna.mutations.Add(A)
		else
			sorting[A.dna_block] = random_string(DNA_BLOCK_SIZE, L)

	for(var/B in sorting)
		result += B
	return result

/datum/dna/proc/generate_unique_enzymes(mob/living/carbon/character)
	. = ""
	if(istype(character))
		real_name = character.real_name
		. += md5(character.real_name)
	else
		. += repeat_string(DNA_UNIQUE_ENZYMES_LEN, "0")
	return .

/datum/dna/proc/mutations_say_mods(var/message)
	if(message)
		for(var/datum/mutation/human/M in mutations)
			message = M.say_mod(message)
		return message

/proc/hardset_dna(mob/living/carbon/owner, ui, se, real_name, blood_type, datum/species/mrace, mcolor)
	if(!istype(owner, /mob/living/carbon/monkey) && !istype(owner, /mob/living/carbon/human))
		return
	if(!owner.dna)
		create_dna(owner, mrace)

	if(mrace)
		if(owner.dna.species.exotic_blood)
			var/datum/reagent/exotic_blood = owner.dna.species.exotic_blood
			var/datum/reagent/R = new exotic_blood
			owner.reagents.del_reagent(R.id)
			qdel(R)
		owner.dna.species = new mrace()

	if(mcolor)
		owner.dna.mutant_color = mcolor

	if(real_name)
		owner.real_name = real_name
		owner.dna.generate_unique_enzymes(owner)

	if(blood_type)
		owner.dna.blood_type = blood_type

	if(ui)
		owner.dna.uni_identity = ui
		updateappearance(owner)

	if(se)
		owner.dna.struc_enzymes = se
		domutcheck(owner)

	check_dna_integrity(owner)

	owner.regenerate_icons()
	return

/proc/check_dna_integrity(mob/living/carbon/character)
	if(!character || !(istype(character, /mob/living/carbon/human) || istype(character, /mob/living/carbon/monkey))) //Evict xenos from carbon 2012
		return
	if(!character.dna)
		if(ready_dna(character))
			return character.dna
		return

	if(length(character.dna.uni_identity) != DNA_UNI_IDENTITY_BLOCKS*DNA_BLOCK_SIZE)
		character.dna.uni_identity = character.dna.generate_uni_identity(character)
	if(length(character.dna.struc_enzymes)!= DNA_STRUC_ENZYMES_BLOCKS*DNA_BLOCK_SIZE)
		character.dna.struc_enzymes = character.dna.generate_struc_enzymes()
	if(!character.dna.real_name || length(character.dna.unique_enzymes) != DNA_UNIQUE_ENZYMES_LEN)
		character.dna.unique_enzymes = character.dna.generate_unique_enzymes(character)
	return character.dna

/proc/ready_dna(mob/living/carbon/character, blood_type)
	if(!istype(character, /mob/living/carbon/monkey) && !istype(character, /mob/living/carbon/human))
		return
	if(!character.dna)
		create_dna(character)
	if(blood_type)
		character.dna.blood_type = blood_type
		character.dna.real_name = character.real_name
	character.dna.uni_identity = character.dna.generate_uni_identity(character)
	character.dna.struc_enzymes = character.dna.generate_struc_enzymes(character)
	character.dna.unique_enzymes = character.dna.generate_unique_enzymes(character)
	return character.dna

/proc/create_dna(mob/living/carbon/C, datum/species/S) //don't use this unless you're about to use hardset_dna or ready_dna
	C.dna = new /datum/dna(C)
	C.dna.holder = C
	if(S)	C.dna.species = new S()	// do not remove; this is here to prevent runtimes

/////////////////////////// DNA DATUM

/////////////////////////// DNA HELPER-PROCS
/proc/getleftblocks(input,blocknumber,blocksize)
	if(blocknumber > 1)
		return copytext(input,1,((blocksize*blocknumber)-(blocksize-1)))

/proc/getrightblocks(input,blocknumber,blocksize)
	if(blocknumber < (length(input)/blocksize))
		return copytext(input,blocksize*blocknumber+1,length(input)+1)

/proc/getblock(input, blocknumber, blocksize=DNA_BLOCK_SIZE)
	return copytext(input, blocksize*(blocknumber-1)+1, (blocksize*blocknumber)+1)

/proc/setblock(istring, blocknumber, replacement, blocksize=DNA_BLOCK_SIZE)
	if(!istring || !blocknumber || !replacement || !blocksize)	return 0
	return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)

/proc/scramble(input,rs,rd)
	var/length = length(input)
	var/ran = gaussian(0, rs*RADIATION_STRENGTH_MULTIPLIER)
	if(ran == 0)		ran = pick(-1,1)	//hacky, statistically should almost never happen. 0-change makes people mad though
	else if(ran < 0)	ran = round(ran)	//negative, so floor it
	else				ran = -round(-ran)	//positive, so ceiling it
	return num2hex(Wrap(hex2num(input)+ran, 0, 16**length), length)

/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks)
	return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1)

/proc/randmut(mob/living/carbon/M, list/candidates, difficulty = 2)
	if(!check_dna_integrity(M))
		return
	var/datum/mutation/human/num = pick(candidates)
	. = num.force_give(M)
	return

/proc/randmutb(mob/living/carbon/M)
	if(!check_dna_integrity(M))
		return
	var/datum/mutation/human/HM = pick((bad_mutations | not_good_mutations) - mutations_list[RACEMUT])
	. = HM.force_give(M)

/proc/randmutg(mob/living/carbon/M)
	if(!check_dna_integrity(M))
		return
	var/datum/mutation/human/HM = pick(good_mutations)
	. = HM.force_give(M)

/proc/randmuti(mob/living/carbon/M)
	if(!check_dna_integrity(M))	return
	var/num = rand(1, DNA_STRUC_ENZYMES_BLOCKS)
	var/newdna = setblock(M.dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, hex_characters))
	M.dna.uni_identity = newdna
	return

/proc/clean_dna(mob/living/carbon/M)
	if(!check_dna_integrity(M))
		return
	M.dna.remove_all_mutations()

/proc/clean_randmut(mob/living/carbon/M, list/candidates, difficulty = 2)
	clean_dna(M)
	randmut(M, candidates, difficulty)

/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
	if(!check_dna_integrity(M))
		return 0
	if(se)
		for(var/i=1, i<=DNA_STRUC_ENZYMES_BLOCKS, i++)
			if(prob(probability))
				M.dna.struc_enzymes = setblock(M.dna.struc_enzymes, i, random_string(DNA_BLOCK_SIZE, hex_characters))
		domutcheck(M)
	if(ui)
		for(var/i=1, i<=DNA_UNI_IDENTITY_BLOCKS, i++)
			if(prob(probability))
				M.dna.uni_identity = setblock(M.dna.uni_identity, i, random_string(DNA_BLOCK_SIZE, hex_characters))
		updateappearance(M)
	return 1

/////////////////////////// DNA HELPER-PROCS

/////////////////////////// DNA MISC-PROCS
/proc/updateappearance(mob/living/carbon/C)
	if(!check_dna_integrity(C))
		return 0

	var/structure = C.dna.uni_identity
	C.gender = (deconstruct_block(getblock(structure, DNA_GENDER_BLOCK), 2)-1) ? FEMALE : MALE
	if(istype(C, /mob/living/carbon/human))
		var/mob/living/carbon/human/H = C
		H.hair_color = sanitize_hexcolor(getblock(structure, DNA_HAIR_COLOR_BLOCK))
		H.facial_hair_color = sanitize_hexcolor(getblock(structure, DNA_FACIAL_HAIR_COLOR_BLOCK))
		H.skin_tone = skin_tones[deconstruct_block(getblock(structure, DNA_SKIN_TONE_BLOCK), skin_tones.len)]
		H.eye_color = sanitize_hexcolor(getblock(structure, DNA_EYE_COLOR_BLOCK))
		H.facial_hair_style = facial_hair_styles_list[deconstruct_block(getblock(structure, DNA_FACIAL_HAIR_STYLE_BLOCK), facial_hair_styles_list.len)]
		H.hair_style = hair_styles_list[deconstruct_block(getblock(structure, DNA_HAIR_STYLE_BLOCK), hair_styles_list.len)]

		H.update_body()
		H.update_hair()
	return 1

/proc/domutcheck(mob/living/carbon/M)
	if(!check_dna_integrity(M))
		return 0

	var/mob/living/carbon/C = M
	var/mob/living/carbon/temp

	for(var/datum/mutation/human/A in good_mutations | bad_mutations | not_good_mutations)
		temp = A.check_block(C)
		if(ismob(temp))
			C = temp

//////////////////////////////////////////////////////////// Monkey Block
	if(M)
		M.regenerate_icons()
	return 1
/////////////////////////// DNA MISC-PROCS

/////////////////////////// DNA MACHINES
/obj/machinery/dna_scannernew
	name = "\improper DNA scanner"
	desc = "It scans DNA structures."
	icon = 'icons/obj/Cryogenic2.dmi'
	icon_state = "scanner"
	density = 1
	var/locked = 0
	anchored = 1
	use_power = 1
	idle_power_usage = 50
	active_power_usage = 300
	var/damage_coeff
	var/scan_level
	var/precision_coeff

/obj/machinery/dna_scannernew/New()
	..()
	component_parts = list()
	component_parts += new /obj/item/weapon/circuitboard/clonescanner(null)
	component_parts += new /obj/item/weapon/stock_parts/scanning_module(null)
	component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
	component_parts += new /obj/item/weapon/stock_parts/micro_laser(null)
	component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
	component_parts += new /obj/item/stack/cable_coil(null, 1)
	component_parts += new /obj/item/stack/cable_coil(null, 1)
	RefreshParts()

/obj/machinery/dna_scannernew/RefreshParts()
	scan_level = 0
	damage_coeff = 0
	precision_coeff = 0
	for(var/obj/item/weapon/stock_parts/scanning_module/P in component_parts)
		scan_level += P.rating
	for(var/obj/item/weapon/stock_parts/manipulator/P in component_parts)
		precision_coeff = P.rating
	for(var/obj/item/weapon/stock_parts/micro_laser/P in component_parts)
		damage_coeff = P.rating

/obj/machinery/dna_scannernew/update_icon()

	//no power or maintenance
	if(stat & (NOPOWER|BROKEN))
		icon_state = initial(icon_state)+ (state_open ? "_open" : "") + "_unpowered"
		return

	if((stat & MAINT) || panel_open)
		icon_state = initial(icon_state)+ (state_open ? "_open" : "") + "_maintenance"
		return

	//running and someone in there
	if(occupant)
		icon_state = initial(icon_state)+ "_occupied"
		return

	//running
	icon_state = initial(icon_state)+ (state_open ? "_open" : "")

/obj/machinery/dna_scannernew/power_change()
	..()
	update_icon()

/obj/machinery/dna_scannernew/proc/toggle_open(var/mob/user)
	if(panel_open)
		user << "Close the maintenance panel first."
		return

	if(state_open)
		close_machine()
		return

	else if(locked)
		user << "The bolts are locked down, securing the door shut."
		return

	open_machine()

/obj/machinery/dna_scannernew/container_resist()
	var/mob/living/user = usr
	var/breakout_time = 2
	if(state_open || !locked)	//Open and unlocked, no need to escape
		state_open = 1
		return
	user.changeNext_move(CLICK_CD_BREAKOUT)
	user.last_special = world.time + CLICK_CD_BREAKOUT
	user << "You lean on the back of [src] and start pushing the door open. (this will take about [breakout_time] minutes.)"
	user.visible_message("You hear a metallic creaking from [src]!")

	if(do_after(user,(breakout_time*60*10))) //minutes * 60seconds * 10deciseconds
		if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
			return

		locked = 0
		visible_message("[user] successfully broke out of [src]!")
		user << "You successfully break out of [src]!"

		open_machine()

/obj/machinery/dna_scannernew/close_machine()
	if(!state_open)
		return 0

	..()

	// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
	if(occupant)
		if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
			|| locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \
			|| locate(/obj/machinery/computer/cloning, get_step(src, EAST)) \
			|| locate(/obj/machinery/computer/cloning, get_step(src, WEST)))

			var/mob/dead/observer/ghost = occupant.get_ghost()
			if(ghost)
				ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be cloned! (Verbs -> Ghost -> Re-enter corpse)"
				ghost << sound('sound/effects/genetics.ogg')
	return 1

/obj/machinery/dna_scannernew/open_machine()
	if(state_open)
		return 0

	..()

	return 1

/obj/machinery/dna_scannernew/relaymove(mob/user as mob)
	if(user.stat || locked)
		return

	open_machine()
	return

/obj/machinery/dna_scannernew/attackby(var/obj/item/I, mob/user, params)

	if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant...
		update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed
		return

	if(exchange_parts(user, I))
		return

	if(default_pry_open(I))
		return

	if(default_deconstruction_crowbar(I))
		return

	if(istype(I, /obj/item/weapon/grab))
		var/obj/item/weapon/grab/G = I
		if(!ismob(G.affecting))
			return

		if(!state_open)
			user << "Open the scanner first."
			return

		var/mob/M = G.affecting
		M.loc = loc
		user.stop_pulling()
		qdel(G)

/obj/machinery/dna_scannernew/attack_hand(mob/user)
	if(..(user,1,0)) //don't set the machine, since there's no dialog
		return

	toggle_open(user)

/obj/machinery/dna_scannernew/blob_act()
	if(prob(75))
		qdel(src)

//DNA COMPUTER
/obj/machinery/computer/scan_consolenew
	name = "\improper DNA scanner access console"
	desc = "Scan DNA."
	icon = 'icons/obj/computer.dmi'
	icon_state = "scanner"
	density = 1
	circuit = /obj/item/weapon/circuitboard/scan_consolenew
	var/radduration = 2
	var/radstrength = 1

	var/list/buffer[NUMBER_OF_BUFFERS]

	var/injectorready = 0	//Quick fix for issue 286 (screwdriver the screen twice to restore injector)	-Pete
	var/current_screen = "mainmenu"
	var/obj/machinery/dna_scannernew/connected = null
	var/obj/item/weapon/disk/data/diskette = null
	anchored = 1.0
	use_power = 1
	idle_power_usage = 10
	active_power_usage = 400

/obj/machinery/computer/scan_consolenew/attackby(obj/item/I as obj, mob/user as mob, params)
	if (istype(I, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES
		if (!src.diskette)
			user.drop_item()
			I.loc = src
			src.diskette = I
			user << "You insert [I]."
			src.updateUsrDialog()
			return
	else
		..()
	return

/obj/machinery/computer/scan_consolenew/New()
	..()

	spawn(5)
		for(dir in list(NORTH,EAST,SOUTH,WEST))
			connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
			if(!isnull(connected))
				break
		spawn(250)
			injectorready = 1
		return
	return

/obj/machinery/computer/scan_consolenew/attack_hand(mob/user)
	if(..())
		return
	ShowInterface(user)

/obj/machinery/computer/scan_consolenew/proc/ShowInterface(mob/user, last_change)
	if(!user) return
	var/datum/browser/popup = new(user, "scannernew", "DNA Modifier Console", 880, 600) // Set up the popup browser window
	if(!( in_range(src, user) || istype(user, /mob/living/silicon) ))
		popup.close()
		return
	popup.add_stylesheet("scannernew", 'html/browser/scannernew.css')

	var/mob/living/carbon/viable_occupant
	var/occupant_status = "

Subject Status:

"
	var/scanner_status
	var/temp_html
	if(connected && connected.is_operational())
		if(connected.occupant)	//set occupant_status message
			viable_occupant = connected.occupant
			if(check_dna_integrity(viable_occupant) && (!(NOCLONE in viable_occupant.mutations) || (connected.scan_level == 3)))	//occupent is viable for dna modification
				occupant_status += "[viable_occupant.name] => "
				switch(viable_occupant.stat)
					if(CONSCIOUS)	occupant_status += "Conscious"
					if(UNCONSCIOUS)	occupant_status += "Unconscious"
					else			occupant_status += "DEAD - Cannot Operate"
				occupant_status += "

"
				occupant_status += "

Health:

[viable_occupant.health]%

"
				occupant_status += "

Radiation Level:

[viable_occupant.radiation]%

"
				var/rejuvenators = viable_occupant.reagents.get_reagent_amount("inaprovaline")
				occupant_status += "

Rejuvenators:

[rejuvenators] units

"
				occupant_status += "

Unique Enzymes :

[viable_occupant.dna.unique_enzymes]

"
				occupant_status += "

Last Operation:

[last_change ? last_change : "----"]

"
			else
				viable_occupant = null
				occupant_status += "Invalid DNA structure

"
		else
			occupant_status += "No subject detected

"

		if(connected.state_open)
			scanner_status = "Open"
		else
			scanner_status = "Closed"
			if(connected.locked)
				scanner_status += " (Locked)"
			else
				scanner_status += " (Unlocked)"

	else
		occupant_status += "----

"
		scanner_status += "Error: No scanner detected"

	var/status = "
"
	status += "

Scanner:

[scanner_status]

"
	status += "[occupant_status]"

	status += "
Radiation Emitter Status
"
	var/stddev = radstrength*RADIATION_STRENGTH_MULTIPLIER
	status += "

Output Level:

[radstrength]

"
	status += "

  \> Mutation:

(-[stddev] to +[stddev] = 68%) (-[2*stddev] to +[2*stddev] = 95%)

"
	if(connected)
		stddev = RADIATION_ACCURACY_MULTIPLIER/(radduration + (connected.precision_coeff ** 2))
	else
		stddev = RADIATION_ACCURACY_MULTIPLIER/radduration
	var/chance_to_hit
	switch(stddev)	//hardcoded values from a z-table for a normal distribution
		if(0 to 0.25)			chance_to_hit = ">95%"
		if(0.25 to 0.5)			chance_to_hit = "68-95%"
		if(0.5 to 0.75)			chance_to_hit = "55-68%"
		else					chance_to_hit = "<38%"
	status += "

Pulse Duration:

[radduration]

"
	status += "

  \> Accuracy:

[chance_to_hit]

"
	status += "
" // Close statusDisplay div
	var/buttons = "Scan "
	if(connected)
		buttons += " [connected.state_open ? "Close" : "Open"] Scanner "
		if (connected.state_open)
			buttons += "[connected.locked ? "Unlock" : "Lock"] Scanner "
		else
			buttons += "[connected.locked ? "Unlock" : "Lock"] Scanner "
	else				buttons += "Open Scanner Lock Scanner "
	if(viable_occupant)	buttons += "Inject Rejuvenators "
	else				buttons += "Inject Rejuvenators "
	if(diskette)		buttons += "Eject Disk "
	else				buttons += "Eject Disk "
	if(current_screen == "buffer")	buttons += "Radiation Emitter Menu "
	else							buttons += "Buffer Menu "

	switch(current_screen)
		if("working")
			temp_html += status
			temp_html += "
System Busy
"
			temp_html += "Working ... Please wait ([radduration] Seconds)"
		if("buffer")
			temp_html += status
			temp_html += buttons
			temp_html += "
Buffer Menu
"

			if(istype(buffer))
				for(var/i=1, i<=buffer.len, i++)
					temp_html += "
Slot [i]: "
					var/list/buffer_slot = buffer[i]
					if( !buffer_slot || !buffer_slot.len || !buffer_slot["name"] || !((buffer_slot["UI"] && buffer_slot["UE"]) || buffer_slot["SE"]) )
						temp_html += "
\tNo Data"
						if(viable_occupant)	temp_html += "
Save to Buffer "
						else				temp_html += "
Save to Buffer "
						temp_html += "Clear Buffer "
						if(diskette)		temp_html += "Load from Disk "
						else				temp_html += "Load from Disk "
						temp_html += "Save to Disk "
					else
						var/ui = buffer_slot["UI"]
						var/se = buffer_slot["SE"]
						var/ue = buffer_slot["UE"]
						var/name = buffer_slot["name"]
						var/label = buffer_slot["label"]
						var/blood_type = buffer_slot["blood_type"]
						temp_html += "
\tLabel: [label ? label : name]"
						temp_html += "
\tSubject: [name]"
						if(ue && name && blood_type)
							temp_html += "
\tBlood Type: [blood_type]"
							temp_html += "
\tUE: [ue] "
							if(viable_occupant)	temp_html += "Occupant "
							else				temp_html += "Occupant"
							if(injectorready)	temp_html += "Injector"
							else				temp_html += "Injector"
						else
							temp_html += "
\tBlood Type: No Data"
							temp_html += "
\tUE: No Data"
						if(ui)
							temp_html += "
\tUI: [ui] "
							if(viable_occupant)	temp_html += "Occupant "
							else				temp_html += "Occupant"
							if(injectorready)	temp_html += "Injector"
							else				temp_html += "Injector"
						else
							temp_html += "
\tUI: No Data"
						if(se)
							temp_html += "
\tSE: [se] "
							if(viable_occupant)	temp_html += "Occupant "
							else				temp_html += "Occupant "
							if(injectorready)	temp_html += "Injector"
							else				temp_html += "Injector"
						else
							temp_html += "
\tSE: No Data"
						if(viable_occupant)	temp_html += "
Save to Buffer "
						else				temp_html += "
Save to Buffer "
						temp_html += "Clear Buffer "
						if(diskette)		temp_html += "Load from Disk "
						else				temp_html += "Load from Disk "
						if(diskette && !diskette.read_only)	temp_html += "Save to Disk "
						else								temp_html += "Save to Disk "
		else
			temp_html += status
			temp_html += buttons
			temp_html += "
Radiation Emitter Menu
"

			temp_html += "-- Output Level ++"
			temp_html += "
-- Pulse Duration ++"

			temp_html += "
Irradiate Subject
"
			temp_html += "

Unique Identifier:

"

			var/max_line_len = 7*DNA_BLOCK_SIZE
			if(viable_occupant)
				temp_html += "
1
"
				var/len = length(viable_occupant.dna.uni_identity)
				for(var/i=1, i<=len, i++)
					temp_html += "[copytext(viable_occupant.dna.uni_identity,i,i+1)]"
					if ((i % max_line_len) == 0)
						temp_html += "

"
					if((i % DNA_BLOCK_SIZE) == 0 && i < len)
						temp_html += "
[(i / DNA_BLOCK_SIZE) + 1]
"
			else
				temp_html += "----"
			temp_html += "

"

			temp_html += "

Structural Enzymes:

"
			if(viable_occupant)
				temp_html += "
1
"
				var/len = length(viable_occupant.dna.struc_enzymes)
				for(var/i=1, i<=len, i++)
					temp_html += "[copytext(viable_occupant.dna.struc_enzymes,i,i+1)]"
					if ((i % max_line_len) == 0)
						temp_html += "

"
					if((i % DNA_BLOCK_SIZE) == 0 && i < len)
						temp_html += "
[(i / DNA_BLOCK_SIZE) + 1]
"
			else
				temp_html += "----"
			temp_html += "

"

	popup.set_content(temp_html)
	popup.open()

/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
	if(..())
		return
	if(!isturf(usr.loc))
		return
	if(!( (isturf(loc) && in_range(src, usr)) || istype(usr, /mob/living/silicon) ))
		return
	if(current_screen == "working")
		return

	add_fingerprint(usr)
	usr.set_machine(src)

	var/mob/living/carbon/viable_occupant
	if(connected)
		viable_occupant = connected.occupant
		if(!istype(viable_occupant) || !viable_occupant.dna || (NOCLONE in viable_occupant.mutations))
			viable_occupant = null

	//Basic Tasks///////////////////////////////////////////
	var/num = round(text2num(href_list["num"]))
	var/last_change
	switch(href_list["task"])
		if("togglelock")
			if(connected)	connected.locked = !connected.locked
		if("toggleopen")
			if(connected)	connected.toggle_open(usr)
		if("setduration")
			if(!num)
				num = round(input(usr, "Choose pulse duration:", "Input an Integer", null) as num|null)
			if(num)
				radduration = Wrap(num, 1, RADIATION_DURATION_MAX+1)
		if("setstrength")
			if(!num)
				num = round(input(usr, "Choose pulse strength:", "Input an Integer", null) as num|null)
			if(num)
				radstrength = Wrap(num, 1, RADIATION_STRENGTH_MAX+1)
		if("screen")
			current_screen = href_list["text"]
		if("rejuv")
			if(viable_occupant && viable_occupant.reagents)
				var/inaprovaline_amount = viable_occupant.reagents.get_reagent_amount("inaprovaline")
				var/can_add = max(min(REJUVENATORS_MAX - inaprovaline_amount, REJUVENATORS_INJECT), 0)
				viable_occupant.reagents.add_reagent("inaprovaline", can_add)
		if("setbufferlabel")
			var/text = sanitize(input(usr, "Input a new label:", "Input an Text", null) as text|null)
			if(num && text)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				var/list/buffer_slot = buffer[num]
				if(istype(buffer_slot))
					buffer_slot["label"] = text
		if("setbuffer")
			if(num && viable_occupant)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				buffer[num] = list(
					"label"="Buffer[num]:[viable_occupant.real_name]",
					"UI"=viable_occupant.dna.uni_identity,
					"SE"=viable_occupant.dna.struc_enzymes,
					"UE"=viable_occupant.dna.unique_enzymes,
					"name"=viable_occupant.real_name,
					"blood_type"=viable_occupant.dna.blood_type
					)
		if("clearbuffer")
			if(num)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				var/list/buffer_slot = buffer[num]
				if(istype(buffer_slot))
					buffer_slot.Cut()
		if("transferbuffer")
			if(num && viable_occupant)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				var/list/buffer_slot = buffer[num]
				if(istype(buffer_slot))                                                                                //15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage
					viable_occupant.radiation += rand(15/(connected.damage_coeff ** 2),40/(connected.damage_coeff ** 2)) //Each laser level reduces damage by lvl^2, so no effect on 1 lvl, 4 times less damage on 2 and 9 times less damage on 3
					switch(href_list["text"])                                                                            //Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove
						if("se")
							if(buffer_slot["SE"])
								viable_occupant.dna.struc_enzymes = buffer_slot["SE"]
								domutcheck(viable_occupant)
						if("ui")
							if(buffer_slot["UI"])
								viable_occupant.dna.uni_identity = buffer_slot["UI"]
								updateappearance(viable_occupant)
						else
							if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"])
								viable_occupant.real_name = buffer_slot["name"]
								viable_occupant.name = buffer_slot["name"]
								viable_occupant.dna.unique_enzymes = buffer_slot["UE"]
								viable_occupant.dna.blood_type = buffer_slot["blood_type"]
								updateappearance(viable_occupant)
		if("injector")
			if(num && injectorready)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				var/list/buffer_slot = buffer[num]
				if(istype(buffer_slot))
					var/obj/item/weapon/dnainjector/I
					switch(href_list["text"])
						if("se")
							if(buffer_slot["SE"])
								I = new /obj/item/weapon/dnainjector(loc)
								for(var/datum/mutation/human/HM in good_mutations + bad_mutations + not_good_mutations)
									if(HM.check_block_string(buffer_slot["SE"]))
										if(prob(HM.get_chance))
											I.add_mutations.Add(HM)
									else
										I.remove_mutations.Add(HM)
								I.damage_coeff  = connected.damage_coeff
						if("ui")
							if(buffer_slot["UI"])
								I = new /obj/item/weapon/dnainjector(loc)
								I.fields = list("UI"=buffer_slot["UI"])
								I.damage_coeff = connected.damage_coeff
						else
							if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"])
								I = new /obj/item/weapon/dnainjector(loc)
								I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"])
								I.damage_coeff  = connected.damage_coeff
					if(I)
						injectorready = 0
						spawn(INJECTOR_TIMEOUT)
							injectorready = 1
		if("loaddisk")
			if(num && diskette && diskette.fields)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				buffer[num] = diskette.fields.Copy()
		if("savedisk")
			if(num && diskette && !diskette.read_only)
				num = Clamp(num, 1, NUMBER_OF_BUFFERS)
				var/list/buffer_slot = buffer[num]
				if(istype(buffer_slot))
					diskette.name = "data disk \[[buffer_slot["label"]]\]"
					diskette.fields = buffer_slot.Copy()
		if("ejectdisk")
			if(diskette)
				diskette.loc = get_turf(src)
				diskette = null
		if("pulseui","pulsese")
			if(num && viable_occupant && connected && viable_occupant.stat != DEAD)
				radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1)
				radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1)

				var/locked_state = connected.locked
				connected.locked = 1

				current_screen = "working"
				ShowInterface(usr)

				sleep(radduration*10)
				current_screen = "mainmenu"

				if(viable_occupant && connected && connected.occupant==viable_occupant)
					viable_occupant.radiation += (RADIATION_IRRADIATION_MULTIPLIER*radduration*radstrength)/(connected.damage_coeff ** 2) //Read comment in "transferbuffer" section above for explanation
					switch(href_list["task"])                                                                                //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage
						if("pulseui")
							var/len = length(viable_occupant.dna.uni_identity)
							num = Wrap(num, 1, len+1)
							num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
                                                                                //Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
							var/block = round((num-1)/DNA_BLOCK_SIZE)+1
							var/subblock = num - block*DNA_BLOCK_SIZE
							last_change = "UI #[block]-[subblock]; "

							var/hex = copytext(viable_occupant.dna.uni_identity, num, num+1)
							last_change += "[hex]"
							hex = scramble(hex, radstrength, radduration)
							last_change += "->[hex]"

							viable_occupant.dna.uni_identity = copytext(viable_occupant.dna.uni_identity, 1, num) + hex + copytext(viable_occupant.dna.uni_identity, num+1, 0)
							updateappearance(viable_occupant)
						if("pulsese")
							var/len = length(viable_occupant.dna.struc_enzymes)
							num = Wrap(num, 1, len+1)
							num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len)

							var/block = round((num-1)/DNA_BLOCK_SIZE)+1
							var/subblock = num - block*DNA_BLOCK_SIZE
							last_change = "SE #[block]-[subblock]; "

							var/hex = copytext(viable_occupant.dna.struc_enzymes, num, num+1)
							last_change += "[hex]"
							hex = scramble(hex, radstrength, radduration)
							last_change += "->[hex]"

							viable_occupant.dna.struc_enzymes = copytext(viable_occupant.dna.struc_enzymes, 1, num) + hex + copytext(viable_occupant.dna.struc_enzymes, num+1, 0)
							domutcheck(viable_occupant)
				else
					current_screen = "mainmenu"

				if(connected)
					connected.locked = locked_state

	ShowInterface(usr,last_change)

/////////////////////////// DNA MACHINES
#undef INJECTOR_TIMEOUT
#undef REJUVENATORS_INJECT
#undef REJUVENATORS_MAX
#undef NUMBER_OF_BUFFERS

#undef RADIATION_STRENGTH_MAX
#undef RADIATION_STRENGTH_MULTIPLIER

#undef RADIATION_DURATION_MAX
#undef RADIATION_ACCURACY_MULTIPLIER

#undef RADIATION_IRRADIATION_MULTIPLIER

//#undef BAD_MUTATION_DIFFICULTY
//#undef GOOD_MUTATION_DIFFICULTY
//#undef OP_MUTATION_DIFFICULTY

//value in range 1 to values. values must be greater than 0
//all arguments assumed to be positive integers
proc/construct_block(value, values, blocksize=DNA_BLOCK_SIZE)
	var/width = round((16**blocksize)/values)
	if(value < 1)
		value = 1
	value = (value * width) - rand(1,width)
	return num2hex(value, blocksize)

//value is hex
proc/deconstruct_block(value, values, blocksize=DNA_BLOCK_SIZE)
	var/width = round((16**blocksize)/values)
	value = round(hex2num(value) / width) + 1
	if(value > values)
		value = values
	return value

/datum/dna/proc/is_same_as(var/datum/dna/D)
	if(uni_identity == D.uni_identity && struc_enzymes == D.struc_enzymes && real_name == D.real_name)
		if(species == D.species && mutant_color == D.mutant_color && blood_type == D.blood_type)
			return 1
	return 0


code:
/datum/game_mode
	var/list/datum/mind/abductors = list()

/datum/game_mode/abduction
	name = "Abduction"
	config_tag = "abduction"
	antag_flag = BE_ABDUCTOR
	recommended_enemies = 2
	required_players = 13
	var/max_teams = 4
	var/teams = 1
	var/list/datum/mind/scientists = list()
	var/list/datum/mind/agents = list()
	var/list/datum/objective/team_objectives = list()
	var/list/team_names = list()

/datum/game_mode/abduction/announce()
	world << "The current game mode is - Abduction!"

/datum/game_mode/abduction/pre_setup()
	teams = max(1, min(max_teams,round(num_players()/config.abductor_scaling_coeff)))
	var/possible_teams = max(1,round(antag_candidates.len / 2))
	teams = min(teams,possible_teams)

	abductors.len = 2*teams
	scientists.len = teams
	agents.len = teams
	team_objectives.len = teams
	team_names.len = teams

	for(var/i=1,i<=teams,i++)
		if(!make_abductor_team(i))
			return 0

	return 1

/datum/game_mode/abduction/proc/make_abductor_team(var/team_number,var/preset_agent=null,var/preset_scientist=null)
	//Team Name
	team_names[team_number] = "Mothership [pick(possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
	//Team Objective
	var/datum/objective/experiment/team_objective = new
	team_objective.team = team_number
	team_objectives[team_number] = team_objective
	//Team Members

	if(!preset_agent || !preset_scientist)
		if(antag_candidates.len <=2)
			return 0

	var/datum/mind/scientist
	var/datum/mind/agent

	if(!preset_scientist)
		scientist = pick(antag_candidates)
		antag_candidates -= scientist
	else
		scientist = preset_scientist

	if(!preset_agent)
		agent = pick(antag_candidates)
		antag_candidates -= agent
	else
		agent = preset_agent

	scientist.assigned_role = "MODE"
	scientist.special_role = "Abductor"
	log_game("[scientist.key] (ckey) has been selected as an abductor team [team_number] scientist.")

	agent.assigned_role = "MODE"
	agent.special_role = "Abductor"
	log_game("[agent.key] (ckey) has been selected as an abductor team [team_number] agent.")

	abductors |= agent
	abductors |= scientist
	scientists[team_number] = scientist
	agents[team_number] = agent
	return 1

/datum/game_mode/abduction/post_setup()
	//Spawn Team
	var/list/obj/effect/landmark/abductor/agent_landmarks = new
	var/list/obj/effect/landmark/abductor/scientist_landmarks = new
	agent_landmarks.len = max_teams
	scientist_landmarks.len = max_teams
	for(var/obj/effect/landmark/abductor/A in landmarks_list)
		if(istype(A,/obj/effect/landmark/abductor/agent))
			agent_landmarks[text2num(A.team)] = A
		else if(istype(A,/obj/effect/landmark/abductor/scientist))
			scientist_landmarks[text2num(A.team)] = A

	var/datum/mind/agent
	var/obj/effect/landmark/L
	var/datum/mind/scientist
	var/team_name
	var/mob/living/carbon/human/H
	var/datum/species/abductor/S
	for(var/team_number=1,team_number<=teams,team_number++)
		team_name = team_names[team_number]
		agent = agents[team_number]
		H = agent.current
		L = agent_landmarks[team_number]
		H.loc = L.loc
		hardset_dna(H, null, null, null, null, /datum/species/abductor)
		S = H.dna.species
		S.agent = 1
		S.abductor = 1
		S.team = team_number
		H.real_name = team_name + " Agent"
		equip_common(H,team_number)
		equip_agent(H,team_number)
		greet_agent(agent,team_number)
		H.regenerate_icons()

		scientist = scientists[team_number]
		H = scientist.current
		L = scientist_landmarks[team_number]
		H.loc = L.loc
		hardset_dna(H, null, null, null, null, /datum/species/abductor)
		S = H.dna.species
		S.scientist = 1
		S.abductor = 1
		S.team = team_number
		H.real_name = team_name + " Scientist"
		equip_common(H,team_number)
		equip_scientist(H,team_number)
		greet_scientist(scientist,team_number)
		H.regenerate_icons()
	return ..()

//Used for create antag buttons
/datum/game_mode/abduction/proc/post_setup_team(var/team_number)
	var/list/obj/effect/landmark/abductor/agent_landmarks = new
	var/list/obj/effect/landmark/abductor/scientist_landmarks = new
	agent_landmarks.len = max_teams
	scientist_landmarks.len = max_teams
	for(var/obj/effect/landmark/abductor/A in landmarks_list)
		if(istype(A,/obj/effect/landmark/abductor/agent))
			agent_landmarks[text2num(A.team)] = A
		else if(istype(A,/obj/effect/landmark/abductor/scientist))
			scientist_landmarks[text2num(A.team)] = A

	var/datum/mind/agent
	var/obj/effect/landmark/L
	var/datum/mind/scientist
	var/team_name
	var/mob/living/carbon/human/H
	var/datum/species/abductor/S

	team_name = team_names[team_number]
	agent = agents[team_number]
	H = agent.current
	L = agent_landmarks[team_number]
	H.loc = L.loc
	hardset_dna(H, null, null, null, null, /datum/species/abductor)
	S = H.dna.species
	S.agent = 1
	S.abductor = 1
	S.team = team_number
	H.real_name = team_name + " Agent"
	equip_common(H,team_number)
	equip_agent(H,team_number)
	greet_agent(agent,team_number)
	H.regenerate_icons()

	scientist = scientists[team_number]
	H = scientist.current
	L = scientist_landmarks[team_number]
	H.loc = L.loc
	hardset_dna(H, null, null, null, null, /datum/species/abductor)
	S = H.dna.species
	S.scientist = 1
	S.abductor = 1
	S.team = team_number
	H.real_name = team_name + " Scientist"
	equip_common(H,team_number)
	equip_scientist(H,team_number)
	greet_scientist(scientist,team_number)
	H.regenerate_icons()

/datum/game_mode/abduction/proc/greet_agent(var/datum/mind/abductor,var/team_number)
	abductor.objectives += team_objectives[team_number]
	var/team_name = team_names[team_number]

	abductor.current << "You are an Abductor Agent of [team_name]!"
	abductor.current << "With the help of your teammate kidnap and experiment on station members!"
	abductor.current << "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."

	var/obj_count = 1
	for(var/datum/objective/objective in abductor.objectives)
		abductor.current << "Objective #[obj_count]: [objective.explanation_text]"
		obj_count++
	return

/datum/game_mode/abduction/proc/greet_scientist(var/datum/mind/abductor,var/team_number)
	abductor.objectives += team_objectives[team_number]
	var/team_name = team_names[team_number]

	abductor.current << "You are an Abductor Scientist of [team_name]!"
	abductor.current << "With the help of your teammate kidnap and experiment on station members!"
	abductor.current << "Use your tool and ship consoles to support the agent and retrieve human specimens."

	var/obj_count = 1
	for(var/datum/objective/objective in abductor.objectives)
		abductor.current << "Objective #[obj_count]: [objective.explanation_text]"
		obj_count++
	return

/datum/game_mode/abduction/proc/equip_common(var/mob/living/carbon/human/agent,var/team_number)
	var/radio_freq = SYND_FREQ

	var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate/alt(agent)
	R.set_frequency(radio_freq)
	agent.equip_to_slot_or_del(R, slot_ears)
	agent.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(agent), slot_shoes)
	agent.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(agent), slot_w_uniform) //they're greys gettit
	agent.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(agent), slot_back)

/datum/game_mode/abduction/proc/get_team_console(var/team)
	var/obj/machinery/abductor/console/console
	for(var/obj/machinery/abductor/console/c in machines)
		if(c.team == team)
			console = c
			break
	return console

/datum/game_mode/abduction/proc/equip_agent(var/mob/living/carbon/human/agent,var/team_number)
	var/obj/machinery/abductor/console/console = get_team_console(team_number)
	var/obj/item/clothing/suit/armor/abductor/vest/V = new /obj/item/clothing/suit/armor/abductor/vest(agent)
	if(console!=null)
		console.vest = V
		V.flags |= NODROP
	agent.equip_to_slot_or_del(V, slot_wear_suit)
	agent.equip_to_slot_or_del(new /obj/item/weapon/abductor_baton(agent), slot_in_backpack)
	agent.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/decloner/alien(agent), slot_belt)
	agent.equip_to_slot_or_del(new /obj/item/device/abductor/silencer(agent), slot_in_backpack)
	agent.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/abductor(agent), slot_head)

/datum/game_mode/abduction/proc/equip_scientist(var/mob/living/carbon/human/scientist,var/team_number)
	var/obj/machinery/abductor/console/console = get_team_console(team_number)
	var/obj/item/device/abductor/gizmo/G = new /obj/item/device/abductor/gizmo(scientist)
	if(console!=null)
		console.gizmo = G
		G.console = console
	scientist.equip_to_slot_or_del(G, slot_in_backpack)

	var/obj/item/weapon/implant/abductor/beamplant = new /obj/item/weapon/implant/abductor(scientist)
	beamplant.imp_in = scientist
	beamplant.implanted = 1
	beamplant.implanted(scientist)
	beamplant.home = console.pad

/datum/game_mode/abduction/check_finished()
	var/all_dead = 1
	for(var/team_number=1,team_number<=teams,team_number++)
		var/datum/mind/smind = scientists[team_number]
		if(smind.current)
			var/mob/living/M = smind.current
			if(M.stat != DEAD)
				all_dead = 0
		var/obj/machinery/abductor/console/con = get_team_console(team_number)
		var/datum/objective/objective = team_objectives[team_number]
		if (con.experiment.points > objective.target_amount)
			return 1
	if(all_dead)
		return 1
	return ..()

/datum/game_mode/abduction/declare_completion()
	for(var/team_number=1,team_number<=teams,team_number++)
		var/obj/machinery/abductor/console/console = get_team_console(team_number)
		var/datum/objective/objective = team_objectives[team_number]
		var/team_name = team_names[team_number]
		var/datum/mind/amind = agents[team_number]
		var/datum/mind/smind = scientists[team_number]
		var/mob/living/carbon/human/agent = amind.current
		var/mob/living/carbon/human/scientist = smind.current
		if (console.experiment.points > objective.target_amount)
			world << "[team_name] team fullfilled its mission! "
			world << "Team Members : [agent.name]([agent.ckey]),[scientist.name]([scientist.ckey])"
		else
			world << "[team_name] team failed its mission! "
			world << "Team Members: [agent.name]([agent.ckey])
[scientist.name]([scientist.ckey])"

		world << "Abductees:"
		display_abductees(console)

	..()
	return 1

/datum/game_mode/abduction/proc/display_abductees(var/obj/machinery/abductor/console/console)
	var/list/mob/living/abductees = console.experiment.history
	for(var/mob/living/abductee in abductees)
		if(!abductee.mind)
			continue
		world << "[abductee.name]([abductee.ckey]))"
		var/count = 1
		for(var/datum/objective/objective in abductee.mind.objectives)
			if(objective.check_completion())
				world << "
Objective #[count]: [objective.explanation_text] Success!"
			else
				world << "
Objective #[count]: [objective.explanation_text] Fail."
			count++

/datum/game_mode/proc/auto_declare_completion_abduction()
	if(abductors.len)
		world << "Abductors:"
		for(var/datum/mind/M in abductors)
			world << "Abductor [M.current ? M.current.name : "Abductor"]([M.key])"
	return

//Landmarks
// TODO: Split into seperate landmarks for prettier ships
/obj/effect/landmark/abductor
	var/team = 1

/obj/effect/landmark/abductor/console/New()
	var/obj/machinery/abductor/console/c = new /obj/machinery/abductor/console(src.loc)
	c.team = team

	spawn(5) // I'd do this properly when i got some time, temporary hack for mappers
		c.Initialize()
	qdel(src)

/obj/effect/landmark/abductor/agent
/obj/effect/landmark/abductor/scientist

// OBJECTIVES
datum/objective/experiment
	dangerrating = 10
	target_amount = 6
	var/team

datum/objective/experiment/New()
	explanation_text = "Experiment on [target_amount] humans"

datum/objective/experiment/check_completion()
	return 0

datum/objective/abductee
	dangerrating = 5
	completed = 1

datum/objective/abductee/steal
	explanation_text = "Steal all"

datum/objective/abductee/steal/New()
	var/target = pick(list("Pets","Lights","Monkeys","Fruits","Shoes","Soap Bars"))
	explanation_text+=" [target]"

datum/objective/abductee/capture
	explanation_text = "Capture"

datum/objective/abductee/capture/New()
	var/list/jobs = SSjob.occupations
	for(var/datum/job/J in jobs)
		if(J.current_positions < 1)
			jobs -= J
	if(jobs.len > 0)
		var/datum/job/target = pick(jobs)
		explanation_text += " \a [target.title]."
	else
		explanation_text += " someone."

datum/objective/abductee/shuttle
	explanation_text = "You must escape the station! Get the shuttle called!"

datum/objective/abductee/noclone
	explanation_text = "Don't allow anyone to be cloned."

license: mit


code:
#define VEST_STEALTH 1
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2

//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
	name = "Agent Vest"
	desc = "Vest outfitted with alien stealth technology."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "vest_stealth"
	item_state = "armor"
	blood_overlay_type = "armor"
	origin_tech = "materials=5;biotech=4;powerstorage=5"
	armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
	action_button_name = "Activate"
	action_button_is_hands_free = 1
	unacidable = 1
	var/mode = VEST_STEALTH
	var/stealth_active = 0
	var/combat_cooldown = 10
	var/datum/icon_snapshot/disguise
	var/stealth_armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15)
	var/combat_armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 50, bio = 50, rad = 50)

/obj/item/clothing/suit/armor/abductor/vest/proc/flip_mode()
	switch(mode)
		if(VEST_STEALTH)
			mode = VEST_COMBAT
			DeactivateStealth()
			armor = combat_armor
			icon_state = "vest_combat"
			if(istype(loc, /mob/living/carbon/human))
				var/mob/living/carbon/human/H = loc
				H.update_inv_wear_suit()
			return
		if(VEST_COMBAT)// TO STEALTH
			mode = VEST_STEALTH
			armor = stealth_armor
			icon_state = "vest_stealth"
			if(istype(loc, /mob/living/carbon/human))
				var/mob/living/carbon/human/H = loc
				H.update_inv_wear_suit()
			ActivateStealth()
			return

/obj/item/clothing/suit/armor/abductor/vest/proc/SetDisguise(var/datum/icon_snapshot/entry)
	disguise = entry
	ActivateStealth()

/obj/item/clothing/suit/armor/abductor/vest/proc/ActivateStealth()
	if(disguise == null)
		return
	stealth_active = 1
	if(istype(src.loc, /mob/living/carbon/human))
		var/mob/living/carbon/human/M = src.loc
		spawn(0)
			anim(M.loc,M,'icons/mob/mob.dmi',,"cloak",,M.dir)

		M.name_override = disguise.name
		M.icon = disguise.icon
		M.icon_state = disguise.icon_state
		M.overlays = disguise.overlays
		M.update_inv_r_hand()
		M.update_inv_l_hand()
	return

/obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth()
	if(!stealth_active)
		return
	stealth_active = 0
	if(istype(src.loc, /mob/living/carbon/human))
		var/mob/living/carbon/human/M = src.loc
		spawn(0)
			anim(M.loc,M,'icons/mob/mob.dmi',,"uncloak",,M.dir)
		M.name_override = null
		M.overlays.Cut()
		M.regenerate_icons()
	return

/obj/item/clothing/suit/armor/abductor/vest/IsShield()
	DeactivateStealth()
	return 0
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
	DeactivateStealth()
	return 0

/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
	switch(mode)
		if(VEST_COMBAT)
			Adrenaline()
		if(VEST_STEALTH)
			if(stealth_active)
				DeactivateStealth()
			else
				ActivateStealth()

/obj/item/clothing/suit/armor/abductor/vest/proc/Adrenaline()
	if(istype(src.loc, /mob/living/carbon/human))
		if(combat_cooldown != initial(combat_cooldown))
			src.loc << "Combat injection is still recharging."
		var/mob/living/carbon/human/M = src.loc
		M.stat = 0
		M.SetParalysis(0)
		M.SetStunned(0)
		M.SetWeakened(0)
		M.lying = 0
		M.update_canmove()
		M.adjustStaminaLoss(-75)
		combat_cooldown = 0
		SSobj.processing |= src

/obj/item/clothing/suit/armor/abductor/vest/process()
	combat_cooldown++
	if(combat_cooldown==initial(combat_cooldown))
		SSobj.processing.Remove(src)

/obj/item/device/abductor/proc/IsAbductor(var/user)
	if(ishuman(user))
		var/mob/living/carbon/human/H = user
		if(H.dna.species.id != "abductor")
			return 0
		return 1
	return 0

/obj/item/device/abductor/proc/AbductorCheck(var/user)
	if(IsAbductor(user))
		return 1
	user << "You can't figure how this works."
	return 0

/obj/item/device/abductor/proc/ScientistCheck(var/user)
	var/mob/living/carbon/human/H = user
	var/datum/species/abductor/S = H.dna.species
	return S.scientist

/obj/item/device/abductor/gizmo
	name = "Science Tool"
	desc = "Alien science is 90% dissections 10% probings."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "gizmo_scan"
	item_state = "silencer"
	origin_tech = "materials=5;magnets=5;bluespace=6"
	var/mode = GIZMO_SCAN
	var/mob/living/marked = null
	var/obj/machinery/abductor/console/console
	unacidable = 1

/obj/item/device/abductor/gizmo/attack_self(mob/user)
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this"
		return
	if(mode == GIZMO_SCAN)
		mode = GIZMO_MARK
		icon_state = "gizmo_mark"
	else
		mode = GIZMO_SCAN
		icon_state = "gizmo_scan"
	user << "You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE"

/obj/item/device/abductor/gizmo/attack(mob/living/M, mob/user)
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this"
		return
	switch(mode)
		if(GIZMO_SCAN)
			scan(M, user)
		if(GIZMO_MARK)
			mark(M, user)

/obj/item/device/abductor/gizmo/afterattack(var/atom/target, var/mob/living/user, flag, params)
	if(flag)
		return
	if(!AbductorCheck(user))
		return
	if(!ScientistCheck(user))
		user << "You're not trained to use this"
		return
	switch(mode)
		if(GIZMO_SCAN)
			scan(target, user)
		if(GIZMO_MARK)
			mark(target, user)

/obj/item/device/abductor/gizmo/proc/scan(var/atom/target, var/mob/living/user)
	if(istype(target,/mob/living/carbon/human))
		if(console!=null)
			console.AddSnapshot(target)
			user << "You scan and add the being to the database"

/obj/item/device/abductor/gizmo/proc/mark(var/atom/target, var/mob/living/user)
	if(marked == target)
		user << "This specimen is already marked."
		return
	if(istype(target,/mob/living/carbon/human))
		if(IsAbductor(target))
			marked = target
			user << "You mark the target for future retrieval."
		else
			prepare(target,user)

/obj/item/device/abductor/gizmo/proc/prepare(var/atom/target, var/mob/living/user)
	if(get_dist(target,user)>1)
		user << "You need to be next to the specimen to prepare it for transport."
		return
	user << "You start preparing the specimen for transport "
	if(do_after(user, 100))
		marked = target
		user << "You finish preparing the specimen for transport "

/obj/item/device/abductor/silencer
	name = "Abductor Silencer"
	desc = "Device used to break communication equipment"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "silencer"
	item_state = "gizmo"
	unacidable = 1

/obj/item/device/abductor/silencer/attack(mob/living/M, mob/user)
	if(!AbductorCheck(user))
		return
	radio_off(M, user)

/obj/item/device/abductor/silencer/afterattack(var/atom/target, var/mob/living/user, flag, params)
	if(flag)
		return
	if(!AbductorCheck(user))
		return
	radio_off(target, user)

/obj/item/device/abductor/silencer/proc/radio_off(var/atom/target, var/mob/living/user)
	if( !(user in (viewers(7,target))) )
		return

	var/turf/targloc = get_turf(target)

	var/mob/living/carbon/human/M
	for(M in view(2,targloc))
		user << "You silence [M.name] radio devices."
		radio_off_mob(M)

/obj/item/device/abductor/silencer/proc/radio_off_mob(var/mob/living/carbon/human/M)
	var/list/all_items = M.GetAllContents()

	for(var/obj/I in all_items)
		if(istype(I,/obj/item/device/radio/))
			var/obj/item/device/radio/r = I
			r.listening = 0
			if(!istype(I,/obj/item/device/radio/headset))
				r.broadcasting = 0 //goddamned headset hacks

/obj/item/weapon/implant/abductor
	name = "Emergency Beam"
	desc = "Gets you back on the ship."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "implant"
	activated = 1
	var/obj/machinery/abductor/pad/home
	var/cooldown = 30

/obj/item/weapon/implant/abductor/activate()
	if(cooldown == initial(cooldown))
		home.Retrieve(imp_in,1)
		cooldown = 0
		SSobj.processing |= src
	else
		imp_in << "The emergency beam is still recharging!"
	return

/obj/item/weapon/implant/abductor/process()
	if(cooldown < initial(cooldown))
		cooldown++
		if(cooldown == initial(cooldown))
			SSobj.processing.Remove(src)

/obj/item/device/firing_pin/alien
	name = "alien-looking pin"
	desc = "Only non-humans can use this pin"

/obj/item/device/firing_pin/alien/pin_auth(mob/living/user)
	if(ishuman(user))
		var/mob/living/carbon/human/H = user
		if(H.dna.species.id == "human") //stealth lizard buff go
			return 0
	return 1

/obj/item/weapon/gun/energy/decloner/alien
	ammo_type = list(/obj/item/ammo_casing/energy/declone)
	pin = /obj/item/device/firing_pin/alien
	unacidable = 1
	icon_state = "decloner"
	item_state = "gun"

/obj/item/weapon/gun/energy/decloner/alien/update_icon() // No charge levels
	return

/obj/item/weapon/paper/abductor
	name = "Dissection Guide"
	info = {"Dissection for Dummies

 1.Acquire fresh specimen.

 2.Put the specimen on operating table

 3.Apply surgical drapes preparing for dissection

 4.Apply scalpel to specimen torso

 5.Stop the bleeders and retract skin

 6.Cut out organs you find with a scalpel

 7.Use your hands to remove the remaining organs

 8.Insert replacement gland (Retrieve one from gland storage)

 9.Consider dressing the specimen back to not disturb the habitat

 10.Put the specimen in the experiment machinery

 11.Choose one of the machine options and follow displayed instructions

Congratulations! You are now trained for xenobiology research!"}

#define BATON_STUN 0
#define BATON_SLEEP 1
#define BATON_CUFF 2
#define BATON_PROBE 3
#define BATON_MODES 4

/obj/item/weapon/abductor_baton
	name = "Advanced Baton"
	var/mode = BATON_STUN
	icon = 'icons/obj/abductor.dmi'
	icon_state = "wonderprod"
	item_state = "wonderprod"
	slot_flags = SLOT_BELT
	origin_tech = "materials=6;combat=5;biotech=7"
	force = 7
	unacidable = 1
	w_class = 3
	action_button_name = "Toggle Mode"

/obj/item/weapon/abductor_baton/proc/toggle(mob/living/user=usr)
	mode = (mode+1)%BATON_MODES
	var/txt
	switch(mode)
		if(BATON_STUN)
			txt = "stun"
		if(BATON_SLEEP)
			txt = "sleep inducment"
		if(BATON_CUFF)
			txt = "restraining"
		if(BATON_PROBE)
			txt = "probing"

	usr << "You switch the baton to [txt] mode"
	update_icon()

/obj/item/weapon/abductor_baton/update_icon()
	switch(mode)
		if(BATON_STUN)
			icon_state = "wonderprod"
		if(BATON_SLEEP)
			icon_state = "wonderprod"
		if(BATON_CUFF)
			icon_state = "wonderprod"
		if(BATON_PROBE)
			icon_state = "wonderprod"

/obj/item/weapon/abductor_baton/proc/IsAbductor(var/mob/living/user)
	if(!ishuman(user))
		return 0
	var/mob/living/carbon/human/H = user
	if(!H.dna)
		return 0
	if(H.dna.species.id != "abductor")
		return 0
	return 1

/obj/item/weapon/abductor_baton/attack(mob/target as mob, mob/living/user as mob)
	if(!IsAbductor(user))
		return

	if(isrobot(target))
		..()
		return

	if(!isliving(target))
		return

	var/mob/living/L = target

	user.do_attack_animation(L)
	switch(mode)
		if(BATON_STUN)
			StunAttack(L,user)
		if(BATON_SLEEP)
			SleepAttack(L,user)
		if(BATON_CUFF)
			CuffAttack(L,user)
		if(BATON_PROBE)
			ProbeAttack(L,user)

/obj/item/weapon/abductor_baton/attack_self(mob/living/user)
	toggle(user)

/obj/item/weapon/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
	user.lastattacked = L
	L.lastattacker = user

	L.Stun(7)
	L.Weaken(7)
	L.apply_effect(STUTTER, 7)

	L.visible_message("[user] has stunned [L] with [src]!", \
							"[user] has stunned you with [src]!")
	playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)

	if(ishuman(L))
		var/mob/living/carbon/human/H = L
		H.forcesay(hit_appends)

	add_logs(user, L, "stunned")
	return

/obj/item/weapon/abductor_baton/proc/SleepAttack(mob/living/L,mob/living/user)
	if(L.stunned)
		L.SetSleeping(60)
		L.visible_message("[user] has induced sleep in [L] with [src]!", \
							"You suddenly feel very drowsy!")
		playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)

		add_logs(user, L, "put to sleep")
	else
		user << "[L] must be stunned for the sleep induction to work!"
	return

/obj/item/weapon/abductor_baton/proc/CuffAttack(mob/living/L,mob/living/user)
	if(!iscarbon(L))
		return
	var/mob/living/carbon/C = L
	if(!C.handcuffed)
		playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
		C.visible_message("[user] is trying to put energy cuffs on [C]!", \
								"[user] is trying to put energy cuffs on [C]!")
		if(do_mob(user, C, 30))
			if(!C.handcuffed)
				C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/used(C)
				C.update_inv_handcuffed(0)
				user << "You handcuff [C]."
				add_logs(user, C, "handcuffed")
		else
			user << "You fail to handcuff [C]."
	return

/obj/item/weapon/abductor_baton/proc/ProbeAttack(mob/living/L,mob/living/user)
	L.visible_message("[user] probes [L] with [src]!", \
						"[user] probed [L]!")

	var/species = "Unknown Species"
	if(ishuman(L))
		var/mob/living/carbon/human/H = L
		if(H.dna && H.dna.species)
			species = "[H.dna.species.name]"
		if(L.mind && L.mind.changeling)
			species = "Changeling Lifeform"
	user << "Probing Result:[species]"

/obj/item/weapon/restraints/handcuffs/energy
	name = "energy cuffs"
	desc = "Energy field restraining the hands."
	icon_state = "cuff_white" // Needs sprite
	breakouttime = 450
	unacidable = 1
	trashtype = /obj/item/weapon/restraints/handcuffs/energy/used

/obj/item/weapon/restraints/handcuffs/energy/used
	desc = "Energy Discharge"

/obj/item/weapon/restraints/handcuffs/energy/used/dropped(mob/user)
	user.visible_message("[user] cuffs break in a discharge of energy!", \
							"[user] cuffs break in a discharge of energy!")
	var/datum/effect/effect/system/spark_spread/S = new
	S.set_up(4,0,user.loc)
	S.start()
	qdel(src)

/obj/item/weapon/abductor_baton/examine(mob/user)
	..()
	switch(mode)
		if(BATON_STUN)
			user <<"The baton is in stun mode."
		if(BATON_SLEEP)
			user <<"The baton is in sleep induction mode."
		if(BATON_CUFF)
			user <<"The baton is in restrain mode."
		if(BATON_PROBE)
			user <<"The baton is in probing mode."

/obj/item/weapon/scalpel/alien
	name = "alien scalpel"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/weapon/hemostat/alien
	name = "alien hemostat"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/weapon/retractor/alien
	name = "alien retractor"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/weapon/circular_saw/alien
	name = "alien saw"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/weapon/surgicaldrill/alien
	name = "alien drill"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/weapon/cautery/alien
	name = "alien cautery"
	icon = 'icons/obj/abductor.dmi'
	unacidable = 1

/obj/item/clothing/head/helmet/abductor
	name = "Agent Headgear"
	desc = "Abducting with style. Spiky style."
	icon_state = "alienhelmet"
	item_state = "alienhelmet"
	unacidable = 1
	blockTracking = 1
	origin_tech = "materials=6;magnets=5"

/obj/structure/optable/abductor
	icon = 'icons/obj/abductor.dmi'
	icon_state = "bed"
	can_buckle = 1
	buckle_lying = 1

/obj/structure/stool/bed/abductor //Doesn't this already exist somewhere else?
	name = "resting contraption"
	desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?"
	icon_state = "abed" //Until pillows get added I guess

/obj/structure/table/abductor
	name = "alien table"
	desc = "Advanced flat surface technology at work!"
	icon_state = "alientable"

/obj/structure/closet/abductor
	name = "alien locker"
	desc = "Contains secrets of the universe"
	icon_state = "abductor"
	icon_door = "abductor"


code:
/datum/surgery/organ_extraction
	name = "experimental dissection"
	steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin,/datum/surgery_step/incise, /datum/surgery_step/extract_organ ,/datum/surgery_step/gland_insert)
	species = list(/mob/living/carbon/human)
	location = "chest"
	user_species_restricted = 1
	user_species_ids = list("abductor")
	ignore_clothes = 1

/datum/surgery_step/extract_organ
	accept_hand = 1
	time = 32
	var/obj/item/IC = null
	var/list/organ_types = list(/obj/item/organ/heart)

/datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	for(var/obj/item/I in target.internal_organs)
		if(I.type in organ_types)
			IC = I
			break
	user.visible_message("[user] starts to remove [target]'s organs.")

/datum/surgery_step/extract_organ/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	if(IC)
		user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!")
		user.put_in_hands(IC)
		target.internal_organs -= IC
		return 1
	else
		user.visible_message("[user] doesn't find anything in [target]'s [target_zone].")
		return 0

/datum/surgery_step/gland_insert
	implements = list(/obj/item/gland = 100)
	time = 32

/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	user.visible_message("[user] starts to insert [tool] into [target].")

/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
	user.visible_message("[user] inserts [tool] into [target].")
	user.drop_item()
	var/obj/item/gland/gland = tool
	gland.Inject(target)
	return 1


code:
/obj/item/gland/
	name = "Fleshy mass"
	desc = "Eww"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "gland"
	var/cooldown_low = 30
	var/cooldown_high = 30
	var/cooldown_current = 0
	var/cooldown = 0
	var/uses // -1 For inifinite
	var/active = 0
	var/mob/living/carbon/human/host

/obj/item/gland/proc/HostCheck()
	if(ishuman(host) && host == src.loc)
		if(host.stat != DEAD)
			return 1
	return 0

/obj/item/gland/proc/Start()
	active = 1
	SSobj.processing |= src

/obj/item/gland/proc/Inject(var/mob/living/carbon/human/target)
	host = target
	target.internal_organs += src
	src.loc = target

/obj/item/gland/process()
	if(!active)
		SSobj.processing.Remove(src)
		return
	cooldown++
	if(cooldown >= cooldown_current)
		//This gives a chance to transplant the gland active into someone else if you're fast
		if(!HostCheck())
			active = 0
			return
		activate()
		uses--
		cooldown = 0
		cooldown_current = rand(cooldown_low,cooldown_high)
	if(uses == 0)
	 active = 0

/obj/item/gland/proc/activate()
	return

/obj/item/gland/heals
	cooldown_low = 20
	cooldown_high = 40
	uses = -1
	icon_state = "health"

obj/item/gland/heals/activate()
	host << "You feel weird."
	host.adjustBruteLoss(-20)
	host.adjustOxyLoss(-20)
	host.adjustFireLoss(-20)

/obj/item/gland/mindshock
	cooldown_low = 30
	cooldown_high = 30
	uses = -1
	icon_state = "mindshock"

/obj/item/gland/mindshock/activate()
	host << "You feel weird."

	var/turf/T = get_turf(host)
	for(var/mob/living/carbon/human/H in orange(4,T))
		if(H == host)
			continue
		H << " You hear a buzz in your head "
		H.confused += 20

/obj/item/gland/pop
	cooldown_low = 120
	cooldown_high = 180
	uses = 5
	icon_state = "species"

/obj/item/gland/pop/activate()
	host << "You feel weird."
	var/species = pick(list(/datum/species/lizard,/datum/species/slime,/datum/species/plant/pod,/datum/species/fly))
	hardset_dna(host, null, null, null, null, species)
	host.regenerate_icons()
	return

/obj/item/gland/ventcrawling
	cooldown_low = 180
	cooldown_high = 240
	uses = 1
	icon_state = "vent"

/obj/item/gland/ventcrawling/activate()
	host << "You feel weird."
	host << "You feel very stretchy."
	host.ventcrawler = 2
	return

/obj/item/gland/viral
	cooldown_low = 180
	cooldown_high = 240
	uses = 1
	icon_state = "viral"

/obj/item/gland/viral/activate()
	var/virus_type = pick(/datum/disease/beesease, /datum/disease/brainrot, /datum/disease/magnitis)
	var/datum/disease/D = new virus_type()
	D.carrier = 1
	host.viruses += D
	D.affected_mob = host
	D.holder = host
	host.med_hud_set_status()

/obj/item/gland/emp //TODO : Replace with something more interesting
	cooldown_low = 90
	cooldown_high = 160
	uses = 5
	icon_state = "emp"

/obj/item/gland/emp/activate()
	empulse(get_turf(host), 2, 5, 1)

/obj/item/gland/spiderman
	cooldown_low = 90
	cooldown_high = 160
	uses = 10
	icon_state = "spider"

/obj/item/gland/spiderman/activate()
	if(uses == initial(uses))
		host.faction += "spiders"
	new /obj/effect/spider/spiderling(host.loc)

/obj/item/gland/egg
	cooldown_low = 60
	cooldown_high = 90
	uses = -1
	icon_state = "egg"

/obj/item/gland/egg/activate()
	var/obj/item/weapon/reagent_containers/food/snacks/egg/egg = new(host.loc)
	egg.reagents.add_reagent("sacid",20)
	egg.desc += " It smells bad."

/obj/item/gland/bloody
	cooldown_low = 200
	cooldown_high = 400
	uses = -1

/obj/item/gland/bloody/activate()
	host.adjustBruteLoss(15)

	host.visible_message("[host] skin erupts with blood!",\
	"Your skin erupts with blood! It hurts!")

	for(var/turf/T in oview(3,host)) //Make this respect walls and such
		T.add_blood_floor(host)
	for(var/mob/living/carbon/human/H in oview(3,host)) //Blood decals for simple animals would be neat. aka Carp with blood on it.
		if(H.wear_suit)
			H.wear_suit.add_blood(host)
			H.update_inv_wear_suit(0)
		else if(H.w_uniform)
			H.w_uniform.add_blood(host)
			H.update_inv_w_uniform(0)

/obj/item/gland/bodysnatch
	cooldown_low = 600
	cooldown_high = 600
	uses = 1

/obj/item/gland/bodysnatch/activate()
	//spawn cocoon with clone greytide snpc inside
	var/obj/effect/cocoon/abductor/C = new (get_turf(host))
	C.Copy(host)
	C.Start()
	host.gib()
	return

/obj/effect/cocoon/abductor
	name = "Slimy cocoon"
	desc = "You can see something moving inside"
	icon = 'icons/effects/effects.dmi'
	icon_state = "cocoon_large3"
	color = rgb(10,120,10)
	density = 1
	var/hatch_time = 0

/obj/effect/cocoon/abductor/proc/Copy(var/mob/living/carbon/human/H)
	var/mob/living/carbon/human/interactive/greytide/clone = new(src)
	hardset_dna(clone,H.dna.uni_identity,H.dna.struc_enzymes,H.real_name, H.dna.blood_type, H.dna.species.type, H.dna.mutant_color)

	//There's no define for this / get all items ?
	var/list/slots = list(slot_back,slot_w_uniform,slot_wear_suit,\
	slot_wear_mask,slot_head,slot_shoes,slot_gloves,slot_ears,\
	slot_glasses,slot_belt,slot_s_store,slot_l_store,slot_r_store,slot_wear_id)

	for(var/slot in slots)
		var/obj/item/I = H.get_item_by_slot(slot)
		if(I)
			clone.equip_to_slot_if_possible(I,slot)

/obj/effect/cocoon/abductor/proc/Start()
	hatch_time = world.time + 600
	SSobj.processing |= src

/obj/effect/cocoon/abductor/process()
	if(world.time > hatch_time)
		SSobj.processing.Remove(src)
		for(var/mob/M in contents)
			src.visible_message("[src] hatches!")
			M.loc = src.loc
		qdel(src)

/obj/item/gland/plasma
	cooldown_low = 1200
	cooldown_high = 2400
	uses = 1

/obj/item/gland/plasma/activate()
	host << "You feel bloated."
	sleep(150)
	host << "Your stomach feels about to explode!"
	sleep(50)
	host.visible_message("[host] explodes in a cloud of plasma!")
	var/turf/simulated/T = get_turf(host)
	if(istype(T))
		T.atmos_spawn_air(SPAWN_TOXINS|SPAWN_20C,6665)
	host.gib()
	return


code:
/obj/machinery/computer/camera_advanced/abductor
	name = "Human Observation Console"
	var/team = 0
	networks = list("SS13","Abductor")
	off_action = new/datum/action/camera_off/abductor //specific datum
	var/datum/action/teleport_in/tele_in_action = new
	var/datum/action/teleport_out/tele_out_action = new
	var/datum/action/teleport_self/tele_self_action = new
	var/datum/action/vest_mode_swap/vest_mode_action = new
	var/datum/action/vest_disguise_swap/vest_disguise_action = new
	var/obj/machinery/abductor/console/console

	icon = 'icons/obj/abductor.dmi'
	icon_state = "camera"

/obj/machinery/computer/camera_advanced/abductor/CreateEye()
	..()
	eyeobj.visible_icon = 1
	eyeobj.icon = 'icons/obj/abductor.dmi'
	eyeobj.icon_state = "camera_target"

/obj/machinery/computer/camera_advanced/abductor/GrantActions(var/mob/living/carbon/user)
	off_action.target = user
	off_action.holder = src
	off_action.Grant(user)

	jump_action.target = user
	jump_action.holder = src
	jump_action.Grant(user)
	//TODO : add null checks
	if(console)
		if (console.pad)
			tele_in_action.target = console.pad
			tele_in_action.holder = src
			tele_in_action.Grant(user)

			tele_out_action.target = console
			tele_out_action.holder = src
			tele_out_action.Grant(user)

			tele_self_action.target = console.pad
			tele_self_action.holder = src
			tele_self_action.Grant(user)

		vest_mode_action.target = console
		vest_mode_action.holder = src
		vest_mode_action.Grant(user)

		vest_disguise_action.target = console
		vest_disguise_action.holder = src
		vest_disguise_action.Grant(user)

/obj/machinery/computer/camera_advanced/abductor/proc/IsAbductor(var/mob/living/carbon/human/H)
	return H.dna.species.id == "abductor"

/obj/machinery/computer/camera_advanced/abductor/proc/IsScientist(var/mob/living/carbon/human/H)
	var/datum/species/abductor/S = H.dna.species
	return S.scientist

/obj/machinery/computer/camera_advanced/abductor/attack_hand(var/mob/user as mob)
	if(!iscarbon(user) || !IsAbductor(user))
		return
	return ..()

/datum/action/camera_off/abductor/Activate()
	if(!target || !iscarbon(target))
		return
	var/mob/living/carbon/C = target
	var/obj/machinery/computer/camera_advanced/abductor/origin = holder
	if (!C.remote_control)
		C.remote_control = origin.eyeobj
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	C.remote_view = 0
	origin.current_user = null
	origin.jump_action.Remove(C)
	origin.tele_in_action.Remove(C)
	origin.tele_out_action.Remove(C)
	origin.tele_self_action.Remove(C)
	origin.vest_mode_action.Remove(C)
	origin.vest_disguise_action.Remove(C)
	if(C.client)
		C.client.perspective = MOB_PERSPECTIVE
		C.client.eye = src
		if(remote_eye)
			C.client.images -= remote_eye.user_image
	C.remote_control = null
	C.unset_machine()
	src.Remove(C)

/datum/action/teleport_in
	name = "Send To"
	action_type = AB_INNATE
	button_icon_state = "beam_down"

/datum/action/teleport_in/Activate()
	if(!target || !iscarbon(owner))
		return
	var/mob/living/carbon/human/C = owner
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	var/obj/machinery/abductor/pad/P = target

	if(cameranet.checkTurfVis(remote_eye.loc))
		P.PadToLoc(remote_eye.loc)

/datum/action/teleport_out
	name = "Retrieve"
	action_type = AB_INNATE
	button_icon_state = "beam_up"

/datum/action/teleport_out/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target

	console.TeleporterRetrieve()

/datum/action/teleport_self
	name = "Send Self"
	action_type = AB_INNATE
	button_icon_state = "beam_down"

/datum/action/teleport_self/Activate()
	if(!target || !iscarbon(owner))
		return
	var/mob/living/carbon/human/C = owner
	var/mob/camera/aiEye/remote/remote_eye = C.remote_control
	var/obj/machinery/abductor/pad/P = target

	if(cameranet.checkTurfVis(remote_eye.loc))
		P.MobToLoc(remote_eye.loc,C)

/datum/action/vest_mode_swap
	name = "Switch Vest Mode"
	action_type = AB_INNATE
	button_icon_state = "vest_mode"

/datum/action/vest_mode_swap/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target
	console.FlipVest()

/datum/action/vest_disguise_swap
	name = "Switch Vest Disguise"
	action_type = AB_INNATE
	button_icon_state = "vest_disguise"

/datum/action/vest_disguise_swap/Activate()
	if(!target || !iscarbon(owner))
		return
	var/obj/machinery/abductor/console/console = target
	console.SelectDisguise(remote=1)


code:
//Common

/obj/machinery/abductor
	var/team = 0

/obj/machinery/abductor/proc/IsAbductor(var/mob/living/carbon/human/H)
	if(!H.dna)
		return 0
	return H.dna.species.id == "abductor"

/obj/machinery/abductor/proc/IsAgent(var/mob/living/carbon/human/H)
	if(H.dna.species.id == "abductor")
		var/datum/species/abductor/S = H.dna.species
		return S.agent
	return 0

/obj/machinery/abductor/proc/IsScientist(var/mob/living/carbon/human/H)
	if(H.dna.species.id == "abductor")
		var/datum/species/abductor/S = H.dna.species
		return S.scientist
	return 0

//Console

/obj/machinery/abductor/console
	name = "Abductor console"
	desc = "Ship command center."
	icon = 'icons/obj/abductor.dmi'
	icon_state = "console"
	density = 1
	anchored = 1.0
	var/obj/item/device/abductor/gizmo/gizmo
	var/obj/item/clothing/suit/armor/abductor/vest/vest
	var/obj/machinery/abductor/experiment/experiment
	var/obj/machinery/abductor/pad/pad
	var/obj/machinery/computer/camera_advanced/abductor/camera
	var/list/datum/icon_snapshot/disguises = list()

/obj/machinery/abductor/console/attack_hand(var/mob/user as mob)
	if(..())
		return
	if(!IsAbductor(user))
		user << "You start mashing alien buttons at random!"
		if(do_after(user,100))
			TeleporterSend()
		return
	user.set_machine(src)
	var/dat = ""
	dat += "
 Abductsoft 3000
"

	if(experiment != null)
		var/points = experiment.points
		dat += "Collected Samples : [points]
"
		dat += "Transfer data in exchange for supplies:
"
		dat += "Advanced Baton
"
		dat += "Agent Helmet
"
		dat += "Radio Silencer
"
		dat += "Science Tool
"
	else
		dat += "NO EXPERIMENT MACHINE DETECTED
"

	if(pad!=null)
		dat += "Emergency Teleporter System."
		dat += "Consider using primary observation console first."
		dat += "Activate Teleporter
"
		dat += "Set Teleporter
"
		if(gizmo!=null && gizmo.marked!=null)
			dat += "Retrieve Mark
"
		else
			dat += "Retrieve Mark
"
	else
		dat += "NO TELEPAD DETECTED
"

	if(vest!=null)
		dat += "
 Agent Vest Mode

"
		var/mode = vest.mode
		if(mode == VEST_STEALTH)
			dat += "Combat"
			dat += "Stealth"
		else
			dat += "Combat"
			dat += "Stealth"

		dat+="
"
		dat += "Select Agent Vest Disguise
"
	else
		dat += "NO AGENT VEST DETECTED"
	var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()
	return

/obj/machinery/abductor/console/Topic(href, href_list)
	if(..())
		return

	usr.set_machine(src)
	if(href_list["teleporter_set"])
		TeleporterSet()
	else if(href_list["teleporter_send"])
		TeleporterSend()
	else if(href_list["teleporter_retrieve"])
		TeleporterRetrieve()
	else if(href_list["flip_vest"])
		FlipVest()
	else if(href_list["select_disguise"])
		SelectDisguise()
	else if(href_list["dispense"])
		switch(href_list["dispense"])
			if("baton")
				Dispense(/obj/item/weapon/abductor_baton,cost=2)
			if("helmet")
				Dispense(/obj/item/clothing/head/helmet/abductor)
			if("silencer")
				Dispense(/obj/item/device/abductor/silencer)
			if("tool")
				Dispense(/obj/item/device/abductor/gizmo)
	src.updateUsrDialog()

/obj/machinery/abductor/console/proc/TeleporterSet()
	var/A = null
	A = input("Select area to teleport to", "Teleport", A) in teleportlocs
	if(pad!=null && in_range(usr,src))
		pad.teleport_target = teleportlocs[A]
	return

/obj/machinery/abductor/console/proc/TeleporterRetrieve()
	if(gizmo!=null && pad!=null && gizmo.marked)
		pad.Retrieve(gizmo.marked)
	return

/obj/machinery/abductor/console/proc/TeleporterSend()
	if(pad!=null)
		pad.Send()
	return

/obj/machinery/abductor/console/proc/FlipVest()
	if(vest!=null)
		vest.flip_mode()
	return

/obj/machinery/abductor/console/proc/SelectDisguise(var/remote=0)
	var/list/entries = list()
	var/tempname
	var/datum/icon_snapshot/temp
	for(var/i = 1; i <= disguises.len; i++)
		temp = disguises[i]
		tempname = temp.name
		entries["[tempname]"] = disguises[i]
	var/entry_name = input( "Choose Disguise", "Disguise") in entries
	var/datum/icon_snapshot/chosen = entries[entry_name]
	if(chosen && (remote || in_range(usr,src)))
		vest.SetDisguise(chosen)
	return

/obj/machinery/abductor/console/proc/Initialize()

	for(var/obj/machinery/abductor/pad/p in machines)
		if(p.team == team)
			pad = p
			break

	for(var/obj/machinery/abductor/experiment/e in machines)
		if(e.team == team)
			experiment = e
			e.console = src

	for(var/obj/machinery/computer/camera_advanced/abductor/c in machines)
		if(c.team == team)
			camera = c
			c.console = src

/obj/machinery/abductor/console/proc/AddSnapshot(var/mob/living/carbon/human/target)
	var/datum/icon_snapshot/entry = new
	entry.name = target.name
	entry.icon = target.icon
	entry.icon_state = target.icon_state
	entry.overlays = target.get_overlays_copy(list(L_HAND_LAYER,R_HAND_LAYER))
	for(var/i=1,i<=disguises.len,i++)
		var/datum/icon_snapshot/temp = disguises[i]
		if(temp.name == entry.name)
			disguises[i] = entry
			return
	disguises.Add(entry)
	return

/obj/machinery/abductor/console/attackby(O as obj, user as mob, params)
	if(istype(O, /obj/item/device/abductor/gizmo))
		var/obj/item/device/abductor/gizmo/G = O
		user << "You link the tool to the console."
		gizmo = G
		G.console = src
	else if(istype(O, /obj/item/clothing/suit/armor/abductor/vest))
		var/obj/item/clothing/suit/armor/abductor/vest/V = O
		user << "You link the vest to the console."
		vest = V
	else
		..()

/obj/machinery/abductor/console/proc/Dispense(var/item,var/cost=1)
	if(experiment && experiment.points >= cost)
		experiment.points-=cost
		say("Incoming supply!")
		if(pad)
			flick("alien-pad", pad)
			new item(pad.loc)
		else
			new item(src.loc)
	else
		say("Insufficent data!")
	return


code:
/obj/machinery/abductor/gland_dispenser
	name = "Replacement Organ Storage"
	desc = "A tank filled with replacement organs"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "dispenser"
	density = 1
	anchored = 1
	var/list/gland_types
	var/list/gland_colors
	var/list/amounts

/obj/machinery/abductor/gland_dispenser/proc/random_color()
	//TODO : replace with presets or spectrum
	return rgb(rand(0,255),rand(0,255),rand(0,255))

/obj/machinery/abductor/gland_dispenser/New()
	gland_types = typesof(/obj/item/gland) - /obj/item/gland
	gland_types = shuffle(gland_types)
	gland_colors = new/list(gland_types.len)
	amounts = new/list(gland_types.len)
	for(var/i=1,i<=gland_types.len,i++)
		gland_colors[i] = random_color()
		amounts[i] = rand(1,5)

/obj/machinery/abductor/gland_dispenser/attack_hand(var/mob/user as mob)
	if(..())
		return
	if(!IsAbductor(user))
		return
	user.set_machine(src)
	var/box_css = {"
	"}
	var/dat = ""
	var/item_count = 0
	for(var/i=1,i<=gland_colors.len,i++)
		item_count++
		var/g_color = gland_colors[i]
		var/amount = amounts[i]
		dat += "[amount]"
		if(item_count == 3) // Three boxes per line
			dat +="

"
			item_count = 0
	var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200)
	popup.add_head_content(box_css)
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()
	return

/obj/machinery/abductor/gland_dispenser/attackby(obj/item/weapon/W, mob/user, params)
	if(istype(W, /obj/item/gland))
		user.drop_item()
		W.loc = src
		for(var/i=1,i<=gland_colors.len,i++)
			if(gland_types[i] == W.type)
				amounts[i]++

/obj/machinery/abductor/gland_dispenser/Topic(href, href_list)
	if(..())
		return
	usr.set_machine(src)

	if(href_list["dispense"])
		Dispense(text2num(href_list["dispense"]))
	src.updateUsrDialog()

/obj/machinery/abductor/gland_dispenser/proc/Dispense(var/count)
	if(amounts[count]>0)
		amounts[count]--
		var/T = gland_types[count]
		new T(get_turf(src))


code:
/obj/machinery/abductor/experiment
	name = "Experimental machinery"
	desc = "A human-sized coffin sporting wide array of automatic surgery tools"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "experiment-open"
	density = 0
	anchored = 1
	state_open = 1
	var/points = 0
	var/list/history = new
	var/flash = " - || - "
	var/obj/machinery/abductor/console/console

/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
	if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
		return
	if(IsAbductor(target))
		return
	close_machine(target)

/obj/machinery/abductor/experiment/allow_drop()
	return 0

/obj/machinery/abductor/experiment/attack_hand(mob/user)
	if(..())
		return

	experimentUI(user)

/obj/machinery/abductor/experiment/open_machine()
	if(!state_open && !panel_open)
		..()

/obj/machinery/abductor/experiment/close_machine(mob/target)
	for(var/mob/living/carbon/C in loc)
		if(IsAbductor(C))
			return
	if(state_open && !panel_open)
		..(target)

/obj/machinery/abductor/experiment/proc/dissection_icon(var/mob/living/carbon/human/H)
	var/icon/photo = null
	var/g = (H.gender == FEMALE) ? "f" : "m"
	if(!config.mutant_races || H.dna.species.use_skintones)
		photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]_s")
	else
		photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]_s")
		photo.Blend("#[H.dna.mutant_color]", ICON_MULTIPLY)

	var/icon/eyes_s
	if(EYECOLOR in H.dna.species.specflags)
		eyes_s = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[H.dna.species.eyes]_s")
		eyes_s.Blend("#[H.eye_color]", ICON_MULTIPLY)

	var/datum/sprite_accessory/S
	S = hair_styles_list[H.hair_style]
	if(S && (HAIR in H.dna.species.specflags))
		var/icon/hair_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
		hair_s.Blend("#[H.hair_color]", ICON_MULTIPLY)
		eyes_s.Blend(hair_s, ICON_OVERLAY)

	S = facial_hair_styles_list[H.facial_hair_style]
	if(S && (FACEHAIR in H.dna.species.specflags))
		var/icon/facial_s = icon("icon" = S.icon, "icon_state" = "[S.icon_state]_s")
		facial_s.Blend("#[H.facial_hair_color]", ICON_MULTIPLY)
		eyes_s.Blend(facial_s, ICON_OVERLAY)

	if(eyes_s)
		photo.Blend(eyes_s, ICON_OVERLAY)

	var/icon/splat = icon("icon" = 'icons/mob/dam_human.dmi',"icon_state" = "chest30")
	photo.Blend(splat,ICON_OVERLAY)

	return photo

/obj/machinery/abductor/experiment/proc/experimentUI(mob/user)
	var/dat
	dat += "
 Experiment
"
	if(occupant)
		var/obj/item/weapon/photo/P = new
		P.photocreate(null, icon(dissection_icon(occupant), dir = SOUTH))
		user << browse_rsc(P.img, "dissection_img")
		dat += "

"
		dat += "" //Avert your eyes
		dat += "	"
		dat += "Probe
"
		dat += "Dissect
"
		dat += "Analyze
"
		dat += "

"
	else
		dat += " Experiment "

	if(!occupant)
		dat += "
Machine Unoccupied
"
	else
		dat += "
Subject Status :
"
		dat += "[occupant.name] => "
		switch(occupant.stat)
			if(0)
				dat += "Conscious"
			if(1)
				dat += "Unconscious"
			else
				dat += "DEAD"
	dat += "
"
	dat += "[flash]"
	dat += "
"
	dat += "Scan"
	dat += "Close" : "open=1'>Open"]"
	var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
	popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
	popup.set_content(dat)
	popup.open()

/obj/machinery/abductor/experiment/Topic(href, href_list)
	if(..() || usr == occupant)
		return
	usr.set_machine(src)
	if(href_list["refresh"])
		updateUsrDialog()
		return
	if(href_list["open"])
		open_machine()
		return
	if(href_list["close"])
		close_machine()
		return
	if(occupant && occupant.stat != DEAD)
		if(href_list["experiment"])
			flash = Experiment(occupant,href_list["experiment"])
	updateUsrDialog()
	add_fingerprint(usr)

/obj/machinery/abductor/experiment/proc/Experiment(var/mob/occupant,var/type)
	var/mob/living/carbon/human/H = occupant
	var/point_reward = 0
	if(H in history)
		return "Specimen already in the database"
	if(H.stat == DEAD)
		say("Specimen deceased - please provide fresh sample.")
		return "Specimen Deceased"
	var/obj/item/gland/GlandTest = locate() in H
	if(!GlandTest)
		say("Experimental dissection not detected!")
		return "No glands detected!"
	if(H.mind != null && H.ckey != null)
		history += H
		say("Processing Specimen...")
		sleep(5)
		switch(text2num(type))
			if(1)
				H << "You feel violated."
			if(2)
				H << "You feel being sliced and put back together."
			if(3)
				H << "You feel under intense scrutiny."
		sleep(5)
		H << "Your mind snaps!"
		var/objtype = pick(typesof(/datum/objective/abductee/) - /datum/objective/abductee/)
		var/datum/objective/abductee/O = new objtype()
		H.mind.objectives += O
		var/obj_count = 1
		H << "Your current objectives:"
		for(var/datum/objective/objective in H.mind.objectives)
			H << "Objective #[obj_count]: [objective.explanation_text]"
			obj_count++

		for(var/obj/item/gland/G in H)
			G.Start()
			point_reward++
		if(point_reward > 0)
			open_machine()
			SendBack(H)
			playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
			points += point_reward
			return "Experiment Successfull! [point_reward] new data-points collected."
		else
			playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
			return "Experiment Failed! No replacement organ detected."
	else
		say("Brain Activity Nonexistant - Disposing Sample...")
		open_machine()
		SendBack(H)
		return "Specimen Braindead - Disposed"
	return "ERROR"

/obj/machinery/abductor/experiment/proc/SendBack(var/mob/living/carbon/human/H)
	H.Sleeping(8)
	var/area/A
	if(console && console.pad && console.pad.teleport_target)
		A = console.pad.teleport_target
	//	if(A.safe) // right now crew areas are safe - being locked behind closed doors is not fun
		TeleportToArea(H,A)
	//Area not chosen / It's not safe area - teleport to arrivals
	H.forceMove(pick(latejoin))

/obj/machinery/abductor/experiment/update_icon()
	if(state_open)
		icon_state = "experiment-open"
	else
		icon_state = "experiment"

/obj/machinery/abductor/experiment/say_quote(text)
	return "beeps, \"[text]\""


code:
/obj/machinery/abductor/pad
	name = "Alien Telepad"
	desc = "Use this to transport to and from human habitat"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "alien-pad-idle"
	anchored = 1
	var/area/teleport_target

/obj/machinery/abductor/proc/TeleportToArea(var/mob/living/target,var/area/thearea)
	var/list/L = list()
	for(var/turf/T in get_area_turfs(thearea.type))
		if(!T.density)
			var/clear = 1
			for(var/obj/O in T)
				if(O.density)
					clear = 0
					break
			if(clear)
				L+=T
	if(!L.len)
		return

	if(target && target.buckled)
		target.buckled.unbuckle_mob()

	var/list/tempL = L
	var/attempt = null
	var/success = 0
	while(tempL.len)
		attempt = pick(tempL)
		target.Move(attempt)
		if(get_turf(target) == attempt)
			success = 1
			break
		else
			tempL.Remove(attempt)
	if(!success)
		target.loc = pick(L)

/obj/machinery/abductor/pad/proc/Warp(var/mob/living/target)
	target.Move(src.loc)

/obj/machinery/abductor/pad/proc/Send()
	if(teleport_target == null)
		teleport_target = teleportlocs[pick(teleportlocs)]
	flick("alien-pad", src)
	for(var/mob/living/target in src.loc)
		TeleportToArea(target,teleport_target)
		spawn(0)
			anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/machinery/abductor/pad/proc/Retrieve(var/mob/living/target)
	flick("alien-pad", src)
	spawn(0)
		anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)
	Warp(target)

/obj/machinery/abductor/pad/proc/MobToLoc(var/place,var/mob/living/target)
	var/obj/effect/teleport_abductor/F = new(place)
	var/datum/effect/effect/system/spark_spread/S = new
	S.set_up(10,0,place)
	S.start()
	sleep(10)
	qdel(F)
	flick("alien-pad", src)
	target.forceMove(place)
	anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/machinery/abductor/pad/proc/PadToLoc(var/place)
	var/obj/effect/teleport_abductor/F = new(place)
	var/datum/effect/effect/system/spark_spread/S = new
	S.set_up(10,0,place)
	S.start()
	sleep(40)
	qdel(F)
	flick("alien-pad", src)
	for(var/mob/living/target in src.loc)
		target.forceMove(place)
		spawn(0)
			anim(target.loc,target,'icons/mob/mob.dmi',,"uncloak",,target.dir)

/obj/effect/teleport_abductor
	name = "Huh"
	icon = 'icons/obj/abductor.dmi'
	icon_state = "teleport"


code:
/datum/atom_hud/antag
	hud_icons = list(ANTAG_HUD)

/datum/atom_hud/antag/proc/join_hud(var/mob/living/M)
	if(!istype(M))
		CRASH("join_hud(): [M] ([M.type]) is not a living mob!")
	if(M.mind.antag_hud)
		var/datum/atom_hud/antag/oldhud = M.mind.antag_hud
		oldhud.leave_hud(M)
	add_to_hud(M)
	add_hud_to(M)
	M.mind.antag_hud = src

/datum/atom_hud/antag/proc/leave_hud(var/mob/living/M)
	if(!istype(M))
		CRASH("leave_hud(): [M] ([M.type]) is not a living mob!")
	remove_from_hud(M)
	remove_hud_from(M)
	M.mind.antag_hud = null

//GAME_MODE PROCS
//called to set a mob's antag icon state
/datum/game_mode/proc/set_antag_hud(var/mob/living/M, var/new_icon_state)
	if(!istype(M))
		CRASH("set_antag_hud(): [M] ([M.type]) is not a living mob!")
	var/image/holder = M.hud_list[ANTAG_HUD]
	holder.icon_state = new_icon_state
	M.mind.antag_hud_icon_state = new_icon_state

//MIND PROCS
//this is called by mind.transfer_to()
/datum/mind/proc/transfer_antag_huds(var/mob/living/M)
	for(var/datum/atom_hud/antag/hud in huds)
		if(M in hud.hudusers)
			hud.leave_hud(M)
	var/image/holder = M.hud_list[ANTAG_HUD]
	if(holder && !istype(holder, /mob/dead/observer))
		holder.icon_state = antag_hud_icon_state
	if(antag_hud)
		antag_hud.join_hud(M)


code:
/obj/item/weapon/antag_spawner
	throw_speed = 1
	throw_range = 5
	w_class = 1.0
	var/used = 0

/obj/item/weapon/antag_spawner/proc/spawn_antag(var/client/C, var/turf/T, var/type = "")
	return

/obj/item/weapon/antag_spawner/proc/equip_antag(mob/target as mob)
	return

/obj/item/weapon/antag_spawner/contract
	name = "contract"
	desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid."
	icon = 'icons/obj/wizard.dmi'
	icon_state ="scroll2"

/obj/item/weapon/antag_spawner/contract/attack_self(mob/user as mob)
	user.set_machine(src)
	var/dat
	if(used)
		dat = "You have already summoned your apprentice.
"
	else
		dat = "Contract of Apprenticeship:
"
		dat += "Using this contract, you may summon an apprentice to aid you on your mission.
"
		dat += "If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.
"
		dat += "Which school of magic is your apprentice studying?:
"
		dat += "Destruction
"
		dat += "Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.
"
		dat += "Bluespace Manipulation
"
		dat += "Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.
"
		dat += "Healing
"
		dat += "Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.
"
		dat += "Robeless
"
		dat += "Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.
"
	user << browse(dat, "window=radio")
	onclose(user, "radio")
	return

/obj/item/weapon/antag_spawner/contract/Topic(href, href_list)
	..()
	var/mob/living/carbon/human/H = usr

	if(H.stat || H.restrained())
		return
	if(!istype(H, /mob/living/carbon/human))
		return 1

	if(loc == H || (in_range(src, H) && istype(loc, /turf)))
		H.set_machine(src)
		if(href_list["school"])
			if (used)
				H << "You already used this contract!"
				return
			var/list/candidates = get_candidates(BE_WIZARD)
			if(candidates.len)
				src.used = 1
				var/client/C = pick(candidates)
				spawn_antag(C, get_turf(H.loc), href_list["school"])
				if(H.mind)
					ticker.mode.update_wiz_icons_added(H.mind)
			else
				H << "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later."

/obj/item/weapon/antag_spawner/contract/spawn_antag(var/client/C, var/turf/T, var/type = "")
	PoolOrNew(/obj/effect/effect/harmless_smoke, T)
	var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
	C.prefs.copy_to(M)
	M.key = C.key
	M << "You are the [usr.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
	switch(type)
		if("destruction")
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
			M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
		if("bluespace")
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
			M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
		if("healing")
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
			M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
			M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
		if("robeless")
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
			M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
			M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."

	equip_antag(M)
	var/wizard_name_first = pick(wizard_first)
	var/wizard_name_second = pick(wizard_second)
	var/randomname = "[wizard_name_first] [wizard_name_second]"
	var/newname = copytext(sanitize(input(M, "You are the wizard's apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
	if (!newname)
		newname = randomname
	M.mind.name = newname
	M.real_name = newname
	M.name = newname
	var/datum/objective/protect/new_objective = new /datum/objective/protect
	new_objective.owner = M:mind
	new_objective:target = usr:mind
	new_objective.explanation_text = "Protect [usr.real_name], the wizard."
	M.mind.objectives += new_objective
	ticker.mode.traitors += M.mind
	M.mind.special_role = "apprentice"
	ticker.mode.update_wiz_icons_added(M.mind)
	M << sound('sound/effects/magic.ogg')

/obj/item/weapon/antag_spawner/contract/equip_antag(mob/target as mob)
	target.equip_to_slot_or_del(new /obj/item/device/radio/headset(target), slot_ears)
	target.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(target), slot_w_uniform)
	target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(target), slot_shoes)
	target.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(target), slot_wear_suit)
	target.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(target), slot_head)
	target.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(target), slot_back)
	target.equip_to_slot_or_del(new /obj/item/weapon/storage/box(target), slot_in_backpack)
	target.equip_to_slot_or_del(new /obj/item/weapon/teleportation_scroll/apprentice(target), slot_r_store)

/obj/item/weapon/antag_spawner/borg_tele
	name = "Syndicate Cyborg Teleporter"
	desc = "A single-use teleporter used to deploy a Syndicate Cyborg on the field."
	icon = 'icons/obj/device.dmi'
	icon_state = "locator"
	var/TC_cost = 0

/obj/item/weapon/antag_spawner/borg_tele/attack_self(mob/user as mob)
	if(used)
		user << "The teleporter is out of power."
		return
	var/list/borg_candicates = get_candidates(BE_OPERATIVE)
	if(borg_candicates.len > 0)
		used = 1
		var/client/C = pick(borg_candicates)
		spawn_antag(C, get_turf(src.loc), "syndieborg")
	else
		user << "Unable to connect to Syndicate Command. Please wait and try again later or use the teleporter on your uplink to get your points refunded."

/obj/item/weapon/antag_spawner/borg_tele/spawn_antag(var/client/C, var/turf/T, var/type = "")
	var/datum/effect/effect/system/spark_spread/S = new /datum/effect/effect/system/spark_spread
	S.set_up(4, 1, src)
	S.start()
	var/mob/living/silicon/robot/R = new /mob/living/silicon/robot/syndicate(T)
	R.key = C.key
	ticker.mode.syndicates += R.mind
	ticker.mode.update_synd_icons_added(R.mind)
	R.mind.special_role = "syndicate"
	R.faction = list("syndicate")