code:
/obj/machinery/computer/cloning
	name = "cloning console"
	desc = "Used to clone people and manage DNA."
	icon_screen = "dna"
	icon_keyboard = "med_key"
	circuit = /obj/item/weapon/circuitboard/cloning
	req_access = list(access_heads) //Only used for record deletion right now.
	var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
	var/obj/machinery/clonepod/pod1 = null //Linked cloning pod.
	var/temp = "Inactive"
	var/scantemp_ckey
	var/scantemp = "Ready to Scan"
	var/menu = 1 //Which menu screen to display
	var/list/records = list()
	var/datum/data/record/active_record = null
	var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything.
	var/loading = 0 // Nice loading text
	var/autoprocess = 0

/obj/machinery/computer/cloning/New()
	..()
	spawn(5)
		updatemodules()
		return
	return

/obj/machinery/computer/cloning/process()
	if(!(scanner && pod1 && autoprocess))
		return

	if(scanner.occupant && (scanner.scan_level > 2))
		scan_mob(scanner.occupant)

	if(!(pod1.occupant || pod1.mess) && (pod1.efficiency > 5))
		for(var/datum/data/record/R in records)
			if(!(pod1.occupant || pod1.mess))
				if(pod1.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"]))
					records -= R

/obj/machinery/computer/cloning/proc/updatemodules()
	src.scanner = findscanner()
	src.pod1 = findcloner()

	if (!isnull(src.pod1))
		src.pod1.connected = src // Some variable the pod needs

/obj/machinery/computer/cloning/proc/findscanner()
	var/obj/machinery/dna_scannernew/scannerf = null

	// Loop through every direction
	for(dir in list(NORTH,EAST,SOUTH,WEST))

		// Try to find a scanner in that direction
		scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, dir))

		// If found and operational, return the scanner
		if (!isnull(scannerf) && scannerf.is_operational())
			return scannerf

	// If no scanner was found, it will return null
	return null

/obj/machinery/computer/cloning/proc/findcloner()
	var/obj/machinery/clonepod/podf = null

	for(dir in list(NORTH,EAST,SOUTH,WEST))

		podf = locate(/obj/machinery/clonepod, get_step(src, dir))

		if (!isnull(podf) && podf.is_operational())
			return podf

	return null

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

/obj/machinery/computer/cloning/attack_hand(mob/user)
	if(..())
		return
	interact(user)

/obj/machinery/computer/cloning/interact(mob/user)
	user.set_machine(src)
	add_fingerprint(user)

	if(..())
		return

	updatemodules()

	var/dat = ""
	dat += "Refresh"
	if(scanner && pod1 && ((scanner.scan_level > 2) || (pod1.efficiency > 5)))
		if(!autoprocess)
			dat += "Autoprocess"
		else
			dat += "Stop autoprocess"
	else
		dat += "Autoprocess"
	dat += "
Cloning Pod Status
"
	dat += "
[temp]
"

	switch(src.menu)
		if(1)
			// Modules
			if (isnull(src.scanner) || isnull(src.pod1))
				dat += "
Modules
"
				//dat += "Reload Modules"
				if (isnull(src.scanner))
					dat += "ERROR: No Scanner detected!
"
				if (isnull(src.pod1))
					dat += "ERROR: No Pod detected
"

			// Scanner
			if (!isnull(src.scanner))

				dat += "
Scanner Functions
"

				dat += "
"
				if (!src.scanner.occupant)
					dat += "Scanner Unoccupied"
				else if(loading)
					dat += "[src.scanner.occupant] => Scanning..."
				else
					if (src.scanner.occupant.ckey != scantemp_ckey)
						scantemp = "Ready to Scan"
						scantemp_ckey = src.scanner.occupant.ckey
					dat += "[src.scanner.occupant] => [scantemp]"
				dat += "
"

				if (src.scanner.occupant)
					dat += "Start Scan"
					dat += "
[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]"
				else
					dat += "Start Scan"

			// Database
			dat += "
Database Functions
"
			if (src.records.len && src.records.len > 0)
				dat += "View Records ([src.records.len])
"
			else
				dat += "View Records (0)
"
			if (src.diskette)
				dat += "Eject Disk
"

		if(2)
			dat += "
Current records
"
			dat += "<< Back

"
			for(var/datum/data/record/R in records)
				dat += "
[R.fields["name"]]
Scan ID [R.fields["id"]] View Record"
		if(3)
			dat += "
Selected Record
"
			dat += "<< Back
"

			if (!src.active_record)
				dat += "Record not found."
			else
				dat += "
[src.active_record.fields["name"]]
"
				dat += "Scan ID [src.active_record.fields["id"]] Clone
"

				var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"])

				if ((H) && (istype(H)))
					dat += "Health Implant Data:
[H.sensehealth()]

"
				else
					dat += "Unable to locate Health Implant.

"

				dat += "Unique Identifier:
[src.active_record.fields["UI"]]
"
				dat += "Structural Enzymes:
[src.active_record.fields["SE"]]
"

				if(diskette && diskette.fields)
					dat += "
"
					dat += "
Inserted Disk
"
					dat += "Contents: "
					var/list/L = list()
					if(diskette.fields["UI"])
						L += "Unique Identifier"
					if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
						L += "Unique Enzymes"
					if(diskette.fields["SE"])
						L += "Structural Enzymes"
					dat += english_list(L, "Empty", " + ", " + ")
					dat += "
Load from Disk"

					dat += "
Save to Disk"
					dat += "
"

				dat += "Delete Record"

		if(4)
			if (!src.active_record)
				src.menu = 2
			dat = "[src.temp]
"
			dat += "
Confirm Record Deletion
"

			dat += "Scan card to confirm.
"
			dat += "Cancel"

	//user << browse(dat, "window=cloning")
	//onclose(user, "cloning")
	var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()
	return

/obj/machinery/computer/cloning/Topic(href, href_list)
	if(..())
		return

	if(loading)
		return

	if(href_list["task"])
		switch(href_list["task"])
			if("autoprocess")
				autoprocess = 1
			if("stopautoprocess")
				autoprocess = 0

	else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
		scantemp = ""

		loading = 1
		src.updateUsrDialog()

		spawn(20)
			src.scan_mob(scanner.occupant)

			loading = 0
			src.updateUsrDialog()

		//No locking an open scanner.
	else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
		if ((!scanner.locked) && (scanner.occupant))
			scanner.locked = 1
		else
			scanner.locked = 0

	else if(href_list["view_rec"])
		src.active_record = find_record("id", href_list["view_rec"], records)
		if(active_record)
			if(!active_record.fields["ckey"])
				records -= active_record
				active_record = null
				src.temp = "Record Corrupt"
			else
				src.menu = 3
		else
			src.temp = "Record missing."

	else if (href_list["del_rec"])
		if ((!src.active_record) || (src.menu < 3))
			return
		if (src.menu == 3) //If we are viewing a record, confirm deletion
			src.temp = "Delete record?"
			src.menu = 4

		else if (src.menu == 4)
			var/obj/item/weapon/card/id/C = usr.get_active_hand()
			if (istype(C)||istype(C, /obj/item/device/pda))
				if(src.check_access(C))
					src.temp = "[src.active_record.fields["name"]] => Record deleted."
					src.records.Remove(active_record)
					active_record = null
					src.menu = 2
				else
					src.temp = "Access Denied."

	else if (href_list["disk"]) //Load or eject.
		switch(href_list["disk"])
			if("load")
				if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
					src.temp = "Load error."
					src.updateUsrDialog()
					return
				if (!src.active_record)
					src.temp = "Record error."
					src.menu = 1
					src.updateUsrDialog()
					return

				for(var/key in diskette.fields)
					src.active_record.fields[key] = diskette.fields[key]
				src.temp = "Load successful."

			if("eject")
				if(src.diskette)
					src.diskette.loc = src.loc
					src.diskette = null
			if("save")
				if(!diskette || diskette.read_only || !active_record || !active_record.fields)
					src.temp = "Save error."
					src.updateUsrDialog()
					return

				diskette.fields = active_record.fields.Copy()
				diskette.name = "data disk - '[src.diskette.fields["name"]]'"
				src.temp = "Save successful."

	else if (href_list["refresh"])
		src.updateUsrDialog()

	else if (href_list["clone"])
		var/datum/data/record/C = find_record("id", href_list["clone"], records)
		//Look for that player! They better be dead!
		if(C)
			//Can't clone without someone to clone.  Or a pod.  Or if the pod is busy. Or full of gibs.
			if(!pod1)
				temp = "No Clonepod detected."
			else if(pod1.occupant)
				temp = "Clonepod is currently occupied."
			else if(pod1.mess)
				temp = "Clonepod malfunction."
			else if(!config.revival_cloning)
				temp = "Unable to initiate cloning cycle."
			else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"]))
				temp = "[C.fields["name"]] => Cloning cycle in progress..."
				records.Remove(C)
				if(active_record == C)
					active_record = null
				menu = 1
			else
				temp = "[C.fields["name"]] => Initialisation failure."

		else
			temp = "Data corruption."

	else if (href_list["menu"])
		src.menu = text2num(href_list["menu"])

	src.add_fingerprint(usr)
	src.updateUsrDialog()
	return

/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject)
	if (!istype(subject))
		scantemp = "Unable to locate valid genetic data."
		return
	if (!subject.getorgan(/obj/item/organ/internal/brain))
		scantemp = "No signs of intelligence detected."
		return
	if (subject.suiciding == 1)
		scantemp = "Subject's brain is not responding to scanning stimuli."
		return
	if ((subject.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
		scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
		return
	if ((!subject.ckey) || (!subject.client))
		scantemp = "Mental interface failure."
		return
	if (find_record("ckey", subject.ckey, records))
		scantemp = "Subject already in database."
		return

	var/datum/data/record/R = new()
	if(subject.dna.species)
		R.fields["mrace"] = subject.dna.species.type
	else
		var/datum/species/rando_race = pick(config.roundstart_races)
		R.fields["mrace"] = rando_race.type
	R.fields["ckey"] = subject.ckey
	R.fields["name"] = subject.real_name
	R.fields["id"] = copytext(md5(subject.real_name), 2, 6)
	R.fields["UE"] = subject.dna.unique_enzymes
	R.fields["UI"] = subject.dna.uni_identity
	R.fields["SE"] = subject.dna.struc_enzymes
	R.fields["blood_type"] = subject.dna.blood_type
	R.fields["features"] = subject.dna.features
	R.fields["factions"] = subject.faction
	//Add an implant if needed
	var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject)
	if(!imp)
		imp = new /obj/item/weapon/implant/health(subject)
		imp.implanted = subject
		R.fields["imp"] = "\ref[imp]"
	//Update it if needed
	else
		R.fields["imp"] = "\ref[imp]"

	if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning.
		R.fields["mind"] = "\ref[subject.mind]"

	src.records += R
	scantemp = "Subject successfully scanned."


code:
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31

var/const/CALL_SHUTTLE_REASON_LENGTH = 12

// The communications computer
/obj/machinery/computer/communications
	name = "communications console"
	desc = "This can be used for various important functions. Still under developement."
	icon_screen = "comm"
	icon_keyboard = "tech_key"
	req_access = list(access_heads)
	circuit = /obj/item/weapon/circuitboard/communications
	var/authenticated = 0
	var/auth_id = "Unknown" //Who is currently logged in?
	var/list/messagetitle = list()
	var/list/messagetext = list()
	var/currmsg = 0
	var/aicurrmsg = 0
	var/state = STATE_DEFAULT
	var/aistate = STATE_DEFAULT
	var/message_cooldown = 0
	var/ai_message_cooldown = 0
	var/tmp_alertlevel = 0
	var/const/STATE_DEFAULT = 1
	var/const/STATE_CALLSHUTTLE = 2
	var/const/STATE_CANCELSHUTTLE = 3
	var/const/STATE_MESSAGELIST = 4
	var/const/STATE_VIEWMESSAGE = 5
	var/const/STATE_DELMESSAGE = 6
	var/const/STATE_STATUSDISPLAY = 7
	var/const/STATE_ALERT_LEVEL = 8
	var/const/STATE_CONFIRM_LEVEL = 9
	var/const/STATE_TOGGLE_EMERGENCY = 10

	var/status_display_freq = "1435"
	var/stat_msg1
	var/stat_msg2

/obj/machinery/computer/communications/New()
	shuttle_caller_list += src
	..()

/obj/machinery/computer/communications/process()
	if(..())
		if(state != STATE_STATUSDISPLAY)
			src.updateDialog()

/obj/machinery/computer/communications/Topic(href, href_list)
	if(..())
		return
	if (src.z > ZLEVEL_CENTCOM) //Can only use on centcom and SS13
		usr << "Unable to establish a connection: \black You're too far away from the station!"
		return
	usr.set_machine(src)

	if(!href_list["operation"])
		return
	var/obj/item/weapon/circuitboard/communications/CM = circuit
	switch(href_list["operation"])
		// main interface
		if("main")
			src.state = STATE_DEFAULT
		if("login")
			var/mob/M = usr
			var/obj/item/weapon/card/id/I = M.get_active_hand()
			if (istype(I, /obj/item/device/pda))
				var/obj/item/device/pda/pda = I
				I = pda.id
			if (I && istype(I))
				if(src.check_access(I))
					authenticated = 1
					auth_id = "[I.registered_name] ([I.assignment])"
					if((20 in I.access))
						authenticated = 2
				if(src.emagged)
					authenticated = 2
					auth_id = "Unknown"
		if("logout")
			authenticated = 0

		if("swipeidseclevel")
			var/mob/M = usr
			var/obj/item/weapon/card/id/I = M.get_active_hand()
			if (istype(I, /obj/item/device/pda))
				var/obj/item/device/pda/pda = I
				I = pda.id
			if (I && istype(I))
				if(access_captain in I.access)
					var/old_level = security_level
					if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN
					if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN
					if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
					set_security_level(tmp_alertlevel)
					if(security_level != old_level)
						//Only notify the admins if an actual change happened
						log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
						message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
						switch(security_level)
							if(SEC_LEVEL_GREEN)
								feedback_inc("alert_comms_green",1)
							if(SEC_LEVEL_BLUE)
								feedback_inc("alert_comms_blue",1)
					tmp_alertlevel = 0
				else:
					usr << "You are not authorized to do this!"
					tmp_alertlevel = 0
				state = STATE_DEFAULT
			else
				usr << "You need to swipe your ID!"

		if("announce")
			if(src.authenticated==2 && !message_cooldown)
				make_announcement(usr)
			else if (src.authenticated==2 && message_cooldown)
				usr << "Intercomms recharging. Please stand by."

		if("callshuttle")
			src.state = STATE_DEFAULT
			if(src.authenticated)
				src.state = STATE_CALLSHUTTLE
		if("callshuttle2")
			if(src.authenticated)
				SSshuttle.requestEvac(usr, href_list["call"])
				if(SSshuttle.emergency.timer)
					post_status("shuttle")
			src.state = STATE_DEFAULT
		if("cancelshuttle")
			src.state = STATE_DEFAULT
			if(src.authenticated)
				src.state = STATE_CANCELSHUTTLE
		if("cancelshuttle2")
			if(src.authenticated)
				SSshuttle.cancelEvac(usr)
			src.state = STATE_DEFAULT
		if("messagelist")
			src.currmsg = 0
			src.state = STATE_MESSAGELIST
		if("viewmessage")
			src.state = STATE_VIEWMESSAGE
			if (!src.currmsg)
				if(href_list["message-num"])
					src.currmsg = text2num(href_list["message-num"])
				else
					src.state = STATE_MESSAGELIST
		if("delmessage")
			src.state = (src.currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
		if("delmessage2")
			if(src.authenticated)
				if(src.currmsg)
					var/title = src.messagetitle[src.currmsg]
					var/text  = src.messagetext[src.currmsg]
					src.messagetitle.Remove(title)
					src.messagetext.Remove(text)
					if(src.currmsg == src.aicurrmsg)
						src.aicurrmsg = 0
					src.currmsg = 0
				src.state = STATE_MESSAGELIST
			else
				src.state = STATE_VIEWMESSAGE
		if("status")
			src.state = STATE_STATUSDISPLAY

		if("securitylevel")
			src.tmp_alertlevel = text2num( href_list["newalertlevel"] )
			if(!tmp_alertlevel) tmp_alertlevel = 0
			state = STATE_CONFIRM_LEVEL
		if("changeseclevel")
			state = STATE_ALERT_LEVEL

		if("emergencyaccess")
			state = STATE_TOGGLE_EMERGENCY
		if("enableemergency")
			make_maint_all_access()
			log_game("[key_name(usr)] enabled emergency maintenance access.")
			message_admins("[key_name_admin(usr)] enabled emergency maintenance access.")
			src.state = STATE_DEFAULT
		if("disableemergency")
			revoke_maint_all_access()
			log_game("[key_name(usr)] disabled emergency maintenance access.")
			message_admins("[key_name_admin(usr)] disabled emergency maintenance access.")
			src.state = STATE_DEFAULT

		// Status display stuff
		if("setstat")
			switch(href_list["statdisp"])
				if("message")
					post_status("message", stat_msg1, stat_msg2)
				if("alert")
					post_status("alert", href_list["alert"])
				else
					post_status(href_list["statdisp"])

		if("setmsg1")
			stat_msg1 = reject_bad_text(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40)
			src.updateDialog()
		if("setmsg2")
			stat_msg2 = reject_bad_text(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40)
			src.updateDialog()

		// OMG CENTCOM LETTERHEAD
		if("MessageCentcomm")
			if(src.authenticated==2)
				if(CM.lastTimeUsed + 600 > world.time)
					usr << "Arrays recycling.  Please stand by."
					return
				var/input = stripped_input(usr, "Please choose a message to transmit to Centcom via quantum entanglement.  Please be aware that this process is very expensive, and abuse will lead to... termination.  Transmission does not guarantee a response.", "Send a message to Centcomm.", "")
				if(!input || !(usr in view(1,src)))
					return
				Centcomm_announce(input, usr)
				usr << "Message transmitted."
				log_say("[key_name(usr)] has made a Centcom announcement: [input]")
				CM.lastTimeUsed = world.time

		// OMG SYNDICATE ...LETTERHEAD
		if("MessageSyndicate")
			if((src.authenticated==2) && (src.emagged))
				if(CM.lastTimeUsed + 600 > world.time)
					usr << "Arrays recycling.  Please stand by."
					return
				var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING COORDINATES\] via quantum entanglement.  Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to /??????/.", "")
				if(!input || !(usr in view(1,src)))
					return
				Syndicate_announce(input, usr)
				usr << "Message transmitted."
				log_say("[key_name(usr)] has made a Syndicate announcement: [input]")
				CM.lastTimeUsed = world.time

		if("RestoreBackup")
			usr << "Backup routing data restored!"
			src.emagged = 0
			src.updateDialog()

		if("nukerequest") //When there's no other way
			if(src.authenticated==2)
				if(CM.lastTimeUsed + 600 > world.time)
					usr << "Arrays recycling. Please stand by."
					return
				var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances.  Transmission does not guarantee a response.", "Self Destruct Code Request.","")
				if(!input || !(usr in view(1,src)))
					return
				Nuke_request(input, usr)
				usr << "Request sent."
				log_say("[key_name(usr)] has requested the nuclear codes from Centcomm")
				priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested",'sound/AI/commandreport.ogg')
				CM.lastTimeUsed = world.time

		// AI interface
		if("ai-main")
			src.aicurrmsg = 0
			src.aistate = STATE_DEFAULT
		if("ai-callshuttle")
			src.aistate = STATE_CALLSHUTTLE
		if("ai-callshuttle2")
			SSshuttle.requestEvac(usr, href_list["call"])
			src.aistate = STATE_DEFAULT
		if("ai-messagelist")
			src.aicurrmsg = 0
			src.aistate = STATE_MESSAGELIST
		if("ai-viewmessage")
			src.aistate = STATE_VIEWMESSAGE
			if (!src.aicurrmsg)
				if(href_list["message-num"])
					src.aicurrmsg = text2num(href_list["message-num"])
				else
					src.aistate = STATE_MESSAGELIST
		if("ai-delmessage")
			src.aistate = (src.aicurrmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
		if("ai-delmessage2")
			if(src.aicurrmsg)
				var/title = src.messagetitle[src.aicurrmsg]
				var/text  = src.messagetext[src.aicurrmsg]
				src.messagetitle.Remove(title)
				src.messagetext.Remove(text)
				if(src.currmsg == src.aicurrmsg)
					src.currmsg = 0
				src.aicurrmsg = 0
			src.aistate = STATE_MESSAGELIST
		if("ai-status")
			src.aistate = STATE_STATUSDISPLAY
		if("ai-announce")
			if(!ai_message_cooldown)
				make_announcement(usr, 1)
		if("ai-securitylevel")
			src.tmp_alertlevel = text2num( href_list["newalertlevel"] )
			if(!tmp_alertlevel) tmp_alertlevel = 0
			var/old_level = security_level
			if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN
			if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN
			if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
			set_security_level(tmp_alertlevel)
			if(security_level != old_level)
				//Only notify the admins if an actual change happened
				log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
				message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
				switch(security_level)
					if(SEC_LEVEL_GREEN)
						feedback_inc("alert_comms_green",1)
					if(SEC_LEVEL_BLUE)
						feedback_inc("alert_comms_blue",1)
			tmp_alertlevel = 0
			src.aistate = STATE_DEFAULT
		if("ai-changeseclevel")
			src.aistate = STATE_ALERT_LEVEL

		if("ai-emergencyaccess")
			src.aistate = STATE_TOGGLE_EMERGENCY
		if("ai-enableemergency")
			make_maint_all_access()
			log_game("[key_name(usr)] enabled emergency maintenance access.")
			message_admins("[key_name_admin(usr)] enabled emergency maintenance access.")
			src.aistate = STATE_DEFAULT
		if("ai-disableemergency")
			revoke_maint_all_access()
			log_game("[key_name(usr)] disabled emergency maintenance access.")
			message_admins("[key_name_admin(usr)] disabled emergency maintenance access.")
			src.aistate = STATE_DEFAULT

	src.updateUsrDialog()

/obj/machinery/computer/communications/attackby(obj/I, mob/user, params)
	if(istype(I, /obj/item/weapon/card/id))
		attack_hand(user)
	else
		..()
	return

/obj/machinery/computer/communications/emag_act(mob/user)
	if(!emagged)
		src.emagged = 1
		if(authenticated == 1)
			authenticated = 2
		user << "You scramble the communication routing circuits."

/obj/machinery/computer/communications/attack_hand(mob/user)
	if(..())
		return
	if (src.z > 6)
		user << "Unable to establish a connection: \black You're too far away from the station!"
		return

	user.set_machine(src)
	var/dat = ""
	if(SSshuttle.emergency.mode == SHUTTLE_CALL)
		var/timeleft = SSshuttle.emergency.timeLeft()
		dat += "Emergency shuttle\n
\nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"

	var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))

	if (istype(user, /mob/living/silicon))
		var/dat2 = src.interact_ai(user) // give the AI a different interact proc to limit its access
		if(dat2)
			dat +=  dat2
			//user << browse(dat, "window=communications;size=400x500")
			//onclose(user, "communications")

			popup.set_content(dat)
			popup.open()
		return

	switch(src.state)
		if(STATE_DEFAULT)
			if (src.authenticated)
				if(SSshuttle.emergencyLastCallLoc)
					dat += "
Most recent shuttle call/recall traced to: [format_text(SSshuttle.emergencyLastCallLoc.name)]"
				else
					dat += "
Unable to trace most recent shuttle call/recall signal."
				dat += "
Logged in as: [auth_id]"
				dat += "
"
				dat += "
\[ Log Out \]
"
				dat += "
General Functions"
				dat += "
\[ Message List \]"
				switch(SSshuttle.emergency.mode)
					if(SHUTTLE_IDLE, SHUTTLE_RECALL)
						dat += "
\[ Call Emergency Shuttle \]"
					else
						dat += "
\[ Cancel Shuttle Call \]"

				dat += "
\[ Set Status Display \]"
				if (src.authenticated==2)
					dat += "

Captain Functions"
					dat += "
\[ Make a Captain's Announcement \]"
					dat += "
\[ Change Alert Level \]"
					dat += "
\[ Emergency Maintenance Access \]"
					dat += "
\[ Request Nuclear Authentication Codes \]"
					if(src.emagged == 0)
						dat += "
\[ Send Message to Centcom \]"
					else
						dat += "
\[ Send Message to \[UNKNOWN\] \]"
						dat += "
\[ Restore Backup Routing Data \]"
			else
				dat += "
\[ Log In \]"
		if(STATE_CALLSHUTTLE)
			dat += get_call_shuttle_form()
		if(STATE_CANCELSHUTTLE)
			dat += get_cancel_shuttle_form()
		if(STATE_MESSAGELIST)
			dat += "Messages:"
			for(var/i = 1; i<=src.messagetitle.len; i++)
				dat += "
[src.messagetitle[i]]"
		if(STATE_VIEWMESSAGE)
			if (src.currmsg)
				dat += "[src.messagetitle[src.currmsg]]

[src.messagetext[src.currmsg]]"
				if (src.authenticated)
					dat += "

\[ Delete \]"
			else
				src.state = STATE_MESSAGELIST
				src.attack_hand(user)
				return
		if(STATE_DELMESSAGE)
			if (src.currmsg)
				dat += "Are you sure you want to delete this message? \[ OK | Cancel \]"
			else
				src.state = STATE_MESSAGELIST
				src.attack_hand(user)
				return
		if(STATE_STATUSDISPLAY)
			dat += "Set Status Displays
"
			dat += "\[ Clear \]
"
			dat += "\[ Shuttle ETA \]
"
			dat += "\[ Message \]"
			dat += "

 Line 1: [ stat_msg1 ? stat_msg1 : "(none)"]"
			dat += "
 Line 2: [ stat_msg2 ? stat_msg2 : "(none)"]

"
			dat += "\[ Alert: None |"
			dat += " Red Alert |"
			dat += " Lockdown |"
			dat += " Biohazard \]

"
		if(STATE_ALERT_LEVEL)
			dat += "Current alert level: [get_security_level()]
"
			if(security_level == SEC_LEVEL_DELTA)
				dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate."
			else
				dat += "Blue
"
				dat += "Green"
		if(STATE_CONFIRM_LEVEL)
			dat += "Current alert level: [get_security_level()]
"
			dat += "Confirm the change to: [num2seclevel(tmp_alertlevel)]
"
			dat += "Swipe ID to confirm change.
"
		if(STATE_TOGGLE_EMERGENCY)
			if(emergency_access == 1)
				dat += "Emergency Maintenance Access is currently ENABLED"
				dat += "
Restore maintenance access restrictions?
\[ OK | Cancel \]"
			else
				dat += "Emergency Maintenance Access is currently DISABLED"
				dat += "
Lift access restrictions on maintenance and external airlocks?
\[ OK | Cancel \]"

	dat += "

\[ [(src.state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]"
	//user << browse(dat, "window=communications;size=400x500")
	//onclose(user, "communications")
	popup.set_content(dat)
	popup.open()

/obj/machinery/computer/communications/proc/get_javascript_header(form_id)
	var/dat = {""}
	return dat

/obj/machinery/computer/communications/proc/get_call_shuttle_form(ai_interface = 0)
	var/form_id = "callshuttle"
	var/dat = get_javascript_header(form_id)
	dat += "<form name='callshuttle' id='[form_id]' action='?src=\ref[src]' method='get' style='display: inline'>"
	dat += "<input type='hidden' name='src' value='\ref[src]'>"
	dat += "<input type='hidden' name='operation' value='[ai_interface ? "ai-callshuttle2" : "callshuttle2"]'>"
	dat += "Nature of emergency:
 <input type='text' id='reasonfield' name='call' style='width:250px; background-color:#FFDDDD; onkeydown='getLength() onkeyup='getLength()' onkeypress='getLength()'>"
	dat += "
Are you sure you want to call the shuttle? \[ Call \]"
	return dat

/obj/machinery/computer/communications/proc/get_cancel_shuttle_form()
	var/form_id = "cancelshuttle"
	var/dat = get_javascript_header(form_id)
	dat += "<form name='cancelshuttle' id='[form_id]' action='?src=\ref[src]' method='get' style='display: inline'>"
	dat += "<input type='hidden' name='src' value='\ref[src]'>"
	dat += "<input type='hidden' name='operation' value='cancelshuttle2'>"

	dat += "
Are you sure you want to cancel the shuttle? \[ Cancel \]"
	return dat

/obj/machinery/computer/communications/proc/interact_ai(mob/living/silicon/ai/user)
	var/dat = ""
	switch(src.aistate)
		if(STATE_DEFAULT)
			if(SSshuttle.emergencyLastCallLoc)
				dat += "
Latest emergency signal trace attempt successful.
Last signal origin: [format_text(SSshuttle.emergencyLastCallLoc.name)].
"
			else
				dat += "
Latest emergency signal trace attempt failed.
"
			if(authenticated)
				dat += "Current login: [auth_id]"
			else
				dat += "Current login: None"
			dat += "

General Functions"
			dat += "
\[ Message List \]"
			if(SSshuttle.emergency.mode <= SHUTTLE_IDLE)
				dat += "
\[ Call Emergency Shuttle \]"
			dat += "
\[ Set Status Display \]"
			dat += "

Special Functions"
			dat += "
\[ Make an Announcement \]"
			dat += "
\[ Change Alert Level \]"
			dat += "
\[ Emergency Maintenance Access \]"
		if(STATE_CALLSHUTTLE)
			dat += get_call_shuttle_form(1)
		if(STATE_MESSAGELIST)
			dat += "Messages:"
			for(var/i = 1; i<=src.messagetitle.len; i++)
				dat += "
[src.messagetitle[i]]"
		if(STATE_VIEWMESSAGE)
			if (src.aicurrmsg)
				dat += "[src.messagetitle[src.aicurrmsg]]

[src.messagetext[src.aicurrmsg]]"
				dat += "

\[ Delete \]"
			else
				src.aistate = STATE_MESSAGELIST
				src.attack_hand(user)
				return null
		if(STATE_DELMESSAGE)
			if(src.aicurrmsg)
				dat += "Are you sure you want to delete this message? \[ OK | Cancel \]"
			else
				src.aistate = STATE_MESSAGELIST
				src.attack_hand(user)
				return

		if(STATE_STATUSDISPLAY)
			dat += "Set Status Displays
"
			dat += "\[ Clear \]
"
			dat += "\[ Shuttle ETA \]
"
			dat += "\[ Message \]"
			dat += "

 Line 1: [ stat_msg1 ? stat_msg1 : "(none)"]"
			dat += "
 Line 2: [ stat_msg2 ? stat_msg2 : "(none)"]

"
			dat += "\[ Alert: None |"
			dat += " Red Alert |"
			dat += " Lockdown |"
			dat += " Biohazard \]

"

		if(STATE_ALERT_LEVEL)
			dat += "Current alert level: [get_security_level()]
"
			if(security_level == SEC_LEVEL_DELTA)
				dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate."
			else
				dat += "Blue
"
				dat += "Green"

		if(STATE_TOGGLE_EMERGENCY)
			if(emergency_access == 1)
				dat += "Emergency Maintenance Access is currently ENABLED"
				dat += "
Restore maintenance access restrictions?
\[ OK | Cancel \]"
			else
				dat += "Emergency Maintenance Access is currently DISABLED"
				dat += "
Lift access restrictions on maintenance and external airlocks?
\[ OK | Cancel \]"

	dat += "

\[ [(src.aistate != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]"
	return dat

/obj/machinery/computer/communications/proc/make_announcement(mob/living/user, is_silicon)
	var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?")
	if(!input || !user.canUseTopic(src))
		return
	if(is_silicon)
		minor_announce(input,"[user.name] Announces:")
		ai_message_cooldown = 1
		spawn(600)//One minute cooldown
			ai_message_cooldown = 0
	else
		priority_announce(html_decode(input), null, 'sound/misc/announce.ogg', "Captain")
		message_cooldown = 1
		spawn(600)//One minute cooldown
			message_cooldown = 0
	log_say("[key_name(user)] has made a priority announcement: [input]")
	message_admins("[key_name_admin(user)] has made a priority announcement.")

/obj/machinery/computer/communications/proc/post_status(command, data1, data2)

	var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)

	if(!frequency) return

	var/datum/signal/status_signal = new
	status_signal.source = src
	status_signal.transmission_method = 1
	status_signal.data["command"] = command

	switch(command)
		if("message")
			status_signal.data["msg1"] = data1
			status_signal.data["msg2"] = data2
		if("alert")
			status_signal.data["picture_state"] = data1

	frequency.post_signal(src, status_signal)

/obj/machinery/computer/communications/Destroy()
	shuttle_caller_list -= src
	SSshuttle.autoEvac()
	return ..()

/obj/machinery/computer/communications/proc/overrideCooldown()
	var/obj/item/weapon/circuitboard/communications/CM = circuit
	CM.lastTimeUsed = 0

license: mit


code:
/obj/machinery/computer
	name = "computer"
	icon = 'icons/obj/computer.dmi'
	icon_state = "computer"
	density = 1
	anchored = 1
	use_power = 1
	idle_power_usage = 300
	active_power_usage = 300
	var/obj/item/weapon/circuitboard/circuit = null // if circuit==null, computer can't disassembly
	var/processing = 0
	var/brightness_on = 2
	var/icon_keyboard = "generic_key"
	var/icon_screen = "generic"

/obj/machinery/computer/New(location, obj/item/weapon/circuitboard/C)
	..(location)
	if(C && istype(C))
		circuit = C
	else
		if(circuit)
			circuit = new circuit(null)
	power_change()
	update_icon()

/obj/machinery/computer/initialize()
	power_change()

/obj/machinery/computer/process()
	if(stat & (NOPOWER|BROKEN))
		return 0
	return 1

/obj/machinery/computer/emp_act(severity)
	if(prob(20/severity)) set_broken()
	..()

/obj/machinery/computer/ex_act(severity, target)
	if(target == src)
		qdel(src)
		return
	switch(severity)
		if(1)
			qdel(src)
			return
		if(2)
			if (prob(25))
				qdel(src)
				return
			if (prob(50))
				verbs.Cut()
				set_broken()
		if(3)
			if (prob(25))
				verbs.Cut()
				set_broken()
		else
	return

/obj/machinery/computer/bullet_act(obj/item/projectile/Proj)
	if(prob(Proj.damage))
		if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
			set_broken()
	..()

/obj/machinery/computer/update_icon()
	overlays.Cut()
	if(stat & NOPOWER)
		overlays += "[icon_keyboard]_off"
		return
	overlays += icon_keyboard
	if(stat & BROKEN)
		overlays += "[icon_state]_broken"
	else
		overlays += icon_screen

/obj/machinery/computer/power_change()
	..()
	if(stat & NOPOWER)
		SetLuminosity(0)
	else
		SetLuminosity(brightness_on)
	update_icon()
	return

/obj/machinery/computer/proc/set_broken()
	if(circuit) //no circuit, no breaking
		stat |= BROKEN
		update_icon()
	return

/obj/machinery/computer/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/weapon/screwdriver) && circuit && !(flags&NODECONSTRUCT))
		playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
		user << " You start to disconnect the monitor..."
		if(do_after(user, 20/I.toolspeed, target = src))
			var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
			A.circuit = circuit
			A.anchored = 1
			circuit = null
			for (var/obj/C in src)
				C.loc = src.loc
			if (src.stat & BROKEN)
				user << "The broken glass falls out."
				new /obj/item/weapon/shard( src.loc )
				A.state = 3
				A.icon_state = "3"
			else
				user << "You disconnect the monitor."
				A.state = 4
				A.icon_state = "4"
			qdel(src)
	return

/obj/machinery/computer/attack_paw(mob/living/user)
	user.do_attack_animation(src)
	if(circuit)
		if(prob(10))
			user.visible_message("[user.name] smashes the [src.name] with its paws.",\
			"You smash the [src.name] with your paws.",\
			"You hear a smashing sound.")
			set_broken()
			return
	user.visible_message("[user.name] smashes against the [src.name] with its paws.",\
	"You smash against the [src.name] with your paws.",\
	"You hear hear a clicking sound.")

/obj/machinery/computer/attack_alien(mob/living/user)
	user.do_attack_animation(src)
	if(circuit)
		if(prob(80))
			user.visible_message("[user.name] smashes the [src.name] with its claws.",\
			"You smash the [src.name] with your claws.",\
			"You hear a smashing sound.")
			set_broken()
			return
	user.visible_message("[user.name] smashes against the [src.name] with its claws.",\
	"You smash against the [src.name] with your claws.",\
	"You hear a clicking sound.")


code:
body
{
	padding-left: 53%;
	cursor: default;
}

#ntbgcenter
{
	background-position: 550px 0px !important;
}

#minimap
{
	position: fixed;
	top: 8px;
	left: 8px;
	border: 2px inset #888;
	overflow: hidden;
	min-width: 480px;
	min-height: 480px;
	width: 53%;
	height: 100%;
	max-width: 480px;
	max-height: 480px;
}

#textbased
{
	width: 100%;
	padding-left: 20px;
}

#textbased table
{
	min-width: 380px;
	width: 100%;
	table-layout: fixed;
}

#textbased td
{
	vertical-align: top;
	padding: 2px;
}

#textbased tbody td
{
	transition: .2s all;
}

#textbased tbody tr:hover td, #textbased tbody tr.hover td
{
	background-color: #515151;
}

#textarea:after
{
	content: "";
	clear: both;
}

.health
{
	width: 16px;
	height: 16px;
	background-color: #FFF;
	border: 1px solid #434343;
	position: relative;
	top: 2px;
}

.health-5 { background-color: #17d568; }
.health-4 { background-color: #2ecc71; }
.health-3 { background-color: #e67e22; }
.health-2 { background-color: #ed5100; }
.health-1 { background-color: #e74c3c; }
.health-0 { background-color: #ed2814; }

.health > div
{
	margin-left: 20px;
	margin-top: -4px;
}

.tt
{
	position: relative;
	display: inline-block;
	height: 16px;
}

.tt > div
{
	display: none;
}

.tt:hover > div
{
	position: absolute;
	bottom: -30px;
	left: 50%;
	margin-left: -64px;

	display: block;
	width: 128px;
	height: 24px;
	border: 1px solid #313131;
	background-color: #434343;
	padding: 4px;
	z-index: 999;
	text-align: center;
}

.tt > div > span
{
	position: relative;
	top: -2px;
}

.dot
{
	position: absolute;
	width: 3px;
	height: 3px;
	margin-top: 0px;
	margin-left: 0px;
	border: 1px solid transparent;
}

.dot.active
{
	z-index: 9999 !important;
	width: 8px;
	height: 8px;
	margin-top: -2px;
	margin-left: -3px;
}

.zoom
{
	position: fixed;
	left: 53%;
	top: 10px;
	display: block;
	width: 24px;
	height: 24px;
	text-align: center;
	margin-left: 20px !important;
}

.zoom.in
{
	margin-left: -3px !important;
}


code:
/obj/machinery/computer/crew
	name = "crew monitoring console"
	desc = "Used to monitor active health sensors built into most of the crew's uniforms."
	icon_screen = "crew"
	icon_keyboard = "med_key"
	use_power = 1
	idle_power_usage = 250
	active_power_usage = 500
	circuit = "/obj/item/weapon/circuitboard/crew"

/obj/machinery/computer/crew/attack_ai(mob/user)
	if(stat & (BROKEN|NOPOWER))
		return
	crewmonitor.show(user)

/obj/machinery/computer/crew/attack_hand(mob/user)
	if(..())
		return
	if(stat & (BROKEN|NOPOWER))
		return
	crewmonitor.show(user)

var/global/datum/crewmonitor/crewmonitor = new

/datum/crewmonitor
	var/list/jobs
	var/list/interfaces
	var/list/data

/datum/crewmonitor/New()
	. = ..()

	var/list/jobs = new/list()
	jobs["Captain"] = 00
	jobs["Head of Personnel"] = 50
	jobs["Head of Security"] = 10
	jobs["Warden"] = 11
	jobs["Security Officer"] = 12
	jobs["Detective"] = 13
	jobs["Chief Medical Officer"] = 20
	jobs["Chemist"] = 21
	jobs["Geneticist"] = 22
	jobs["Virologist"] = 23
	jobs["Medical Doctor"] = 24
	jobs["Research Director"] = 30
	jobs["Scientist"] = 31
	jobs["Roboticist"] = 32
	jobs["Chief Engineer"] = 40
	jobs["Station Engineer"] = 41
	jobs["Atmospheric Technician"] = 42
	jobs["Quartermaster"] = 51
	jobs["Shaft Miner"] = 52
	jobs["Cargo Technician"] = 53
	jobs["Bartender"] = 61
	jobs["Cook"] = 62
	jobs["Botanist"] = 63
	jobs["Librarian"] = 64
	jobs["Chaplain"] = 65
	jobs["Clown"] = 66
	jobs["Mime"] = 67
	jobs["Janitor"] = 68
	jobs["Lawyer"] = 69
	jobs["Admiral"] = 200
	jobs["Centcom Commander"] = 210
	jobs["Custodian"] = 211
	jobs["Medical Officer"] = 212
	jobs["Research Officer"] = 213
	jobs["Emergency Response Team Commander"] = 220
	jobs["Security Response Officer"] = 221
	jobs["Engineer Response Officer"] = 222
	jobs["Medical Response Officer"] = 223
	jobs["Assistant"] = 999 //Unknowns/custom jobs should appear after civilians, and before assistants

	src.jobs = jobs
	src.interfaces = list()
	src.data = list()
	register_asset("crewmonitor.js",'crew.js')
	register_asset("crewmonitor.css",'crew.css')

/datum/crewmonitor/Destroy()
	if (src.interfaces)
		for (var/datum/html_interface/hi in interfaces)
			qdel(hi)
		src.interfaces = null

	return ..()

/datum/crewmonitor/proc/show(mob/mob, z)
	if (mob.client)
		sendResources(mob.client)
	if (!z) z = mob.z

	if (z > 0 && src.interfaces)
		var/datum/html_interface/hi

		if (!src.interfaces["[z]"])
			src.interfaces["[z]"] = new/datum/html_interface/nanotrasen(src, "Crew Monitoring", 900, 540, "<link rel=\"stylesheet\" type=\"text/css\" href=\"crewmonitor.css\" />")

			hi = src.interfaces["[z]"]

			hi.updateContent("content", "
+-

")

			src.update(z, TRUE)
		else
			hi = src.interfaces["[z]"]

		// Debugging purposes
		mob << browse_rsc(file("code/game/machinery/computer/crew.js"), "crew.js")
		mob << browse_rsc(file("code/game/machinery/computer/crew.css"), "crew.css")

		hi = src.interfaces["[z]"]
		hi.show(mob)
		src.updateFor(mob, hi, z)

/datum/crewmonitor/proc/updateFor(hclient_or_mob, datum/html_interface/hi, z)
	// This check will succeed if updateFor is called after showing to the player, but will fail
	// on regular updates. Since we only really need this once we don't care if it fails.
	hi.callJavaScript("clearAll", null, hclient_or_mob)

	for (var/list/L in data)
		hi.callJavaScript("add", L, hclient_or_mob)

	hi.callJavaScript("onAfterUpdate", null, hclient_or_mob)

/datum/crewmonitor/proc/update(z, ignore_unused = FALSE)
	if (src.interfaces["[z]"])
		var/datum/html_interface/hi = src.interfaces["[z]"]

		if (ignore_unused || hi.isUsed())
			var/list/results = list()
			var/obj/item/clothing/under/U
			var/obj/item/weapon/card/id/I
			var/turf/pos
			var/ijob
			var/name
			var/assignment
			var/dam1
			var/dam2
			var/dam3
			var/dam4
			var/area
			var/pos_x
			var/pos_y
			var/life_status

			for(var/mob/living/carbon/human/H in mob_list)
				// Check if their z-level is correct and if they are wearing a uniform.
				// Accept H.z==0 as well in case the mob is inside an object.
				if ((H.z == 0 || H.z == z) && istype(H.w_uniform, /obj/item/clothing/under))
					U = H.w_uniform

					// Are the suit sensors on?
					if (U.has_sensor && U.sensor_mode)
						pos = H.z == 0 || U.sensor_mode == 3 ? get_turf(H) : null

						// Special case: If the mob is inside an object confirm the z-level on turf level.
						if (H.z == 0 && (!pos || pos.z != z)) continue

						I = H.wear_id ? H.wear_id.GetID() : null

						if (I)
							name = I.registered_name
							assignment = I.assignment
							ijob = jobs[I.assignment]
						else
							name = "Unknown"
							assignment = ""
							ijob = 80

						if (U.sensor_mode >= 1) life_status = (!H.stat ? "true" : "false")
						else                    life_status = null

						if (U.sensor_mode >= 2)
							dam1 = round(H.getOxyLoss(),1)
							dam2 = round(H.getToxLoss(),1)
							dam3 = round(H.getFireLoss(),1)
							dam4 = round(H.getBruteLoss(),1)
						else
							dam1 = null
							dam2 = null
							dam3 = null
							dam4 = null

						if (U.sensor_mode >= 3)
							if (!pos) pos = get_turf(H)
							var/area/player_area = get_area(H)

							area = format_text(player_area.name)
							pos_x = pos.x
							pos_y = pos.y
						else
							area = null
							pos_x = null
							pos_y = null

						results[++results.len] = list(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, pos_x, pos_y, H.can_track(null))

			src.data = results
			src.updateFor(null, hi, z) // updates for everyone

/datum/crewmonitor/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
	var/z = ""

	for (z in src.interfaces)
		if (src.interfaces[z] == hi) break

	if (hclient.client.mob && hclient.client.mob.stat == 0 && hclient.client.mob.z == text2num(z))
		if (isAI(hclient.client.mob)) return TRUE
		else if (isrobot(hclient.client.mob))
			return (locate(/obj/machinery/computer/crew, range(world.view, hclient.client.mob))) || (locate(/obj/item/device/sensor_device, hclient.client.mob.contents))
		else
			return (locate(/obj/machinery/computer/crew, range(1, hclient.client.mob))) || (locate(/obj/item/device/sensor_device, hclient.client.mob.contents))
	else
		return FALSE

/datum/crewmonitor/Topic(href, href_list[], datum/html_interface_client/hclient)
	if (istype(hclient))
		if (hclient && hclient.client && hclient.client.mob && isAI(hclient.client.mob))
			var/mob/living/silicon/ai/AI = hclient.client.mob

			switch (href_list["action"])
				if ("select_person")
					AI.ai_camera_track(href_list["name"])

				if ("select_position")
					var/x = text2num(href_list["x"])
					var/y = text2num(href_list["y"])
					var/turf/tile = locate(x, y, AI.z)

					var/obj/machinery/camera/C = locate(/obj/machinery/camera) in range(5, tile)

					if (!C) C = locate(/obj/machinery/camera) in urange(10, tile)
					if (!C) C = locate(/obj/machinery/camera) in urange(15, tile)

					if (C)
						var/turf/current_loc = AI.eyeobj.loc

						spawn(min(30, get_dist(get_turf(C), AI.eyeobj) / 4))
							if (AI && AI.eyeobj && current_loc == AI.eyeobj.loc)
								AI.switchCamera(C)

/mob/living/carbon/human/Move()
	if (src.w_uniform)
		var/old_z = src.z

		. = ..()

		if (old_z != src.z) crewmonitor.queueUpdate(old_z)
		crewmonitor.queueUpdate(src.z)
	else
		return ..()

/datum/crewmonitor/proc/queueUpdate(z)
	addtimer(crewmonitor, "update", 5, TRUE, z)

/datum/crewmonitor/proc/sendResources(var/client/client)
	send_asset(client, "crewmonitor.js")
	send_asset(client, "crewmonitor.css")
	SSminimap.send(client)


code:
/*!
 * jQuery scrollintoview() plugin and :scrollable selector filter
 *
 * Version 1.8 (14 Jul 2011)
 * Requires jQuery 1.4 or newer
 */

(function ($) {
    var converter = {
        vertical: { x: false, y: true },
        horizontal: { x: true, y: false },
        both: { x: true, y: true },
        x: { x: true, y: false },
        y: { x: false, y: true }
    };

    var settings = {
        duration: "fast",
        direction: "both"
    };

    var rootrx = /^(?:html)$/i;

    // gets border dimensions
    var borders = function (domElement, styles) {
        styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
        var px = document.defaultView && document.defaultView.getComputedStyle ? true : false;
        var b = {
            top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0),
            left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0),
            bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0),
            right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0)
        };
        return {
            top: b.top,
            left: b.left,
            bottom: b.bottom,
            right: b.right,
            vertical: b.top + b.bottom,
            horizontal: b.left + b.right
        };
    };

    var dimensions = function ($element) {
        var win = $(window);
        var isRoot = rootrx.test($element[0].nodeName);
        return {
            border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]),
            scroll: {
                top: (isRoot ? win : $element).scrollTop(),
                left: (isRoot ? win : $element).scrollLeft()
            },
            scrollbar: {
                right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth,
                bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight
            },
            rect: (function () {
                var r = $element[0].getBoundingClientRect();
                return {
                    top: isRoot ? 0 : r.top,
                    left: isRoot ? 0 : r.left,
                    bottom: isRoot ? $element[0].clientHeight : r.bottom,
                    right: isRoot ? $element[0].clientWidth : r.right
                };
            })()
        };
    };

    $.fn.extend({
        scrollintoview: function (options) {
            /// Scrolls the first element in the set into view by scrolling its closest scrollable parent.
            /// <param name="options" type="Object">Additional options that can configure scrolling:
            ///        duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
            ///        direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
            ///        complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
            /// </param>
            /// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>

            options = $.extend({}, settings, options);
            options.direction = converter[typeof (options.direction) === "string" && options.direction.toLowerCase()] || converter.both;

            var dirStr = "";
            if (options.direction.x === true) dirStr = "horizontal";
            if (options.direction.y === true) dirStr = dirStr ? "both" : "vertical";

            var el = this.eq(0);
            var scroller = el.closest(":scrollable(" + dirStr + ")");

            // check if there's anything to scroll in the first place
            if (scroller.length > 0)
            {
                scroller = scroller.eq(0);

                var dim = {
                    e: dimensions(el),
                    s: dimensions(scroller)
                };

                var rel = {
                    top: dim.e.rect.top - (dim.s.rect.top + dim.s.border.top),
                    bottom: dim.s.rect.bottom - dim.s.border.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom,
                    left: dim.e.rect.left - (dim.s.rect.left + dim.s.border.left),
                    right: dim.s.rect.right - dim.s.border.right - dim.s.scrollbar.right - dim.e.rect.right
                };

                var animOptions = {};

                // vertical scroll
                if (options.direction.y === true)
                {
                    if (rel.top < 0)
                    {
                        animOptions.scrollTop = dim.s.scroll.top + rel.top;
                    }
                    else if (rel.top > 0 && rel.bottom < 0)
                    {
                        animOptions.scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom);
                    }
                }

                // horizontal scroll
                if (options.direction.x === true)
                {
                    if (rel.left < 0)
                    {
                        animOptions.scrollLeft = dim.s.scroll.left + rel.left;
                    }
                    else if (rel.left > 0 && rel.right < 0)
                    {
                        animOptions.scrollLeft = dim.s.scroll.left + Math.min(rel.left, -rel.right);
                    }
                }

                // scroll if needed
                if (!$.isEmptyObject(animOptions))
                {
                    if (rootrx.test(scroller[0].nodeName))
                    {
                        scroller = $("html,body");
                    }
                    scroller
                        .animate(animOptions, options.duration)
                        .eq(0) // we want function to be called just once (ref. "html,body")
                        .queue(function (next) {
                            $.isFunction(options.complete) && options.complete.call(scroller[0]);
                            next();
                        });
                }
                else
                {
                    // when there's nothing to scroll, just call the "complete" function
                    $.isFunction(options.complete) && options.complete.call(scroller[0]);
                }
            }

            // return set back
            return this;
        }
    });

    var scrollValue = {
        auto: true,
        scroll: true,
        visible: false,
        hidden: false
    };

    $.extend($.expr[":"], {
        scrollable: function (element, index, meta, stack) {
            var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;
            var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);
            var overflow = {
                x: scrollValue[styles.overflowX.toLowerCase()] || false,
                y: scrollValue[styles.overflowY.toLowerCase()] || false,
                isRoot: rootrx.test(element.nodeName)
            };

            // check if completely unscrollable (exclude HTML element because it's special)
            if (!overflow.x && !overflow.y && !overflow.isRoot)
            {
                return false;
            }

            var size = {
                height: {
                    scroll: element.scrollHeight,
                    client: element.clientHeight
                },
                width: {
                    scroll: element.scrollWidth,
                    client: element.clientWidth
                },
                // check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
                scrollableX: function () {
                    return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;
                },
                scrollableY: function () {
                    return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;
                }
            };
            return direction.y && size.scrollableY() || direction.x && size.scrollableX();
        }
    });
})(jQuery);

/*!
 * Crew manifest script
 */

var minimap_height = 480;
var scale_x;
var scale_y;
var zoom_factor = null;
var minimap_mousedown = false;
var minimap_mousedown_scrollLeft;
var minimap_mousedown_scrollTop;
var minimap_mousedown_clientX;
var minimap_mousedown_clientY;
var minimap_mousedown_counter = 0;

function disableSelection(){ return false; };

$(window).on("onUpdateContent", function()
{
	$("#textbased").html("
<colgroup><col /><col style=\"width: 24px;\" class=\"colhealth\" /><col style=\"width: 180px;\" /></colgroup>

Name

Position

");

	$("#minimap").append("");

	$("body")[0].onselectstart = disableSelection;

	$("#minimap").on("click", function(e)
	{
		if (!$(e.target).is(".zoom,.dot"))
		{
			var x		= ((((e.clientX + this.scrollLeft - 8) / scale_x) / tile_size) + 1).toFixed(0);
			var y		= ((maxy - (((e.clientY + this.scrollTop - 8) / scale_y) / tile_size)) + 1).toFixed(0);

			window.location.href = "byond://?src=" + hSrc + "&action=select_position&x=" + x + "&y=" + y;
		}
	}).on("mousedown", function(e)
	{
		minimap_mousedown_scrollLeft = this.scrollLeft;
		minimap_mousedown_scrollTop = this.scrollTop;
		minimap_mousedown_clientX = e.clientX;
		minimap_mousedown_clientY = e.clientY;

		var c = ++minimap_mousedown_counter;
		setTimeout(function()
		{
			if (c == minimap_mousedown_counter)
			{
				minimap_mousedown = true;
				$("#minimap").css("cursor", "move");
			}
		}, 100);
	});

	$(document).on("mousemove", function(e)
	{
		if (minimap_mousedown)
		{
			var offsetX = minimap_mousedown_clientX - e.clientX;
			var offsetY = minimap_mousedown_clientY - e.clientY;

			var minimap = document.getElementById("minimap");
			minimap.scrollLeft = minimap_mousedown_scrollLeft + offsetX;
			minimap.scrollTop = minimap_mousedown_scrollTop + offsetY;
		}
	}).on("mouseup", function()
	{
		++minimap_mousedown_counter;
		if (minimap_mousedown)
		{
			document.body.focus();
			minimap_mousedown = false;
			$("#minimap").css("cursor", "");
		}
	});

	$(window).on("resize", onResize);

	scaleMinimap(1.00);
});

function zoomIn()
{
	scaleMinimap(Math.min(6.00, zoom_factor + 1.00));
}

function zoomOut()
{
	scaleMinimap(Math.max(1.00, zoom_factor - 1.00));
}

function scaleMinimap(factor)
{
	var $minimap					= $("#minimap");

	if (factor != zoom_factor)
	{
		zoom_factor					= factor;

		var old_map_width			= $minimap.width();
		var old_map_height			= $minimap.height();
		var old_canvas_size			= $("#minimap > img").height(); // height is assumed to be the same
		var new_canvas_size			= minimap_height * factor;      // ditto

		var old_scrollLeft			= $minimap[0].scrollLeft;
		var old_scrollTop			= $minimap[0].scrollTop;

		var old_factor				= old_canvas_size / minimap_height;
		var diff_factor				= factor - old_factor;

		var old_centerX				= ((old_map_width  / 2) * diff_factor) + old_scrollLeft;
		var old_centerY				= ((old_map_height / 2) * diff_factor) + old_scrollTop;

		$("#minimap > img").css("height", new_canvas_size + "px");
		$minimap.css("max-width", new_canvas_size + "px");

		var new_map_width			= $minimap.width();
		var new_map_height			= $minimap.height();

		var new_centerX				= (new_map_width  / 2) + old_centerX;
		var new_centerY				= (new_map_height / 2) + old_centerY;

		var scrollLeft				= new_centerX - (new_map_width  / 2);
		var scrollTop				= new_centerY - (new_map_height / 2);

		scale_x						= new_canvas_size / (maxx * tile_size);
		scale_y						= new_canvas_size / (maxy * tile_size);

		onResize();

		$minimap[0].scrollLeft		= scrollLeft;
		$minimap[0].scrollTop		= scrollTop;

		$(".dot").each(function()
		{
			var $this				= $(this);
			var tx					= translateX(parseInt($this.attr("data-x")));
			var ty					= translateY(parseInt($this.attr("data-y")));

			// Workaround for IE bug where it doesn't modify the positions.
			setTimeout(function(){ $this.css({ "top": ty + "px", "left": tx + "px" });}, 0);
		});
	}
}

function onResize()
{
	if (zoom_factor == 1.00)
	{
		$(".zoom").css("left", "442px");
		$("#minimap").css("max-height", Math.min($(window).height() - 16, 480) + "px");
	}
	else
	{
		$(".zoom").css("left", ($("#minimap").width() - 34) + "px");
		$("#minimap").css("max-height", Math.min($(window).height() - 16, $("#minimap > img").height()) + "px");
	}

	if (expandHealth())
	{
		$(".colhealth").css("width", "150px");
		$(".health").removeClass("tt");
	}
	else
	{
		$(".colhealth").css("width", "24px");
		$(".health").addClass("tt");
	}

	$("body").css("padding-left", Math.min($(window).width() - 400, $("#minimap").width() - 10) + "px");
}

function expandHealth()
{
	return $("#textbased").width() > 510;
}

var updateMap = true;

function switchTo(i)
{
	if (i == 1)
	{
		$("#minimap").hide();
		$("#textbased").show();
	}
	else
	{
		$("#textbased").hide();
		$("#minimap").show();
	}
}

var orig_scrollTop = 0;

function clearAll()
{
	orig_scrollTop = $(window).scrollTop();
	$("#textbased-tbody").empty();
	$("#minimap .dot").remove();
}

function onAfterUpdate()
{
	$(window).scrollTop(orig_scrollTop);
}

function isHead(ijob)
{
	return (ijob % 10 == 0); // head roles always end in 0
}

function getColor(ijob)
{
	if		(ijob == 0)					{ return "#C06616"; } // captain
	else if	(ijob >= 10 && ijob < 20)	{ return "#E74C3C"; } // security
	else if (ijob >= 20 && ijob < 30)	{ return "#3498DB"; } // medical
	else if (ijob >= 30 && ijob < 40)	{ return "#9B59B6"; } // science
	else if (ijob >= 40 && ijob < 50)	{ return "#F1C40F"; } // engineering
	else if (ijob >= 50 && ijob < 60)	{ return "#F39C12"; } // cargo
	else if (ijob >= 200 && ijob < 230)	{ return "#00C100"; } // Centcom
	else								{ return "#C38312"; } // other / unknown
}

function add(name, assignment, ijob, life_status, dam1, dam2, dam3, dam4, area, pos_x, pos_y, in_range)
{
	try							{ ijob = parseInt(ijob); }
	catch (ex)					{ ijob = 0; }

	var ls						= "";

	if (life_status === null)	{ ls = (life_status ? "Deceased" : "Living"); }

	var healthHTML				= "";

	if (dam1 != "" || dam2 != "" || dam3 != "" || dam4 != "")
	{
		var avg_dam				= parseInt(dam1) + parseInt(dam2) + parseInt(dam3) + parseInt(dam4);
		var i;

		if		(avg_dam <= 0)	{ i = 5; }
		else if (avg_dam <= 25)	{ i = 4; }
		else if (avg_dam <= 50)	{ i = 3; }
		else if (avg_dam <= 75)	{ i = 2; }
		else					{ i = 0; }

		healthHTML = "

(" + dam1 + "/" + dam2 + "/" + dam3 + "/" + dam4 + ")

";
	}
	else
	{
		healthHTML = "

Not Available

";
	}

	var trElem					= $("

").attr("data-ijob", ijob);
	var tdElem;
	var spanElem;

	tdElem						= $("	");

	var italics = false;

	if (name.length >= 7 && name.substring(0, 3) == "")
	{
		name = name.substring(3, name.length - 4);
		italics = true;
	}

	spanElem					= $("").text(name);

	if (italics)
	{
		spanElem.css("font-style", "italic");
	}

	if (isHead(ijob))			{ spanElem.css("font-weight", "bold"); }

	var color					= getColor(ijob);

	if (color)					{ spanElem.css("color", color); }

	tdElem.append(spanElem);

	if (assignment)				{ tdElem.append($("").text(" (" + assignment + ")")); }

	trElem.append(tdElem);

	tdElem						= $("	");
	tdElem.html(healthHTML);

	trElem.append(tdElem);

	tdElem						= $("	");

	if (area && pos_x && pos_y)
	{
		tdElem.append($("

").text(area).addClass("tt").append($("

").append($("").text("(" + pos_x + ", " + pos_y + ")"))));
		tdElem.css("cursor", "pointer").on("click", function()
		{
			window.clipboardData.setData("Text", pos_x + ", " + pos_y);
		});
	}
	else						{ tdElem.text("Not Available"); }

	trElem.append(tdElem);

	var item = $("#textbased-tbody > tr").filter(function(){ return parseInt($(this).attr("data-ijob")) >= ijob; }).eq(0);

	if (item.length > 0)		{ trElem.insertBefore(item); }
	else						{ $("#textbased-tbody").append(trElem); }

	if (updateMap && pos_x && pos_y && (in_range == "1"))
	{
		var x					= parseInt(pos_x);
		var y					= maxy - parseInt(pos_y);

		var tx					= translateX(x);
		var ty					= translateY(y);

		var dotElem				= $("

");

		$("#minimap").append(dotElem);

		var counter = 0;

		function enable()
		{
			++counter;
			dotElem.addClass("active").css({ "border-color": color });
		}

		function disable()
		{
			++counter;
			dotElem.removeClass("active").css({ "border-color": "transparent" });
		}

		function click(e)
		{
			e.preventDefault();
			e.stopPropagation();

			window.location.href = "byond://?src=" + hSrc + "&action=select_person&name=" + encodeURIComponent(name);
		}

		trElem.on("mouseover", function()
		{
			enable();

			if (zoom_factor > 1.00)
			{
				var c = counter;
				setTimeout(function()
				{
					if (c == counter)
					{
						var minimap	= document.getElementById("minimap");
						var half	= $(minimap).height() / 2;
						var offset	= $(dotElem).offset();

						minimap.scrollLeft = offset.left + minimap.scrollLeft - half;
						minimap.scrollTop = offset.top + minimap.scrollTop - half;
					}
				}, 100);
			}
		}).on("mouseout", disable).on("click", click);
		dotElem.on("mouseover", function()
		{
			trElem.addClass("hover");
			enable();
			trElem.scrollintoview();
		}).on("mouseout", function()
		{
			trElem.removeClass("hover");
			disable();
		}).on("click", click);
	}
}

function translateX(n)	{ return (translate(n - 1.5, scale_x) ).toFixed(0); }
function translateY(n)	{ return (translate(n + 0.75, scale_y) ).toFixed(0); }

function translate(n, scale)
{
	return (n * tile_size) * scale;
}


code:
#define INJECTOR_TIMEOUT 100
#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 SCANNER_ACTION_SE 1
#define SCANNER_ACTION_UI 2
#define SCANNER_ACTION_UE 3
#define SCANNER_ACTION_MIXED 4

/obj/machinery/computer/scan_consolenew
	name = "\improper DNA scanner access console"
	desc = "Scan DNA."
	icon_screen = "dna"
	icon_keyboard = "med_key"
	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
	var/list/delayed_action = null
	anchored = 1
	use_power = 1
	idle_power_usage = 10
	active_power_usage = 400

/obj/machinery/computer/scan_consolenew/attackby(obj/item/I, mob/user, params)
	if (istype(I, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES
		if (!src.diskette)
			if(!user.drop_item())
				return
			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", 800, 630) // 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(viable_occupant.has_dna() && (!(viable_occupant.disabilities & NOCLONE) || (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"
				occupant_status += "

"
				occupant_status += "

Health:

[viable_occupant.health] %

"
				occupant_status += "

Radiation Level:

[viable_occupant.radiation] %

"
				var/rejuvenators = viable_occupant.reagents.get_reagent_amount("epinephrine")
				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"
							temp_html += "Occupant:Delayed "
							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"
							temp_html += "Occupant:Delayed "
							if(injectorready)
								temp_html += "Injector"
							else
								temp_html += "Injector"
						else
							temp_html += "
\tUI: No Data"
						if(ue && name && blood_type && ui)
							temp_html += "
\tUI+UE: [ui]/[ue] "
							if(viable_occupant)
								temp_html += "Occupant "
							else
								temp_html += "Occupant"
							temp_html += "Occupant:Delayed "
							if(injectorready)
								temp_html += "UI+UE Injector"
							else
								temp_html += "UI+UE Injector"
						if(se)
							temp_html += "
\tSE: [se] "
							if(viable_occupant)
								temp_html += "Occupant "
							else
								temp_html += "Occupant "
							temp_html += "Occupant:Delayed "
							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 = get_viable_occupant()

	//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/epinephrine_amount = viable_occupant.reagents.get_reagent_amount("epinephrine")
				var/can_add = max(min(REJUVENATORS_MAX - epinephrine_amount, REJUVENATORS_INJECT), 0)
				viable_occupant.reagents.add_reagent("epinephrine", 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)
				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")
						apply_buffer(SCANNER_ACTION_SE,num)
					if("ui")
						apply_buffer(SCANNER_ACTION_UI,num)
					if("ue")
						apply_buffer(SCANNER_ACTION_UE,num)
					if("mixed")
						apply_buffer(SCANNER_ACTION_MIXED,num)
		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/timed/I
					switch(href_list["text"])
						if("se")
							if(buffer_slot["SE"])
								I = new /obj/item/weapon/dnainjector/timed(loc)
								for(var/datum/mutation/human/HM in good_mutations + bad_mutations + not_good_mutations)
									if(HM.check_block_string(buffer_slot["SE"]))
										I.add_mutations.Add(HM)
									else
										I.remove_mutations.Add(HM)
								var/time_coeff
								for(var/datum/mutation/human/HM in I.add_mutations)
									if(!time_coeff)
										time_coeff = HM.time_coeff
										continue
									time_coeff = min(time_coeff,HM.time_coeff)
								if(connected)
									I.duration = I.duration * time_coeff * connected.damage_coeff
									I.damage_coeff  = connected.damage_coeff
						if("ui")
							if(buffer_slot["UI"])
								I = new /obj/item/weapon/dnainjector/timed(loc)
								I.fields = list("UI"=buffer_slot["UI"])
								if(connected)
									I.damage_coeff = connected.damage_coeff
						if("ue")
							if(buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"])
								I = new /obj/item/weapon/dnainjector/timed(loc)
								I.fields = list("name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"])
								if(connected)
									I.damage_coeff  = connected.damage_coeff
						if("mixed")
							if(buffer_slot["UI"] && buffer_slot["name"] && buffer_slot["UE"] && buffer_slot["blood_type"])
								I = new /obj/item/weapon/dnainjector/timed(loc)
								I.fields = list("UI"=buffer_slot["UI"],"name"=buffer_slot["name"], "UE"=buffer_slot["UE"], "blood_type"=buffer_slot["blood_type"])
								if(connected)
									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("setdelayed")
			if(num)
				delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num)
		if("pulseui","pulsese")
			if(num && viable_occupant && connected)
				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)
							viable_occupant.updateappearance(mutations_overlay_update=1)
						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)
							viable_occupant.domutcheck()
				else
					current_screen = "mainmenu"

				if(connected)
					connected.locked = locked_state

	ShowInterface(usr,last_change)

/obj/machinery/computer/scan_consolenew/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)

/obj/machinery/computer/scan_consolenew/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)

/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant()
	var/mob/living/carbon/viable_occupant = null
	if(connected)
		viable_occupant = connected.occupant
		if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE))
			viable_occupant = null
	return viable_occupant

/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num)
	buffer_num = Clamp(buffer_num, 1, NUMBER_OF_BUFFERS)
	var/list/buffer_slot = buffer[buffer_num]
	var/mob/living/carbon/viable_occupant = get_viable_occupant()
	if(istype(buffer_slot))
		viable_occupant.radiation += rand(10/(connected.damage_coeff ** 2),25/(connected.damage_coeff ** 2))
		//15 and 40 are just magic numbers that were here before so i didnt touch them, they are initial boundaries of damage
		//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
		//Numbers are this high because other way upgrading laser is just not worth the hassle, and i cant think of anything better to inmrove
		switch(action)
			if(SCANNER_ACTION_SE)
				if(buffer_slot["SE"])
					viable_occupant.dna.struc_enzymes = buffer_slot["SE"]
					viable_occupant.domutcheck()
			if(SCANNER_ACTION_UI)
				if(buffer_slot["UI"])
					viable_occupant.dna.uni_identity = buffer_slot["UI"]
					viable_occupant.updateappearance(mutations_overlay_update=1)
			if(SCANNER_ACTION_UE)
				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"]
			if(SCANNER_ACTION_MIXED)
				if(buffer_slot["UI"])
					viable_occupant.dna.uni_identity = buffer_slot["UI"]
					viable_occupant.updateappearance(mutations_overlay_update=1)
				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"]

/obj/machinery/computer/scan_consolenew/proc/on_scanner_close()
	connected.occupant << "[src] activates!"
	if(delayed_action)
		apply_buffer(delayed_action["action"],delayed_action["buffer"])
		delayed_action = null //or make it stick + reset button ?
	return

/////////////////////////// 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 SCANNER_ACTION_SE
#undef SCANNER_ACTION_UI
#undef SCANNER_ACTION_UE
#undef SCANNER_ACTION_MIXED

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


code:
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31

/obj/machinery/computer/upload
	var/mob/living/silicon/current = null //The target of future law uploads
	icon_screen = "command"

/obj/machinery/computer/upload/attackby(obj/item/O, mob/user, params)
	if(istype(O, /obj/item/weapon/aiModule))
		var/obj/item/weapon/aiModule/M = O
		if(src.stat & (NOPOWER|BROKEN|MAINT))
			return
		if(!current)
			user << "You haven't selected anything to transmit laws to!"
			return
		if(!can_upload_to(current))
			user << "Upload failed! Check to make sure [current.name] is functioning properly."
			current = null
			return
		var/turf/currentloc = get_turf(current)
		if(currentloc && user.z != currentloc.z)
			user << "Upload failed! Unable to establish a connection to [current.name]. You're too far away!"
			current = null
			return
		M.install(current.laws, user)
	else
		..()

/obj/machinery/computer/upload/proc/can_upload_to(mob/living/silicon/S)
	if(S.stat == DEAD || S.syndicate)
		return 0
	return 1

/obj/machinery/computer/upload/ai
	name = "\improper AI upload console"
	desc = "Used to upload laws to the AI."
	circuit = /obj/item/weapon/circuitboard/aiupload

/obj/machinery/computer/upload/ai/attack_hand(mob/user)
	if(..())
		return

	src.current = select_active_ai(user)

	if (!src.current)
		user << "No active AIs detected!"
	else
		user << "[src.current.name] selected for law changes."

/obj/machinery/computer/upload/ai/can_upload_to(mob/living/silicon/ai/A)
	if(!A || !isAI(A))
		return 0
	if(A.control_disabled)
		return 0
	return ..()

/obj/machinery/computer/upload/borg
	name = "cyborg upload console"
	desc = "Used to upload laws to Cyborgs."
	circuit = /obj/item/weapon/circuitboard/borgupload

/obj/machinery/computer/upload/borg/attack_hand(mob/user)
	if(..())
		return

	src.current = select_active_free_borg(user)

	if(!src.current)
		user << "No active unslaved cyborgs detected!"
	else
		user << "[src.current.name] selected for law changes."

/obj/machinery/computer/upload/borg/can_upload_to(mob/living/silicon/robot/B)
	if(!B || !isrobot(B))
		return 0
	if(B.scrambledcodes || B.emagged)
		return 0
	return ..()