code:
var/list/ai_list = list()

//Not sure why this is necessary...
/proc/AutoUpdateAI(obj/subject)
	var/is_in_use = 0
	if (subject!=null)
		for(var/A in ai_list)
			var/mob/living/silicon/ai/M = A
			if ((M.client && M.machine == subject))
				is_in_use = 1
				subject.attack_ai(M)
	return is_in_use

/mob/living/silicon/ai
	name = "AI"
	icon = 'icons/mob/AI.dmi'//
	icon_state = "ai"
	anchored = 1
	density = 1
	status_flags = CANSTUN|CANPARALYSE|CANPUSH
	force_compose = 1 //This ensures that the AI always composes it's own hear message. Needed for hrefs and job display.
	med_hud = DATA_HUD_MEDICAL_BASIC
	sec_hud = DATA_HUD_SECURITY_BASIC
	var/list/network = list("SS13")
	var/obj/machinery/camera/current = null
	var/list/connected_robots = list()
	var/aiRestorePowerRoutine = 0
	//var/list/laws = list()
	var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
	var/viewalerts = 0
	var/icon/holo_icon//Default is assigned when AI is created.
	var/radio_enabled = 1 //Determins if a carded AI can speak with its built in radio or not.
	radiomod = ";" //AIs will, by default, state their laws on the internal radio.
	var/obj/item/device/pda/ai/aiPDA = null
	var/obj/item/device/multitool/aiMulti = null
	var/obj/machinery/bot/Bot

	//MALFUNCTION
	var/datum/module_picker/malf_picker
	var/processing_time = 100
	var/list/datum/AI_Module/current_modules = list()
	var/fire_res_on_core = 0

	var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click()
	var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite
	var/malf_cooldown = 0 //Cooldown var for malf modules

	var/obj/machinery/power/apc/malfhack = null
	var/explosive = 0 //does the AI explode when it dies?

	var/mob/living/silicon/ai/parent = null
	var/camera_light_on = 0
	var/list/obj/machinery/camera/lit_cameras = list()

	var/datum/trackable/track = new()

	var/last_paper_seen = null
	var/can_shunt = 1
	var/last_announcement = "" // For AI VOX, if enabled
	var/turf/waypoint //Holds the turf of the currently selected waypoint.
	var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
	var/apc_override = 0 //hack for letting the AI use its APC even when visionless

/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
	var/list/possibleNames = ai_names

	var/pickedName = null
	while(!pickedName)
		pickedName = pick(ai_names)
		for (var/mob/living/silicon/ai/A in mob_list)
			if (A.real_name == pickedName && possibleNames.len > 1) //fixing the theoretically possible infinite loop
				possibleNames -= pickedName
				pickedName = null

	real_name = pickedName
	name = real_name
	anchored = 1
	canmove = 0
	density = 1
	loc = loc

	holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))

	if(L)
		if (istype(L, /datum/ai_laws))
			laws = L
	else
		make_laws()

	verbs += /mob/living/silicon/ai/proc/show_laws_verb

	aiPDA = new/obj/item/device/pda/ai(src)
	aiPDA.owner = name
	aiPDA.ownjob = "AI"
	aiPDA.name = name + " (" + aiPDA.ownjob + ")"

	aiMulti = new(src)
	radio = new /obj/item/device/radio/headset/ai(src)
	aicamera = new/obj/item/device/camera/siliconcam/ai_camera(src)

	if (istype(loc, /turf))
		verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
		/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
		/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall,\
		/mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/set_automatic_say_channel)

	if(!safety)//Only used by AIize() to successfully spawn an AI.
		if (!B)//If there is no player/brain inside.
			new/obj/structure/AIcore/deactivated(loc)//New empty terminal.
			qdel(src)//Delete AI.
			return
		else
			if (B.brainmob.mind)
				B.brainmob.mind.transfer_to(src)

			src << "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)."
			src << "To look at other parts of the station, click on yourself to get a camera menu."
			src << "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc."
			src << "To use something, simply click on it."
			src << "Use say :b to speak to your cyborgs through binary."
			src << "For department channels, use the following say commands:"
			src << ":o - AI Private, :c - Command, :s - Security, :e - Engineering, :u - Supply, :v - Service, :m - Medical, :n - Science."
			if (!(ticker && ticker.mode && (mind in ticker.mode.malf_ai)))
				show_laws()
				src << "These laws may be changed by other players, or by you being the traitor."

			job = "AI"
	ai_list += src
	shuttle_caller_list += src
	..()
	return

/mob/living/silicon/ai/Destroy()
	ai_list -= src
	shuttle_caller_list -= src
	eyeobj = null
	SSshuttle.autoEvac()
	..()

/mob/living/silicon/ai/verb/pick_icon()
	set category = "AI Commands"
	set name = "Set AI Core Display"
	if(stat || aiRestorePowerRoutine)
		return

		//if(icon_state == initial(icon_state))
	var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo")
	if(icontype == "Clown")
		icon_state = "ai-clown2"
	else if(icontype == "Monochrome")
		icon_state = "ai-mono"
	else if(icontype == "Blue")
		icon_state = "ai"
	else if(icontype == "Inverted")
		icon_state = "ai-u"
	else if(icontype == "Firewall")
		icon_state = "ai-magma"
	else if(icontype == "Green")
		icon_state = "ai-wierd"
	else if(icontype == "Red")
		icon_state = "ai-malf"
	else if(icontype == "Static")
		icon_state = "ai-static"
	else if(icontype == "Red October")
		icon_state = "ai-redoctober"
	else if(icontype == "House")
		icon_state = "ai-house"
	else if(icontype == "Heartline")
		icon_state = "ai-heartline"
	else if(icontype == "Hades")
		icon_state = "ai-hades"
	else if(icontype == "Helios")
		icon_state = "ai-helios"
	else if(icontype == "President")
		icon_state = "ai-pres"
	else if(icontype == "Syndicat Meow")
		icon_state = "ai-syndicatmeow"
	else if(icontype == "Alien")
		icon_state = "ai-alien"
	else if(icontype == "Too Deep")
		icon_state = "ai-toodeep"
	else if(icontype == "Triumvirate")
		icon_state = "ai-triumvirate"
	else if(icontype == "Triumvirate-M")
		icon_state = "ai-triumvirate-malf"
	else if(icontype == "Text")
		icon_state = "ai-text"
	else if(icontype == "Matrix")
		icon_state = "ai-matrix"
	else if(icontype == "Dorf")
		icon_state = "ai-dorf"
	else if(icontype == "Bliss")
		icon_state = "ai-bliss"
	else if(icontype == "Not Malf")
		icon_state = "ai-notmalf"
	else if(icontype == "Fuzzy")
		icon_state = "ai-fuzz"
	else if(icontype == "Goon")
		icon_state = "ai-goon"
	else if(icontype == "Database")
		icon_state = "ai-database"
	else if(icontype == "Glitchman")
		icon_state = "ai-glitchman"
	else if(icontype == "Murica")
		icon_state = "ai-murica"
	else if(icontype == "Nanotrasen")
		icon_state = "ai-nanotrasen"
	else if(icontype == "Gentoo")
		icon_state = "ai-gentoo"
	//else
			//usr <<"You can only change your display once!"
			//return

/mob/living/silicon/ai/Stat()
	..()
	if(statpanel("Status"))
		if(ticker.mode.name == "AI malfunction")
			var/datum/game_mode/malfunction/malf = ticker.mode
			for (var/datum/mind/malfai in malf.malf_ai)
				if ((mind == malfai) && (malf.apcs > 0))
					stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/malf.apcs, 0)] seconds")

		if(!stat)
			stat(null, text("System integrity: [(health+100)/2]%"))
			stat(null, "Station Time: [worldtime2text()]")
			stat(null, text("Connected cyborgs: [connected_robots.len]"))
			var/area/borg_area
			for(var/mob/living/silicon/robot/R in connected_robots)
				borg_area = get_area(R)
				//Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
				if(!R)
					continue
				stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \
 Module: [R.designation] | Loc: [borg_area.name] | Status: [R.stat || !R.client ? "OFFLINE" : "Normal"]"))
		else
			stat(null, text("Systems nonfunctional"))

/mob/living/silicon/ai/proc/ai_alerts()
	var/dat = "<TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'>\n"
	dat += "Close

"
	for (var/cat in alarms)
		dat += text("[]
\n", cat)
		var/list/L = alarms[cat]
		if (L.len)
			for (var/alarm in L)
				var/list/alm = L[alarm]
				var/area/A = alm[1]
				var/C = alm[2]
				var/list/sources = alm[3]
				dat += "<NOBR>"
				if (C && istype(C, /list))
					var/dat2 = ""
					for (var/obj/machinery/camera/I in C)
						dat2 += text("[][]", (dat2=="") ? "" : " | ", src, I, I.c_tag)
					dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera")
				else if (C && istype(C, /obj/machinery/camera))
					var/obj/machinery/camera/Ctmp = C
					dat += text("-- [] ([])", A.name, src, C, Ctmp.c_tag)
				else
					dat += text("-- [] (No Camera)", A.name)
				if (sources.len > 1)
					dat += text("- [] sources", sources.len)
				dat += "</NOBR>
\n"
		else
			dat += "-- All Systems Nominal
\n"
		dat += "
\n"

	viewalerts = 1
	src << browse(dat, "window=aialerts&can_close=0")

/mob/living/silicon/ai/proc/ai_roster()
	var/dat = "<title>Crew Roster</title>Crew Roster:

"

	for(var/datum/data/record/t in sortRecord(data_core.general))
		dat += t.fields["name"] + " - " + t.fields["rank"] + "
"
	dat += ""

	src << browse(dat, "window=airoster")
	onclose(src, "airoster")

/mob/living/silicon/ai/proc/ai_call_shuttle()
	if(src.stat == DEAD)
		src << "You can't call the shuttle because you are dead!"
		return
	if(istype(usr,/mob/living/silicon/ai))
		var/mob/living/silicon/ai/AI = src
		if(AI.control_disabled)
			usr << "Wireless control is disabled!"
			return

	var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as text

	if(trim(reason))
		SSshuttle.requestEvac(src, reason)

	// hack to display shuttle timer
	if(SSshuttle.emergency.mode >= SHUTTLE_CALL)
		var/obj/machinery/computer/communications/C = locate() in machines
		if(C)
			C.post_status("shuttle")

	return

/mob/living/silicon/ai/cancel_camera()
	src.view_core()

/mob/living/silicon/ai/verb/toggle_anchor()
	set category = "AI Commands"
	set name = "Toggle Floor Bolts"
	if(!isturf(loc)) // if their location isn't a turf
		return // stop
	anchored = !anchored // Toggles the anchor

	src << "[anchored ? "You are now anchored." : "You are now unanchored."]"
	// the message in the [] will change depending whether or not the AI is anchored

/mob/living/silicon/ai/update_canmove() //If the AI dies, mobs won't go through it anymore
	return 0

/mob/living/silicon/ai/proc/ai_cancel_call()
	set category = "Malfunction"
	if(src.stat == 2)
		src << "You can't send the shuttle back because you are dead!"
		return
	if(istype(usr,/mob/living/silicon/ai))
		var/mob/living/silicon/ai/AI = src
		if(AI.control_disabled)
			src	 << "Wireless control is disabled!"
			return
	SSshuttle.cancelEvac(src)
	return

/mob/living/silicon/ai/check_eye(var/mob/user as mob)
	if (!current)
		return null
	user.reset_view(current)
	return 1

/mob/living/silicon/ai/blob_act()
	if (stat != 2)
		adjustBruteLoss(60)
		updatehealth()
		return 1
	return 0

/mob/living/silicon/ai/restrained()
	return 0

/mob/living/silicon/ai/emp_act(severity)
	if (prob(30))
		switch(pick(1,2))
			if(1)
				view_core()
			if(2)
				ai_call_shuttle()
	..()

/mob/living/silicon/ai/ex_act(severity, target)
	..()

	switch(severity)
		if(1.0)
			gib()
		if(2.0)
			if (stat != 2)
				adjustBruteLoss(60)
				adjustFireLoss(60)
		if(3.0)
			if (stat != 2)
				adjustBruteLoss(30)

	return

/mob/living/silicon/ai/Topic(href, href_list)
	if(usr != src)
		return
	..()
	if (href_list["mach_close"])
		if (href_list["mach_close"] == "aialerts")
			viewalerts = 0
		var/t1 = text("window=[]", href_list["mach_close"])
		unset_machine()
		src << browse(null, t1)
	if (href_list["switchcamera"])
		switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
	if (href_list["showalerts"])
		ai_alerts()
#ifdef AI_VOX
	if(href_list["say_word"])
		play_vox_word(href_list["say_word"], null, src)
		return
#endif
	if(href_list["show_paper"])
		if(last_paper_seen)
			src << browse(last_paper_seen, "window=show_paper")
	//Carn: holopad requests
	if(href_list["jumptoholopad"])
		var/obj/machinery/hologram/holopad/H = locate(href_list["jumptoholopad"])
		if(stat == CONSCIOUS)
			if(H)
				H.attack_ai(src) //may as well recycle
			else
				src << "Unable to locate the holopad."
	if(href_list["track"])
		var/string = href_list["track"]
		trackable_mobs()
		var/list/trackeable = list()
		trackeable += track.humans + track.others
		var/list/target = list()
		for(var/I in trackeable)
			var/mob/M = trackeable[I]
			if(M.name == string)
				target += M
		if(name == string)
			target += src
		if(target.len)
			ai_actual_track(pick(target))
		else
			src << "Target is not on or near any active cameras on the station."

	if(href_list["callbot"]) //Command a bot to move to a selected location.
		Bot = locate(href_list["callbot"]) in SSbot.processing
		if(!Bot || Bot.remote_disabled || src.control_disabled)
			return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
		waypoint_mode = 1
		src << "Set your waypoint by clicking on a valid location free of obstructions."
		return

	if(href_list["interface"]) //Remotely connect to a bot!
		Bot = locate(href_list["interface"]) in SSbot.processing
		if(!Bot || Bot.remote_disabled || src.control_disabled)
			return
		Bot.attack_ai(src)

	if(href_list["botrefresh"]) //Refreshes the bot control panel.
		botcall()
		return

/mob/living/silicon/ai/bullet_act(var/obj/item/projectile/Proj)
	..(Proj)
	updatehealth()
	return 2

/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M as mob)
	if (!ticker)
		M << "You cannot attack people before the game has started."
		return

	..()
	return

/mob/living/silicon/ai/reset_view(atom/A)
	if (camera_light_on)
		light_cameras()
	if(istype(A,/obj/machinery/camera))
		current = A
	..()

/mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C)

	src.cameraFollow = null

	if (!C || stat == 2) //C.can_use())
		return 0

	if(!src.eyeobj)
		view_core()
		return
	// ok, we're alive, camera is good and in our network...
	eyeobj.setLoc(get_turf(C))
	//machine = src

	return 1

/mob/living/silicon/ai/proc/botcall()
	set category = "AI Commands"
	set name = "Access Robot Control"
	set desc = "Wirelessly control various automatic robots."
	if(stat == 2)
		src << "Critical error. System offline."
		return

	if(control_disabled)
		src << "Wireless communication is disabled."
		return
	var/turf/ai_current_turf = get_turf(src)
	var/ai_Zlevel = ai_current_turf.z
	var/d
	var/area/bot_area
	d += "Query network status
"
	d += "

Name

Status

Location

Control

"

	for (Bot in SSbot.processing)
		if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
			bot_area = get_area(Bot)
			d += "
[Bot.hacked ? "(!) [Bot.name]" : Bot.name]	"
			//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
			d += "[Bot.on ? "[Bot.mode ? "[ Bot.mode_name[Bot.mode] ]": "Idle"]" : "Inactive"]	"
			d += "[bot_area.name]	"
			d += "Interface	"
			d += "Call	"
			d += "
"
			d = format_text(d)

	var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400)
	popup.set_content(d)
	popup.open()

/mob/living/silicon/ai/proc/set_waypoint(var/atom/A)
	var/turf/turf_check = get_turf(A)
		//The target must be in view of a camera or near the core.
	if(turf_check in range(get_turf(src)))
		call_bot(turf_check)
	else if(cameranet && cameranet.checkTurfVis(turf_check))
		call_bot(turf_check)
	else
		src << "Selected location is not visible."

/mob/living/silicon/ai/proc/call_bot(var/turf/waypoint)

	if(!Bot)
		return

	if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot.
		src << "Interface error. Unit is already in use."
		return

	Bot.call_bot(src, waypoint)

/mob/living/silicon/ai/triggerAlarm(var/class, area/A, var/O, var/obj/alarmsource)
	if(alarmsource.z != z)
		return
	if (stat == 2)
		return 1
	var/list/L = alarms[class]
	for (var/I in L)
		if (I == A.name)
			var/list/alarm = L[I]
			var/list/sources = alarm[3]
			if (!(alarmsource in sources))
				sources += alarmsource
			return 1
	var/obj/machinery/camera/C = null
	var/list/CL = null
	if (O && istype(O, /list))
		CL = O
		if (CL.len == 1)
			C = CL[1]
	else if (O && istype(O, /obj/machinery/camera))
		C = O
	L[A.name] = list(A, (C) ? C : O, list(alarmsource))
	if (O)
		if (C && C.can_use())
			queueAlarm("--- [class] alarm detected in [A.name]! ([C.c_tag])", class)
		else if (CL && CL.len)
			var/foo = 0
			var/dat2 = ""
			for (var/obj/machinery/camera/I in CL)
				dat2 += text("[][]", (!foo) ? "" : " | ", src, I, I.c_tag)	//I'm not fixing this shit...
				foo = 1
			queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class)
		else
			queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
	else
		queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
	if (viewalerts) ai_alerts()
	return 1

/mob/living/silicon/ai/cancelAlarm(var/class, area/A as area, obj/origin)
	var/list/L = alarms[class]
	var/cleared = 0
	for (var/I in L)
		if (I == A.name)
			var/list/alarm = L[I]
			var/list/srcs  = alarm[3]
			if (origin in srcs)
				srcs -= origin
			if (srcs.len == 0)
				cleared = 1
				L -= I
	if (cleared)
		queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
		if (viewalerts) ai_alerts()
	return !cleared

//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead
//Addition by Mord_Sith to define AI's network change ability
/mob/living/silicon/ai/proc/ai_network_change()
	set category = "AI Commands"
	set name = "Jump To Network"
	unset_machine()
	src.cameraFollow = null
	var/cameralist[0]

	if(usr.stat == 2)
		usr << "You can't change your camera network because you are dead!"
		return

	var/mob/living/silicon/ai/U = usr

	for (var/obj/machinery/camera/C in cameranet.cameras)
		if(!C.can_use())
			continue

		var/list/tempnetwork = C.network
		tempnetwork.Remove("CREED", "thunder", "RD", "toxins", "Prison")
		if(tempnetwork.len)
			for(var/i in C.network)
				cameralist[i] = i
	var/old_network = network
	network = input(U, "Which network would you like to view?") as null|anything in cameralist

	if(!U.eyeobj)
		U.view_core()
		return

	if(isnull(network))
		network = old_network // If nothing is selected
	else
		for(var/obj/machinery/camera/C in cameranet.cameras)
			if(!C.can_use())
				continue
			if(network in C.network)
				U.eyeobj.setLoc(get_turf(C))
				break
	src << "Switched to [network] camera network."
//End of code by Mord_Sith

/mob/living/silicon/ai/proc/choose_modules()
	set category = "Malfunction"
	set name = "Choose Module"

	malf_picker.use(src)

/mob/living/silicon/ai/proc/ai_statuschange()
	set category = "AI Commands"
	set name = "AI Status"

	if(usr.stat == 2)
		usr <<"You cannot change your emotional status because you are dead!"
		return
	var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow")
	var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
	for (var/obj/machinery/M in machines) //change status
		if(istype(M, /obj/machinery/ai_status_display))
			var/obj/machinery/ai_status_display/AISD = M
			AISD.emotion = emote
		//if Friend Computer, change ALL displays
		else if(istype(M, /obj/machinery/status_display))

			var/obj/machinery/status_display/SD = M
			if(emote=="Friend Computer")
				SD.friendc = 1
			else
				SD.friendc = 0
	return

//I am the icon meister. Bow fefore me.	//>fefore
/mob/living/silicon/ai/proc/ai_hologram_change()
	set name = "Change Hologram"
	set desc = "Change the default hologram available to AI to something else."
	set category = "AI Commands"

	var/input
	if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member")

		var/personnel_list[] = list()

		for(var/datum/data/record/t in data_core.locked)//Look in data core locked.
			personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image.

		if(personnel_list.len)
			input = input("Select a crew member:") as null|anything in personnel_list
			var/icon/character_icon = personnel_list[input]
			if(character_icon)
				del(holo_icon)//Clear old icon so we're not storing it in memory.
				holo_icon = getHologramIcon(icon(character_icon))
		else
			alert("No suitable records found. Aborting.")

	else
		var/icon_list[] = list(
		"default",
		"floating face",
		"xeno queen",
		"space carp"
		)
		input = input("Please select a hologram:") as null|anything in icon_list
		if(input)
			del(holo_icon)
			switch(input)
				if("default")
					holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
				if("floating face")
					holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
				if("xeno queen")
					holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo3"))
				if("space carp")
					holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
	return

/mob/living/silicon/ai/proc/corereturn()
	set category = "Malfunction"
	set name = "Return to Main Core"

	var/obj/machinery/power/apc/apc = src.loc
	if(!istype(apc))
		src << "You are already in your Main Core."
		return
	apc.malfvacate()

/mob/living/silicon/ai/proc/toggle_camera_light()
	if(stat != CONSCIOUS)
		return

	camera_light_on = !camera_light_on

	if (!camera_light_on)
		src << "Camera lights deactivated."

		for (var/obj/machinery/camera/C in lit_cameras)
			C.set_light(0)
			lit_cameras = list()

		return

	light_cameras()

	src << "Camera lights activated."
	return

//AI_CAMERA_LUMINOSITY

/mob/living/silicon/ai/proc/light_cameras()
	var/list/obj/machinery/camera/add = list()
	var/list/obj/machinery/camera/remove = list()
	var/list/obj/machinery/camera/visible = list()
	for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
		for (var/obj/machinery/camera/C in CC.cameras)
			if (!C.can_use() || C.light_disabled || get_dist(C, eyeobj) > 7)
				continue
			visible |= C

	add = visible - lit_cameras
	remove = lit_cameras - visible

	for (var/obj/machinery/camera/C in remove)
		C.set_light(0)
		lit_cameras -= C
	for (var/obj/machinery/camera/C in add)
		C.set_light(AI_CAMERA_LUMINOSITY)
		lit_cameras |= C

/mob/living/silicon/ai/proc/control_integrated_radio()
	set name = "Transceiver Settings"
	set desc = "Allows you to change settings of your radio."
	set category = "AI Commands"

	src << "Accessing Subspace Transceiver control..."
	if (radio)
		radio.interact(src)

/mob/living/silicon/ai/proc/set_syndie_radio()
	if(radio)
		radio.make_syndie()

/mob/living/silicon/ai/proc/set_automatic_say_channel()
	set name = "Set Auto Announce Mode"
	set desc = "Modify the default radio setting for your automatic announcements."
	set category = "AI Commands"

	set_autosay()

/mob/living/silicon/ai/attack_slime(mob/living/carbon/slime/user)
	return


code:
/mob/living/silicon/ai/death(gibbed)
	if(stat == DEAD)	return
	stat = DEAD

	if("[icon_state]_dead" in icon_states(src.icon,1))
		icon_state = "[icon_state]_dead"
	else
		icon_state = "ai_dead"

	update_canmove()
	if(src.eyeobj)
		src.eyeobj.setLoc(get_turf(src))
	if(blind)	blind.layer = 0
	sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
	see_in_dark = 8
	see_invisible = SEE_INVISIBLE_LEVEL_TWO

	shuttle_caller_list -= src
	SSshuttle.autoEvac()

	if(explosive)
		spawn(10)
			explosion(src.loc, 3, 6, 12, 15)

	for(var/obj/machinery/ai_status_display/O in world) //change status
		if(src.key)
			spawn( 0 )
			O.mode = 2
			if (istype(loc, /obj/item/device/aicard))
				loc.icon_state = "aicard-404"

	tod = worldtime2text() //weasellos time of death patch
	if(mind)	mind.store_memory("Time of death: [tod]", 0)

	return ..(gibbed)

license: mit


code:
/mob/living/silicon/ai/examine(mob/user)
	var/msg = "*---------*\nThis is \icon[src] [src]!\n"
	if (src.stat == DEAD)
		msg += "It appears to be powered-down.\n"
	else
		msg += ""
		if (src.getBruteLoss())
			if (src.getBruteLoss() < 30)
				msg += "It looks slightly dented.\n"
			else
				msg += "It looks severely dented!\n"
		if (src.getFireLoss())
			if (src.getFireLoss() < 30)
				msg += "It looks slightly charred.\n"
			else
				msg += "Its casing is melted and heat-warped!\n"

		if (src.stat == UNCONSCIOUS)
			msg += "It is non-responsive and displaying the text: \"RUNTIME: Sensory Overload, stack 26/3\".\n"
		msg += ""
	msg += "*---------*"

	user << msg


code:
// CAMERA NET
//
// The datum containing all the chunks.

var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..

var/datum/cameranet/cameranet = new()

/datum/cameranet
	// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
	var/list/cameras = list()
	// The chunks of the map, mapping the areas that the cameras can see.
	var/list/chunks = list()
	var/ready = 0

// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
	x &= ~(CHUNK_SIZE - 1)
	y &= ~(CHUNK_SIZE - 1)
	var/key = "[x],[y],[z]"
	return (chunks[key])

// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z)
	x &= ~(CHUNK_SIZE - 1)
	y &= ~(CHUNK_SIZE - 1)
	var/key = "[x],[y],[z]"
	if(!chunks[key])
		chunks[key] = new /datum/camerachunk(null, x, y, z)

	return chunks[key]

// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.

/datum/cameranet/proc/visibility(mob/camera/aiEye/ai)
	// 0xf = 15
	var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
	var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
	var/x2 = min(world.maxx, ai.x + 16) & ~(CHUNK_SIZE - 1)
	var/y2 = min(world.maxy, ai.y + 16) & ~(CHUNK_SIZE - 1)

	var/list/visibleChunks = list()

	for(var/x = x1; x <= x2; x += CHUNK_SIZE)
		for(var/y = y1; y <= y2; y += CHUNK_SIZE)
			visibleChunks |= getCameraChunk(x, y, ai.z)

	var/list/remove = ai.visibleCameraChunks - visibleChunks
	var/list/add = visibleChunks - ai.visibleCameraChunks

	for(var/chunk in remove)
		var/datum/camerachunk/c = chunk
		c.remove(ai)

	for(var/chunk in add)
		var/datum/camerachunk/c = chunk
		c.add(ai)

// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or	when doors open.

/datum/cameranet/proc/updateVisibility(atom/A, var/opacity_check = 1)

	if(!ticker || (opacity_check && !A.opacity))
		return
	majorChunkChange(A, 2)

/datum/cameranet/proc/updateChunk(x, y, z)
	// 0xf = 15
	if(!chunkGenerated(x, y, z))
		return
	var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
	chunk.hasChanged()

// Removes a camera from a chunk.

/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
	if(c.can_use())
		majorChunkChange(c, 0)

// Add a camera to a chunk.

/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
	if(c.can_use())
		majorChunkChange(c, 1)

// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.

/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
	if(c.can_use())
		majorChunkChange(c, 1)
	//else
	//	majorChunkChange(c, 0)

// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.

/datum/cameranet/proc/majorChunkChange(atom/c, var/choice)
	// 0xf = 15
	if(!c)
		return

	var/turf/T = get_turf(c)
	if(T)
		var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
		var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
		var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
		var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)

		//world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"

		for(var/x = x1; x <= x2; x += CHUNK_SIZE)
			for(var/y = y1; y <= y2; y += CHUNK_SIZE)
				if(chunkGenerated(x, y, T.z))
					var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
					if(choice == 0)
						// Remove the camera.
						chunk.cameras -= c
					else if(choice == 1)
						// You can't have the same camera in the list twice.
						chunk.cameras |= c
					chunk.hasChanged()

// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.

/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)

	// 0xf = 15
	var/turf/position = get_turf(target)
	if(!position)
		return
	return checkTurfVis(position)

/datum/cameranet/proc/checkTurfVis(var/turf/position)
	if(!position)
		return
	var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
	if(chunk)
		if(chunk.changed)
			chunk.hasChanged(1) // Update now, no matter if it's visible or not.
		if(chunk.visibleTurfs[position])
			return 1
	return 0

// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
	set src in world

	if(cameranet.chunkGenerated(x, y, z))
		var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
		usr.client.debug_variables(chunk)
*/


code:
#define UPDATE_BUFFER 25 // 2.5 seconds

// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the AI Eye to stream these chunks and know what it can and cannot see.

/datum/camerachunk
	var/list/obscuredTurfs = list()
	var/list/visibleTurfs = list()
	var/list/obscured = list()
	var/list/cameras = list()
	var/list/turfs = list()
	var/list/seenby = list()
	var/visible = 0
	var/changed = 0
	var/updating = 0
	var/x = 0
	var/y = 0
	var/z = 0

// Add an AI eye to the chunk, then update if changed.

/datum/camerachunk/proc/add(mob/camera/aiEye/eye)
	var/client/client = eye.GetViewerClient()
	if(client)
		client.images += obscured
	eye.visibleCameraChunks += src
	visible++
	seenby += eye
	if(changed && !updating)
		update()

// Remove an AI eye from the chunk, then update if changed.

/datum/camerachunk/proc/remove(mob/camera/aiEye/eye)
	var/client/client = eye.GetViewerClient()
	if(client)
		client.images -= obscured
	eye.visibleCameraChunks -= src
	seenby -= eye
	if(visible > 0)
		visible--

// Called when a chunk has changed. I.E: A wall was deleted.

/datum/camerachunk/proc/visibilityChanged(turf/loc)
	if(!visibleTurfs[loc])
		return
	hasChanged()

// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
// instead be flagged to update the next time an AI Eye moves near it.

/datum/camerachunk/proc/hasChanged(var/update_now = 0)
	if(visible || update_now)
		if(!updating)
			updating = 1
			spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
				update()
				updating = 0
	else
		changed = 1

// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.

/datum/camerachunk/proc/update()

	set background = BACKGROUND_ENABLED

	var/list/newVisibleTurfs = list()

	for(var/camera in cameras)
		var/obj/machinery/camera/c = camera

		if(!c)
			continue

		if(!c.can_use())
			continue

		var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
		if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
			continue

		for(var/turf/t in c.can_see())
			// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
			// List associations use a tree or hashmap of some sort (alongside the list itself)
			//  so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
			newVisibleTurfs[t] = t

	// Removes turf that isn't in turfs.
	newVisibleTurfs &= turfs

	var/list/visAdded = newVisibleTurfs - visibleTurfs
	var/list/visRemoved = visibleTurfs - newVisibleTurfs

	visibleTurfs = newVisibleTurfs
	obscuredTurfs = turfs - newVisibleTurfs

	for(var/turf in visAdded)
		var/turf/t = turf
		if(t.obscured)
			obscured -= t.obscured
			for(var/eye in seenby)
				var/mob/camera/aiEye/m = eye
				if(!m)
					continue
				var/client/client = m.GetViewerClient()
				if(client)
					client.images -= t.obscured

	for(var/turf in visRemoved)
		var/turf/t = turf
		if(obscuredTurfs[t])
			if(!t.obscured)
				t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)

			obscured += t.obscured
			for(var/eye in seenby)
				var/mob/camera/aiEye/m = eye
				if(!m)
					seenby -= m
					continue
				var/client/client = m.GetViewerClient()
				if(client)
					client.images += t.obscured

	changed = 0

// Create a new camera chunk, since the chunks are made as they are needed.

/datum/camerachunk/New(loc, x, y, z)

	// 0xf = 15
	x &= ~(CHUNK_SIZE - 1)
	y &= ~(CHUNK_SIZE - 1)

	src.x = x
	src.y = y
	src.z = z

	for(var/obj/machinery/camera/c in range(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
		if(c.can_use())
			cameras += c

	for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
		turfs[t] = t

	for(var/camera in cameras)
		var/obj/machinery/camera/c = camera
		if(!c)
			continue

		if(!c.can_use())
			continue

		for(var/turf/t in c.can_see())
			// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
			// List associations use a tree or hashmap of some sort (alongside the list itself)
			//  so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
			visibleTurfs[t] = t

	// Removes turf that isn't in turfs.
	visibleTurfs &= turfs

	obscuredTurfs = turfs - visibleTurfs

	for(var/turf in obscuredTurfs)
		var/turf/t = turf
		if(!t.obscured)
			t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
		obscured += t.obscured

#undef UPDATE_BUFFER


code:
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.

/mob/camera/aiEye
	name = "Inactive AI Eye"

	var/list/visibleCameraChunks = list()
	var/mob/living/silicon/ai/ai = null

// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.

/mob/camera/aiEye/proc/setLoc(var/T)

	if(ai)
		if(!isturf(ai.loc))
			return
		T = get_turf(T)
		loc = T
		cameranet.visibility(src)
		if(ai.client)
			ai.client.eye = src
		//Holopad
		if(istype(ai.current, /obj/machinery/hologram/holopad))
			var/obj/machinery/hologram/holopad/H = ai.current
			H.move_hologram(ai)

/mob/camera/aiEye/Move()
	return 0

/mob/camera/aiEye/proc/GetViewerClient()
	if(ai)
		return ai.client
	return null

// AI MOVEMENT

// The AI's "eye". Described on the top of the page.

/mob/living/silicon/ai
	var/mob/camera/aiEye/eyeobj = new()
	var/sprint = 10
	var/cooldown = 0
	var/acceleration = 1

// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
/mob/living/silicon/ai/New()
	..()
	eyeobj.ai = src
	eyeobj.name = "[src.name] (AI Eye)" // Give it a name
	spawn(5)
		eyeobj.loc = src.loc

/mob/living/silicon/ai/Destroy()
	eyeobj.ai = null
	qdel(eyeobj) // No AI, no Eye
	eyeobj = null
	..()

/atom/proc/move_camera_by_click()
	if(istype(usr, /mob/living/silicon/ai))
		var/mob/living/silicon/ai/AI = usr
		if(AI.eyeobj && AI.client.eye == AI.eyeobj)
			AI.cameraFollow = null
			if (isturf(src.loc) || isturf(src))
				AI.eyeobj.setLoc(src)

// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.

/client/proc/AIMove(n, direct, var/mob/living/silicon/ai/user)

	var/initial = initial(user.sprint)
	var/max_sprint = 50

	if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
		user.sprint = initial

	for(var/i = 0; i < max(user.sprint, initial); i += 20)
		var/turf/step = get_turf(get_step(user.eyeobj, direct))
		if(step)
			user.eyeobj.setLoc(step)

	user.cooldown = world.timeofday + 5
	if(user.acceleration)
		user.sprint = min(user.sprint + 0.5, max_sprint)
	else
		user.sprint = initial

	user.cameraFollow = null

	//user.unset_machine() //Uncomment this if it causes problems.
	//user.lightNearbyCamera()
	if (user.camera_light_on)
		user.light_cameras()

// Return to the Core.
/mob/living/silicon/ai/proc/view_core()

	current = null
	cameraFollow = null
	unset_machine()

	if(src.eyeobj && src.loc)
		src.eyeobj.loc = src.loc
	else
		src << "ERROR: Eyeobj not found. Creating new eye..."
		src.eyeobj = new(src.loc)
		src.eyeobj.ai = src
		src.eyeobj.name = "[src.name] (AI Eye)" // Give it a name

	if(client && client.eye)
		client.eye = src
	for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
		c.remove(eyeobj)

/mob/living/silicon/ai/verb/toggle_acceleration()
	set category = "AI Commands"
	set name = "Toggle Camera Acceleration"

	acceleration = !acceleration
	usr << "Camera acceleration has been toggled [acceleration ? "on" : "off"]."


code:
// CREDITS
/*
 Initial code credit for this goes to Uristqwerty.
 Debugging, functionality, all comments and porting by Giacom.

 Everything about freelook (or what we can put in here) will be stored here.

 WHAT IS THIS?

 This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
 only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
 With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players.
 The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and
 cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it.
 This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking,
 the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.

 HOW IT WORKS

 It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
 explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Del().

 Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
 These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
 the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.

 HOW IT UPDATES

 The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
 turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.

 The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created.
 One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area.
 We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk
 that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead
 flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing
 measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking
 sight; for example, we don't update glass airlocks or floors.

 WHERE IS EVERYTHING?

 cameranet.dm	=	Everything about the cameranet datum.
 chunk.dm		=	Everything about the chunk datum.
 eye.dm			=	Everything about the AI and the AIEye.
 updating.dm	=	Everything about triggers that will update chunks.

*/


code:
#define BORG_CAMERA_BUFFER 30

//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.

// TURFS

/turf
	var/image/obscured

/turf/proc/visibilityChanged()
	if(ticker)
		cameranet.updateVisibility(src)

/turf/simulated/Del()
	visibilityChanged()
	..()

/turf/simulated/New()
	..()
	visibilityChanged()

// STRUCTURES

/obj/structure/Destroy()
	if(ticker)
		cameranet.updateVisibility(src)
	..()

/obj/structure/New()
	..()
	if(ticker)
		cameranet.updateVisibility(src)

// EFFECTS

/obj/effect/Destroy()
	if(ticker)
		cameranet.updateVisibility(src)
	..()

/obj/effect/New()
	..()
	if(ticker)
		cameranet.updateVisibility(src)

// DOORS

// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/proc/update_freelook_sight()
	// Glass door glass = 1
	// don't check then?
	if(!glass && cameranet)
		cameranet.updateVisibility(src, 0)

// ROBOT MOVEMENT

// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/robot/var/updating = 0

/mob/living/silicon/robot/Move()
	var/oldLoc = src.loc
	. = ..()
	if(.)
		if(src.camera)
			if(!updating)
				updating = 1
				spawn(BORG_CAMERA_BUFFER)
					if(oldLoc != src.loc)
						cameranet.updatePortableCamera(src.camera)
					updating = 0

// CAMERA

// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.

/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
	..(user, choice)
	if(src.can_use())
		cameranet.addCamera(src)
	else
		src.set_light(0)
		cameranet.removeCamera(src)

/obj/machinery/camera/New()
	..()
	cameranet.cameras += src
	cameranet.addCamera(src)

/obj/machinery/camera/Destroy()
	cameranet.cameras -= src
	cameranet.removeCamera(src)
	..()

#undef BORG_CAMERA_BUFFER


code:
/mob/living/silicon/ai/proc/show_laws_verb()
	set category = "AI Commands"
	set name = "Show Laws"
	src.show_laws()

/mob/living/silicon/ai/show_laws(var/everyone = 0)
	var/who

	if (everyone)
		who = world
	else
		who = src
	who << "<b>Obey these laws:</b>"

	src.laws_sanity_check()
	src.laws.show_laws(who)


code:
/mob/living/silicon/ai/Life()
	if (src.stat == 2)
		return
	else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
		//Being dead doesn't mean your temperature never changes
		var/turf/T = get_turf(src)

		if (src.stat!=0)
			src.cameraFollow = null
			src.reset_view(null)
			src.unset_machine()

		src.updatehealth()

		update_gravity(mob_has_gravity())

		if (src.malfhack)
			if (src.malfhack.aidisabled)
				src << "ERROR: APC access disabled, hack attempt canceled."
				src.malfhacking = 0
				src.malfhack = null

		if (src.health <= config.health_threshold_dead)
			death()
			return

		if (src.machine)
			if (!( src.machine.check_eye(src) ))
				src.reset_view(null)

		// Handle power damage (oxy)
		if(src.aiRestorePowerRoutine != 0)
			// Lost power
			adjustOxyLoss(1)
		else
			// Gain Power
			adjustOxyLoss(-1)

		//stage = 1
		//if (istype(src, /mob/living/silicon/ai)) // Are we not sure what we are?
		var/blindness = 0
		//stage = 2
		var/area/loc = null
		if (istype(T, /turf))
			//stage = 3
			loc = T.loc
			if (istype(loc, /area))
				//stage = 4
				if (!loc.power_equip && !istype(src.loc,/obj/item))
					//stage = 5
					blindness = 1

		if (!blindness)
			//stage = 4.5
			if(src.blind)
				if (src.blind.layer != 0)
					src.blind.layer = 0
			src.sight |= SEE_TURFS
			src.sight |= SEE_MOBS
			src.sight |= SEE_OBJS
			src.see_in_dark = 8
			src.see_invisible = SEE_INVISIBLE_LEVEL_TWO
			if(see_override)
				see_invisible = see_override

			var/area/home = get_area(src)
			if(!home)	return//something to do with malf fucking things up I guess. <-- aisat is gone. is this still necessary? ~Carn
			if(home.powered(EQUIP))
				home.use_power(1000, EQUIP)

			if (src:aiRestorePowerRoutine==2)
				src << "Alert cancelled. Power has been restored without our assistance."
				src:aiRestorePowerRoutine = 0
				src.blind.layer = 0
				return
			else if (src:aiRestorePowerRoutine==3)
				src << "Alert cancelled. Power has been restored."
				src:aiRestorePowerRoutine = 0
				src.blind.layer = 0
				return
		else

			//stage = 6
			src.blind.screen_loc = "1,1 to 15,15"
			if (src.blind.layer!=18)
				src.blind.layer = 18
			src.sight = src.sight&~SEE_TURFS
			src.sight = src.sight&~SEE_MOBS
			src.sight = src.sight&~SEE_OBJS
			src.see_in_dark = 0
			src.see_invisible = SEE_INVISIBLE_LIVING

			if (((!loc.power_equip) || istype(T, /turf/space)) && !istype(src.loc,/obj/item))
				if (src:aiRestorePowerRoutine==0)
					src:aiRestorePowerRoutine = 1

					src << "You've lost power!"
//							world << "DEBUG CODE TIME! [loc] is the area the AI is sucking power from"
					//if (!is_special_character(src))
						//src.set_zeroth_law("")
					//src.clear_supplied_laws() // Don't reset our laws.
					//var/time = time2text(world.realtime,"hh:mm:ss")
					//lawchanges.Add("[time] : [src.name]'s noncore laws have been reset due to power failure")
					spawn(20)
						src << "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection."
						sleep(50)
						if (loc.power_equip)
							if (!istype(T, /turf/space))
								src << "Alert cancelled. Power has been restored without our assistance."
								src.aiRestorePowerRoutine = 0
								src.blind.layer = 0
								return
						src << "Fault confirmed: missing external power. Shutting down main control system to save power."
						sleep(20)
						src << "Emergency control system online. Verifying connection to power network."
						sleep(50)
						if (istype(T, /turf/space))
							src << "Unable to verify! No power connection detected!"
							src:aiRestorePowerRoutine = 2
							return
						src << "Connection verified. Searching for APC in power network."
						sleep(50)
						var/obj/machinery/power/apc/theAPC = null
/*
						for (var/something in loc)
							if (istype(something, /obj/machinery/power/apc))
								if (!(something:stat & BROKEN))
									theAPC = something
									break
*/
						var/PRP //like ERP with the code, at least this stuff is no more 4x sametext
						for (PRP=1, PRP<=4, PRP++)
							var/area/AIarea = get_area(src)
							for (var/obj/machinery/power/apc/APC in AIarea)
								if (!(APC.stat & BROKEN))
									theAPC = APC
									break
							if (!theAPC)
								switch(PRP)
									if (1) src << "Unable to locate APC!"
									else src << "Lost connection with the APC!"
								src:aiRestorePowerRoutine = 2
								return
							if (loc.power_equip)
								if (!istype(T, /turf/space))
									src << "Alert cancelled. Power has been restored without our assistance."
									src:aiRestorePowerRoutine = 0
									src.blind.layer = 0 //This, too, is a fix to issue 603
									return
							switch(PRP)
								if (1) src << "APC located. Optimizing route to APC to avoid needless power waste."
								if (2) src << "Best route identified. Hacking offline APC power port."
								if (3) src << "Power port upload access confirmed. Loading control program into APC power port software."
								if (4)
									src << "Transfer complete. Forcing APC to execute program."
									sleep(50)
									src << "Receiving control information from APC."
									sleep(2)
									//bring up APC dialog
									apc_override = 1
									theAPC.attack_ai(src)
									apc_override = 0
									src:aiRestorePowerRoutine = 3
									src << "Here are your current laws:"
									src.show_laws()
							sleep(50)
							theAPC = null

/mob/living/silicon/ai/updatehealth()
	if(status_flags & GODMODE)
		health = maxHealth
		stat = CONSCIOUS
		return
	health = maxHealth - getOxyLoss() - getToxLoss() - getBruteLoss()
	if(!fire_res_on_core)
		health -= getFireLoss()


code:
/mob/living/silicon/ai/Login()	//ThisIsDumb(TM) TODO: tidy this up �_� ~Carn
	..()
	for(var/obj/effect/rune/rune in world)
		var/image/blood = image(loc = rune)
		blood.override = 1
		client.images += blood
	regenerate_icons()
	flash = new /obj/screen()
	flash.icon_state = "blank"
	flash.name = "flash"
	flash.screen_loc = "1,1 to 15,15"
	flash.layer = 17
	blind = new /obj/screen()
	blind.icon_state = "black"
	blind.name = " "
	blind.screen_loc = "1,1 to 15,15"
	blind.layer = 0
	client.screen.Add( blind, flash )

	if(stat != DEAD)
		for(var/obj/machinery/ai_status_display/O in machines) //change status
			O.mode = 1
			O.emotion = "Neutral"
	src.view_core()
	return


code:
/mob/living/silicon/ai/Logout()
	..()
	for(var/obj/machinery/ai_status_display/O in world) //change status
		O.mode = 0
	if(!isturf(loc))
		if (client)
			client.eye = loc
			client.perspective = EYE_PERSPECTIVE
	src.view_core()
	return


code:
/mob/living/silicon/ai/say(var/message)
	if(parent && istype(parent) && parent.stat != 2) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
		parent.say(message)
		return
	..(message)

/mob/living/silicon/ai/compose_track_href(atom/movable/speaker, namepart)
	//this proc assumes that the message originated from a radio. if the speaker is not a virtual speaker this will probably fuck up hard.
	var/mob/M = speaker.GetSource()
	if(M)
		return ""
	return ""

/mob/living/silicon/ai/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq)
	//Also includes the  for AI hrefs, for convenience.
	return " [radio_freq ? "(" + speaker.GetJob() + ")" : ""]" + "[speaker.GetSource() ? "" : ""]"

/mob/living/silicon/ai/say_quote(var/text)
	var/ending = copytext(text, length(text))

	if(ending == "?")
		return "queries, \"[text]\"";
	else if(copytext(text, length(text) - 1) == "!!")
		return "alarms, \"[text]\"";
	else if(ending == "!")
		return "declares, \"[text]\"";

	return "states, \"[text]\"";

/mob/living/silicon/ai/IsVocal()
	return !config.silent_ai

/mob/living/silicon/ai/radio(message, message_mode)
	if(!radio_enabled || aiRestorePowerRoutine || stat) //AI cannot speak if radio is disabled (via intellicard) or depowered.
		src << "Your radio transmitter is offline!"
		return 0
	..(message,message_mode)

/mob/living/silicon/ai/get_message_mode(message)
	if(copytext(message, 1, 3) in list(":h", ":H", ".h", ".H", "#h", "#H"))
		return MODE_HOLOPAD
	else
		return ..()

/mob/living/silicon/ai/handle_inherent_channels(message, message_mode)
	. = ..()
	if(.)
		return .

	if(message_mode == MODE_HOLOPAD)
		holopad_talk(message)
		return 1

//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(var/message)
	log_say("[key_name(src)] : [message]")

	message = trim(message)

	if (!message)
		return

	var/obj/machinery/hologram/holopad/T = current
	if(istype(T) && T.masters[src])//If there is a hologram and its master is the user.
		send_speech(message, 7, T, "R")
		src << "Holopad transmitted, [real_name] \"[message]\""//The AI can "hear" its own message.
	else
		src << "No holopad connected."
	return

// Make sure that the code compiles with AI_VOX undefined
#ifdef AI_VOX

var/announcing_vox = 0 // Stores the time of the last announcement
var/const/VOX_CHANNEL = 200
var/const/VOX_DELAY = 600

/mob/living/silicon/ai/verb/announcement_help()

	set name = "Announcement Help"
	set desc = "Display a list of vocal words to announce to the crew."
	set category = "AI Commands"

	var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.
 \

You can also click on the word to preview it.
\

You can only say 30 words for every announcement.
\

Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.

\
	WARNING:
Misuse of the announcement system will get you job banned.
"

	var/index = 0
	for(var/word in vox_sounds)
		index++
		dat += "[capitalize(word)]"
		if(index != vox_sounds.len)
			dat += " / "

	var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
	popup.set_content(dat)
	popup.open()

/mob/living/silicon/ai/proc/announcement()
	if(announcing_vox > world.time)
		src << "Please wait [round((announcing_vox - world.time) / 10)] seconds."
		return

	var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text

	last_announcement = message

	if(!message || announcing_vox > world.time)
		return

	if(stat != CONSCIOUS)
		return

	if(control_disabled)
		src << "Wireless interface disabled, unable to interact with announcement PA."
		return

	var/list/words = text2list(trim(message), " ")
	var/list/incorrect_words = list()

	if(words.len > 30)
		words.len = 30

	for(var/word in words)
		word = lowertext(trim(word))
		if(!word)
			words -= word
			continue
		if(!vox_sounds[word])
			incorrect_words += word

	if(incorrect_words.len)
		src << "These words are not available on the announcement system: [english_list(incorrect_words)]."
		return

	announcing_vox = world.time + VOX_DELAY

	log_game("[key_name(src)] made a vocal announcement with the following message: [message].")

	for(var/word in words)
		play_vox_word(word, src.z, null)
/*
	for(var/mob/M in player_list)
		if(M.client)
			var/turf/T = get_turf(M)
			var/turf/our_turf = get_turf(src)
			if(T.z == our_turf.z)
				M << "AI announcement: [message]"
*/

/proc/play_vox_word(var/word, var/z_level, var/mob/only_listener)

	word = lowertext(word)

	if(vox_sounds[word])

		var/sound_file = vox_sounds[word]
		var/sound/voice = sound(sound_file, wait = 1, channel = VOX_CHANNEL)
		voice.status = SOUND_STREAM

 		// If there is no single listener, broadcast to everyone in the same z level
		if(!only_listener)
			// Play voice for all mobs in the z level
			for(var/mob/M in player_list)
				if(M.client && !M.ear_deaf)
					var/turf/T = get_turf(M)
					if(T.z == z_level)
						M << voice
		else
			only_listener << voice
		return 1
	return 0

#endif


code:
// List is required to compile the resources into the game when it loads.
// Dynamically loading it has bad results with sounds overtaking each other, even with the wait variable.
#ifdef AI_VOX

var/list/vox_sounds = list("," = 'sound/AI_vox/,.ogg',
"." = 'sound/AI_vox/..ogg',
"a" = 'sound/AI_vox/a.ogg',
"accelerating" = 'sound/AI_vox/accelerating.ogg',
"accelerator" = 'sound/AI_vox/accelerator.ogg',
"accepted" = 'sound/AI_vox/accepted.ogg',
"access" = 'sound/AI_vox/access.ogg',
"acknowledge" = 'sound/AI_vox/acknowledge.ogg',
"acknowledged" = 'sound/AI_vox/acknowledged.ogg',
"acquired" = 'sound/AI_vox/acquired.ogg',
"acquisition" = 'sound/AI_vox/acquisition.ogg',
"across" = 'sound/AI_vox/across.ogg',
"activate" = 'sound/AI_vox/activate.ogg',
"activated" = 'sound/AI_vox/activated.ogg',
"activity" = 'sound/AI_vox/activity.ogg',
"adios" = 'sound/AI_vox/adios.ogg',
"administration" = 'sound/AI_vox/administration.ogg',
"advanced" = 'sound/AI_vox/advanced.ogg',
"after" = 'sound/AI_vox/after.ogg',
"agent" = 'sound/AI_vox/agent.ogg',
"alarm" = 'sound/AI_vox/alarm.ogg',
"alert" = 'sound/AI_vox/alert.ogg',
"alien" = 'sound/AI_vox/alien.ogg',
"aligned" = 'sound/AI_vox/aligned.ogg',
"all" = 'sound/AI_vox/all.ogg',
"alpha" = 'sound/AI_vox/alpha.ogg',
"am" = 'sound/AI_vox/am.ogg',
"amigo" = 'sound/AI_vox/amigo.ogg',
"ammunition" = 'sound/AI_vox/ammunition.ogg',
"an" = 'sound/AI_vox/an.ogg',
"and" = 'sound/AI_vox/and.ogg',
"announcement" = 'sound/AI_vox/announcement.ogg',
"anomalous" = 'sound/AI_vox/anomalous.ogg',
"antenna" = 'sound/AI_vox/antenna.ogg',
"any" = 'sound/AI_vox/any.ogg',
"apprehend" = 'sound/AI_vox/apprehend.ogg',
"approach" = 'sound/AI_vox/approach.ogg',
"are" = 'sound/AI_vox/are.ogg',
"area" = 'sound/AI_vox/area.ogg',
"arm" = 'sound/AI_vox/arm.ogg',
"armed" = 'sound/AI_vox/armed.ogg',
"armor" = 'sound/AI_vox/armor.ogg',
"armory" = 'sound/AI_vox/armory.ogg',
"arrest" = 'sound/AI_vox/arrest.ogg',
"ass" = 'sound/AI_vox/ass.ogg',
"at" = 'sound/AI_vox/at.ogg',
"atomic" = 'sound/AI_vox/atomic.ogg',
"attention" = 'sound/AI_vox/attention.ogg',
"authorize" = 'sound/AI_vox/authorize.ogg',
"authorized" = 'sound/AI_vox/authorized.ogg',
"automatic" = 'sound/AI_vox/automatic.ogg',
"away" = 'sound/AI_vox/away.ogg',
"b" = 'sound/AI_vox/b.ogg',
"back" = 'sound/AI_vox/back.ogg',
"backman" = 'sound/AI_vox/backman.ogg',
"bad" = 'sound/AI_vox/bad.ogg',
"bag" = 'sound/AI_vox/bag.ogg',
"bailey" = 'sound/AI_vox/bailey.ogg',
"barracks" = 'sound/AI_vox/barracks.ogg',
"base" = 'sound/AI_vox/base.ogg',
"bay" = 'sound/AI_vox/bay.ogg',
"be" = 'sound/AI_vox/be.ogg',
"been" = 'sound/AI_vox/been.ogg',
"before" = 'sound/AI_vox/before.ogg',
"beyond" = 'sound/AI_vox/beyond.ogg',
"biohazard" = 'sound/AI_vox/biohazard.ogg',
"biological" = 'sound/AI_vox/biological.ogg',
"birdwell" = 'sound/AI_vox/birdwell.ogg',
"bizwarn" = 'sound/AI_vox/bizwarn.ogg',
"black" = 'sound/AI_vox/black.ogg',
"blast" = 'sound/AI_vox/blast.ogg',
"blocked" = 'sound/AI_vox/blocked.ogg',
"bloop" = 'sound/AI_vox/bloop.ogg',
"blue" = 'sound/AI_vox/blue.ogg',
"bottom" = 'sound/AI_vox/bottom.ogg',
"bravo" = 'sound/AI_vox/bravo.ogg',
"breach" = 'sound/AI_vox/breach.ogg',
"breached" = 'sound/AI_vox/breached.ogg',
"break" = 'sound/AI_vox/break.ogg',
"bridge" = 'sound/AI_vox/bridge.ogg',
"bust" = 'sound/AI_vox/bust.ogg',
"but" = 'sound/AI_vox/but.ogg',
"button" = 'sound/AI_vox/button.ogg',
"buzwarn" = 'sound/AI_vox/buzwarn.ogg',
"bypass" = 'sound/AI_vox/bypass.ogg',
"c" = 'sound/AI_vox/c.ogg',
"cable" = 'sound/AI_vox/cable.ogg',
"call" = 'sound/AI_vox/call.ogg',
"called" = 'sound/AI_vox/called.ogg',
"canal" = 'sound/AI_vox/canal.ogg',
"cap" = 'sound/AI_vox/cap.ogg',
"captain" = 'sound/AI_vox/captain.ogg',
"capture" = 'sound/AI_vox/capture.ogg',
"captured" = 'sound/AI_vox/captured.wav',
"ceiling" = 'sound/AI_vox/ceiling.ogg',
"celsius" = 'sound/AI_vox/celsius.ogg',
"center" = 'sound/AI_vox/center.ogg',
"centi" = 'sound/AI_vox/centi.ogg',
"central" = 'sound/AI_vox/central.ogg',
"chamber" = 'sound/AI_vox/chamber.ogg',
"charlie" = 'sound/AI_vox/charlie.ogg',
"check" = 'sound/AI_vox/check.ogg',
"checkpoint" = 'sound/AI_vox/checkpoint.ogg',
"chemical" = 'sound/AI_vox/chemical.ogg',
"cleanup" = 'sound/AI_vox/cleanup.ogg',
"clear" = 'sound/AI_vox/clear.ogg',
"clearance" = 'sound/AI_vox/clearance.ogg',
"close" = 'sound/AI_vox/close.ogg',
"clown" = 'sound/AI_vox/clown.ogg',
"code" = 'sound/AI_vox/code.ogg',
"coded" = 'sound/AI_vox/coded.ogg',
"collider" = 'sound/AI_vox/collider.ogg',
"command" = 'sound/AI_vox/command.ogg',
"communication" = 'sound/AI_vox/communication.ogg',
"complex" = 'sound/AI_vox/complex.ogg',
"computer" = 'sound/AI_vox/computer.ogg',
"condition" = 'sound/AI_vox/condition.ogg',
"containment" = 'sound/AI_vox/containment.ogg',
"contamination" = 'sound/AI_vox/contamination.ogg',
"control" = 'sound/AI_vox/control.ogg',
"coolant" = 'sound/AI_vox/coolant.ogg',
"coomer" = 'sound/AI_vox/coomer.ogg',
"core" = 'sound/AI_vox/core.ogg',
"correct" = 'sound/AI_vox/correct.ogg',
"corridor" = 'sound/AI_vox/corridor.ogg',
"crew" = 'sound/AI_vox/crew.ogg',
"cross" = 'sound/AI_vox/cross.ogg',
"cryogenic" = 'sound/AI_vox/cryogenic.ogg',
"d" = 'sound/AI_vox/d.ogg',
"dadeda" = 'sound/AI_vox/dadeda.ogg',
"damage" = 'sound/AI_vox/damage.ogg',
"damaged" = 'sound/AI_vox/damaged.ogg',
"danger" = 'sound/AI_vox/danger.ogg',
"day" = 'sound/AI_vox/day.ogg',
"deactivated" = 'sound/AI_vox/deactivated.ogg',
"decompression" = 'sound/AI_vox/decompression.ogg',
"decontamination" = 'sound/AI_vox/decontamination.ogg',
"deeoo" = 'sound/AI_vox/deeoo.ogg',
"defense" = 'sound/AI_vox/defense.ogg',
"degrees" = 'sound/AI_vox/degrees.ogg',
"delta" = 'sound/AI_vox/delta.ogg',
"denied" = 'sound/AI_vox/denied.ogg',
"deploy" = 'sound/AI_vox/deploy.ogg',
"deployed" = 'sound/AI_vox/deployed.ogg',
"destroy" = 'sound/AI_vox/destroy.ogg',
"destroyed" = 'sound/AI_vox/destroyed.ogg',
"detain" = 'sound/AI_vox/detain.ogg',
"detected" = 'sound/AI_vox/detected.ogg',
"detonation" = 'sound/AI_vox/detonation.ogg',
"device" = 'sound/AI_vox/device.ogg',
"did" = 'sound/AI_vox/did.ogg',
"die" = 'sound/AI_vox/die.ogg',
"dimensional" = 'sound/AI_vox/dimensional.ogg',
"dirt" = 'sound/AI_vox/dirt.ogg',
"disengaged" = 'sound/AI_vox/disengaged.ogg',
"dish" = 'sound/AI_vox/dish.ogg',
"disposal" = 'sound/AI_vox/disposal.ogg',
"distance" = 'sound/AI_vox/distance.ogg',
"distortion" = 'sound/AI_vox/distortion.ogg',
"do" = 'sound/AI_vox/do.ogg',
"doctor" = 'sound/AI_vox/doctor.ogg',
"doop" = 'sound/AI_vox/doop.ogg',
"door" = 'sound/AI_vox/door.ogg',
"down" = 'sound/AI_vox/down.ogg',
"dual" = 'sound/AI_vox/dual.ogg',
"duct" = 'sound/AI_vox/duct.ogg',
"e" = 'sound/AI_vox/e.ogg',
"east" = 'sound/AI_vox/east.ogg',
"echo" = 'sound/AI_vox/echo.ogg',
"ed" = 'sound/AI_vox/ed.ogg',
"effect" = 'sound/AI_vox/effect.ogg',
"egress" = 'sound/AI_vox/egress.ogg',
"eight" = 'sound/AI_vox/eight.ogg',
"eighteen" = 'sound/AI_vox/eighteen.ogg',
"eighty" = 'sound/AI_vox/eighty.ogg',
"electric" = 'sound/AI_vox/electric.ogg',
"electromagnetic" = 'sound/AI_vox/electromagnetic.ogg',
"elevator" = 'sound/AI_vox/elevator.ogg',
"eleven" = 'sound/AI_vox/eleven.ogg',
"eliminate" = 'sound/AI_vox/eliminate.ogg',
"emergency" = 'sound/AI_vox/emergency.ogg',
"enemy" = 'sound/AI_vox/enemy.wav',
"energy" = 'sound/AI_vox/energy.ogg',
"engage" = 'sound/AI_vox/engage.ogg',
"engaged" = 'sound/AI_vox/engaged.ogg',
"engine" = 'sound/AI_vox/engine.ogg',
"enter" = 'sound/AI_vox/enter.ogg',
"entry" = 'sound/AI_vox/entry.ogg',
"environment" = 'sound/AI_vox/environment.ogg',
"error" = 'sound/AI_vox/error.ogg',
"escape" = 'sound/AI_vox/escape.ogg',
"evacuate" = 'sound/AI_vox/evacuate.ogg',
"exchange" = 'sound/AI_vox/exchange.ogg',
"exit" = 'sound/AI_vox/exit.ogg',
"expect" = 'sound/AI_vox/expect.ogg',
"experiment" = 'sound/AI_vox/experiment.ogg',
"experimental" = 'sound/AI_vox/experimental.ogg',
"explode" = 'sound/AI_vox/explode.ogg',
"explosion" = 'sound/AI_vox/explosion.ogg',
"exposure" = 'sound/AI_vox/exposure.ogg',
"exterminate" = 'sound/AI_vox/exterminate.ogg',
"extinguish" = 'sound/AI_vox/extinguish.ogg',
"extinguisher" = 'sound/AI_vox/extinguisher.ogg',
"extreme" = 'sound/AI_vox/extreme.ogg',
"f" = 'sound/AI_vox/f.ogg',
"face" = 'sound/AI_vox/face.ogg',
"facility" = 'sound/AI_vox/facility.ogg',
"fahrenheit" = 'sound/AI_vox/fahrenheit.ogg',
"failed" = 'sound/AI_vox/failed.ogg',
"failure" = 'sound/AI_vox/failure.ogg',
"farthest" = 'sound/AI_vox/farthest.ogg',
"fast" = 'sound/AI_vox/fast.ogg',
"feet" = 'sound/AI_vox/feet.ogg',
"field" = 'sound/AI_vox/field.ogg',
"fifteen" = 'sound/AI_vox/fifteen.ogg',
"fifth" = 'sound/AI_vox/fifth.ogg',
"fifty" = 'sound/AI_vox/fifty.ogg',
"final" = 'sound/AI_vox/final.ogg',
"fine" = 'sound/AI_vox/fine.ogg',
"fire" = 'sound/AI_vox/fire.ogg',
"first" = 'sound/AI_vox/first.ogg',
"five" = 'sound/AI_vox/five.ogg',
"flag" = 'sound/AI_vox/flag.wav',
"flooding" = 'sound/AI_vox/flooding.ogg',
"floor" = 'sound/AI_vox/floor.ogg',
"fool" = 'sound/AI_vox/fool.ogg',
"for" = 'sound/AI_vox/for.ogg',
"forbidden" = 'sound/AI_vox/forbidden.ogg',
"force" = 'sound/AI_vox/force.ogg',
"forms" = 'sound/AI_vox/forms.ogg',
"found" = 'sound/AI_vox/found.ogg',
"four" = 'sound/AI_vox/four.ogg',
"fourteen" = 'sound/AI_vox/fourteen.ogg',
"fourth" = 'sound/AI_vox/fourth.ogg',
"fourty" = 'sound/AI_vox/fourty.ogg',
"foxtrot" = 'sound/AI_vox/foxtrot.ogg',
"freeman" = 'sound/AI_vox/freeman.ogg',
"freezer" = 'sound/AI_vox/freezer.ogg',
"from" = 'sound/AI_vox/from.ogg',
"front" = 'sound/AI_vox/front.ogg',
"fuel" = 'sound/AI_vox/fuel.ogg',
"g" = 'sound/AI_vox/g.ogg',
"get" = 'sound/AI_vox/get.ogg',
"go" = 'sound/AI_vox/go.ogg',
"going" = 'sound/AI_vox/going.ogg',
"good" = 'sound/AI_vox/good.ogg',
"goodbye" = 'sound/AI_vox/goodbye.ogg',
"gordon" = 'sound/AI_vox/gordon.ogg',
"got" = 'sound/AI_vox/got.ogg',
"government" = 'sound/AI_vox/government.ogg',
"granted" = 'sound/AI_vox/granted.ogg',
"great" = 'sound/AI_vox/great.ogg',
"green" = 'sound/AI_vox/green.ogg',
"grenade" = 'sound/AI_vox/grenade.ogg',
"guard" = 'sound/AI_vox/guard.ogg',
"gulf" = 'sound/AI_vox/gulf.ogg',
"gun" = 'sound/AI_vox/gun.ogg',
"guthrie" = 'sound/AI_vox/guthrie.ogg',
"handling" = 'sound/AI_vox/handling.ogg',
"hangar" = 'sound/AI_vox/hangar.ogg',
"has" = 'sound/AI_vox/has.ogg',
"have" = 'sound/AI_vox/have.ogg',
"hazard" = 'sound/AI_vox/hazard.ogg',
"head" = 'sound/AI_vox/head.ogg',
"health" = 'sound/AI_vox/health.ogg',
"heat" = 'sound/AI_vox/heat.ogg',
"helicopter" = 'sound/AI_vox/helicopter.ogg',
"helium" = 'sound/AI_vox/helium.ogg',
"hello" = 'sound/AI_vox/hello.ogg',
"help" = 'sound/AI_vox/help.ogg',
"here" = 'sound/AI_vox/here.ogg',
"hide" = 'sound/AI_vox/hide.ogg',
"high" = 'sound/AI_vox/high.ogg',
"highest" = 'sound/AI_vox/highest.ogg',
"hit" = 'sound/AI_vox/hit.ogg',
"holds" = 'sound/AI_vox/holds.wav',
"hole" = 'sound/AI_vox/hole.ogg',
"hostile" = 'sound/AI_vox/hostile.ogg',
"hot" = 'sound/AI_vox/hot.ogg',
"hotel" = 'sound/AI_vox/hotel.ogg',
"hour" = 'sound/AI_vox/hour.ogg',
"hours" = 'sound/AI_vox/hours.ogg',
"hundred" = 'sound/AI_vox/hundred.ogg',
"hydro" = 'sound/AI_vox/hydro.ogg',
"i" = 'sound/AI_vox/i.ogg',
"idiot" = 'sound/AI_vox/idiot.ogg',
"illegal" = 'sound/AI_vox/illegal.ogg',
"immediate" = 'sound/AI_vox/immediate.ogg',
"immediately" = 'sound/AI_vox/immediately.ogg',
"in" = 'sound/AI_vox/in.ogg',
"inches" = 'sound/AI_vox/inches.ogg',
"india" = 'sound/AI_vox/india.ogg',
"ing" = 'sound/AI_vox/ing.ogg',
"inoperative" = 'sound/AI_vox/inoperative.ogg',
"inside" = 'sound/AI_vox/inside.ogg',
"inspection" = 'sound/AI_vox/inspection.ogg',
"inspector" = 'sound/AI_vox/inspector.ogg',
"interchange" = 'sound/AI_vox/interchange.ogg',
"intruder" = 'sound/AI_vox/intruder.ogg',
"invallid" = 'sound/AI_vox/invallid.ogg',
"invasion" = 'sound/AI_vox/invasion.ogg',
"is" = 'sound/AI_vox/is.ogg',
"it" = 'sound/AI_vox/it.ogg',
"johnson" = 'sound/AI_vox/johnson.ogg',
"juliet" = 'sound/AI_vox/juliet.ogg',
"key" = 'sound/AI_vox/key.ogg',
"kill" = 'sound/AI_vox/kill.ogg',
"kilo" = 'sound/AI_vox/kilo.ogg',
"kit" = 'sound/AI_vox/kit.ogg',
"lab" = 'sound/AI_vox/lab.ogg',
"lambda" = 'sound/AI_vox/lambda.ogg',
"laser" = 'sound/AI_vox/laser.ogg',
"last" = 'sound/AI_vox/last.ogg',
"launch" = 'sound/AI_vox/launch.ogg',
"leak" = 'sound/AI_vox/leak.ogg',
"leave" = 'sound/AI_vox/leave.ogg',
"left" = 'sound/AI_vox/left.ogg',
"legal" = 'sound/AI_vox/legal.ogg',
"level" = 'sound/AI_vox/level.ogg',
"lever" = 'sound/AI_vox/lever.ogg',
"lie" = 'sound/AI_vox/lie.ogg',
"lieutenant" = 'sound/AI_vox/lieutenant.ogg',
"life" = 'sound/AI_vox/life.ogg',
"light" = 'sound/AI_vox/light.ogg',
"lima" = 'sound/AI_vox/lima.ogg',
"liquid" = 'sound/AI_vox/liquid.ogg',
"loading" = 'sound/AI_vox/loading.ogg',
"locate" = 'sound/AI_vox/locate.ogg',
"located" = 'sound/AI_vox/located.ogg',
"location" = 'sound/AI_vox/location.ogg',
"lock" = 'sound/AI_vox/lock.ogg',
"locked" = 'sound/AI_vox/locked.ogg',
"locker" = 'sound/AI_vox/locker.ogg',
"lockout" = 'sound/AI_vox/lockout.ogg',
"lower" = 'sound/AI_vox/lower.ogg',
"lowest" = 'sound/AI_vox/lowest.ogg',
"magnetic" = 'sound/AI_vox/magnetic.ogg',
"main" = 'sound/AI_vox/main.ogg',
"maintenance" = 'sound/AI_vox/maintenance.ogg',
"malfunction" = 'sound/AI_vox/malfunction.ogg',
"man" = 'sound/AI_vox/man.ogg',
"mass" = 'sound/AI_vox/mass.ogg',
"materials" = 'sound/AI_vox/materials.ogg',
"maximum" = 'sound/AI_vox/maximum.ogg',
"may" = 'sound/AI_vox/may.ogg',
"med" = 'sound/AI_vox/med.ogg',
"medical" = 'sound/AI_vox/medical.ogg',
"men" = 'sound/AI_vox/men.ogg',
"mercy" = 'sound/AI_vox/mercy.ogg',
"mesa" = 'sound/AI_vox/mesa.ogg',
"message" = 'sound/AI_vox/message.ogg',
"meter" = 'sound/AI_vox/meter.ogg',
"micro" = 'sound/AI_vox/micro.ogg',
"middle" = 'sound/AI_vox/middle.ogg',
"mike" = 'sound/AI_vox/mike.ogg',
"miles" = 'sound/AI_vox/miles.ogg',
"military" = 'sound/AI_vox/military.ogg',
"milli" = 'sound/AI_vox/milli.ogg',
"million" = 'sound/AI_vox/million.ogg',
"minefield" = 'sound/AI_vox/minefield.ogg',
"minimum" = 'sound/AI_vox/minimum.ogg',
"minutes" = 'sound/AI_vox/minutes.ogg',
"mister" = 'sound/AI_vox/mister.ogg',
"mode" = 'sound/AI_vox/mode.ogg',
"motor" = 'sound/AI_vox/motor.ogg',
"motorpool" = 'sound/AI_vox/motorpool.ogg',
"move" = 'sound/AI_vox/move.ogg',
"must" = 'sound/AI_vox/must.ogg',
"nearest" = 'sound/AI_vox/nearest.ogg',
"nice" = 'sound/AI_vox/nice.ogg',
"nine" = 'sound/AI_vox/nine.ogg',
"nineteen" = 'sound/AI_vox/nineteen.ogg',
"ninety" = 'sound/AI_vox/ninety.ogg',
"no" = 'sound/AI_vox/no.ogg',
"nominal" = 'sound/AI_vox/nominal.ogg',
"north" = 'sound/AI_vox/north.ogg',
"not" = 'sound/AI_vox/not.ogg',
"november" = 'sound/AI_vox/november.ogg',
"now" = 'sound/AI_vox/now.ogg',
"number" = 'sound/AI_vox/number.ogg',
"objective" = 'sound/AI_vox/objective.ogg',
"observation" = 'sound/AI_vox/observation.ogg',
"of" = 'sound/AI_vox/of.ogg',
"officer" = 'sound/AI_vox/officer.ogg',
"ok" = 'sound/AI_vox/ok.ogg',
"on" = 'sound/AI_vox/on.ogg',
"one" = 'sound/AI_vox/one.ogg',
"open" = 'sound/AI_vox/open.ogg',
"operating" = 'sound/AI_vox/operating.ogg',
"operations" = 'sound/AI_vox/operations.ogg',
"operative" = 'sound/AI_vox/operative.ogg',
"option" = 'sound/AI_vox/option.ogg',
"order" = 'sound/AI_vox/order.ogg',
"organic" = 'sound/AI_vox/organic.ogg',
"oscar" = 'sound/AI_vox/oscar.ogg',
"out" = 'sound/AI_vox/out.ogg',
"outside" = 'sound/AI_vox/outside.ogg',
"over" = 'sound/AI_vox/over.ogg',
"overload" = 'sound/AI_vox/overload.ogg',
"override" = 'sound/AI_vox/override.ogg',
"pacify" = 'sound/AI_vox/pacify.ogg',
"pain" = 'sound/AI_vox/pain.ogg',
"pal" = 'sound/AI_vox/pal.ogg',
"panel" = 'sound/AI_vox/panel.ogg',
"percent" = 'sound/AI_vox/percent.ogg',
"perimeter" = 'sound/AI_vox/perimeter.ogg',
"permitted" = 'sound/AI_vox/permitted.ogg',
"personnel" = 'sound/AI_vox/personnel.ogg',
"pipe" = 'sound/AI_vox/pipe.ogg',
"plant" = 'sound/AI_vox/plant.ogg',
"platform" = 'sound/AI_vox/platform.ogg',
"please" = 'sound/AI_vox/please.ogg',
"point" = 'sound/AI_vox/point.ogg',
"portal" = 'sound/AI_vox/portal.ogg',
"power" = 'sound/AI_vox/power.ogg',
"presence" = 'sound/AI_vox/presence.ogg',
"press" = 'sound/AI_vox/press.ogg',
"primary" = 'sound/AI_vox/primary.ogg',
"proceed" = 'sound/AI_vox/proceed.ogg',
"processing" = 'sound/AI_vox/processing.ogg',
"progress" = 'sound/AI_vox/progress.ogg',
"proper" = 'sound/AI_vox/proper.ogg',
"propulsion" = 'sound/AI_vox/propulsion.ogg',
"prosecute" = 'sound/AI_vox/prosecute.ogg',
"protective" = 'sound/AI_vox/protective.ogg',
"push" = 'sound/AI_vox/push.ogg',
"quantum" = 'sound/AI_vox/quantum.ogg',
"quebec" = 'sound/AI_vox/quebec.ogg',
"question" = 'sound/AI_vox/question.ogg',
"questioning" = 'sound/AI_vox/questioning.ogg',
"quick" = 'sound/AI_vox/quick.ogg',
"quit" = 'sound/AI_vox/quit.ogg',
"radiation" = 'sound/AI_vox/radiation.ogg',
"radioactive" = 'sound/AI_vox/radioactive.ogg',
"rads" = 'sound/AI_vox/rads.ogg',
"rapid" = 'sound/AI_vox/rapid.ogg',
"reach" = 'sound/AI_vox/reach.ogg',
"reached" = 'sound/AI_vox/reached.ogg',
"reactor" = 'sound/AI_vox/reactor.ogg',
"red" = 'sound/AI_vox/red.ogg',
"relay" = 'sound/AI_vox/relay.ogg',
"released" = 'sound/AI_vox/released.ogg',
"remaining" = 'sound/AI_vox/remaining.ogg',
"renegade" = 'sound/AI_vox/renegade.ogg',
"repair" = 'sound/AI_vox/repair.ogg',
"report" = 'sound/AI_vox/report.ogg',
"reports" = 'sound/AI_vox/reports.ogg',
"required" = 'sound/AI_vox/required.ogg',
"research" = 'sound/AI_vox/research.ogg',
"reset" = 'sound/AI_vox/reset.wav',
"resevoir" = 'sound/AI_vox/resevoir.ogg',
"resistance" = 'sound/AI_vox/resistance.ogg',
"returned" = 'sound/AI_vox/returned.wav',
"right" = 'sound/AI_vox/right.ogg',
"rocket" = 'sound/AI_vox/rocket.ogg',
"roger" = 'sound/AI_vox/roger.ogg',
"romeo" = 'sound/AI_vox/romeo.ogg',
"room" = 'sound/AI_vox/room.ogg',
"round" = 'sound/AI_vox/round.ogg',
"run" = 'sound/AI_vox/run.ogg',
"safe" = 'sound/AI_vox/safe.ogg',
"safety" = 'sound/AI_vox/safety.ogg',
"sargeant" = 'sound/AI_vox/sargeant.ogg',
"satellite" = 'sound/AI_vox/satellite.ogg',
"save" = 'sound/AI_vox/save.ogg',
"science" = 'sound/AI_vox/science.ogg',
"scores" = 'sound/AI_vox/scores.wav',
"scream" = 'sound/AI_vox/scream.ogg',
"screen" = 'sound/AI_vox/screen.ogg',
"search" = 'sound/AI_vox/search.ogg',
"second" = 'sound/AI_vox/second.ogg',
"secondary" = 'sound/AI_vox/secondary.ogg',
"seconds" = 'sound/AI_vox/seconds.ogg',
"sector" = 'sound/AI_vox/sector.ogg',
"secure" = 'sound/AI_vox/secure.ogg',
"secured" = 'sound/AI_vox/secured.ogg',
"security" = 'sound/AI_vox/security.ogg',
"select" = 'sound/AI_vox/select.ogg',
"selected" = 'sound/AI_vox/selected.ogg',
"service" = 'sound/AI_vox/service.ogg',
"seven" = 'sound/AI_vox/seven.ogg',
"seventeen" = 'sound/AI_vox/seventeen.ogg',
"seventy" = 'sound/AI_vox/seventy.ogg',
"severe" = 'sound/AI_vox/severe.ogg',
"sewage" = 'sound/AI_vox/sewage.ogg',
"sewer" = 'sound/AI_vox/sewer.ogg',
"shield" = 'sound/AI_vox/shield.ogg',
"shipment" = 'sound/AI_vox/shipment.ogg',
"shock" = 'sound/AI_vox/shock.ogg',
"shoot" = 'sound/AI_vox/shoot.ogg',
"shower" = 'sound/AI_vox/shower.ogg',
"shut" = 'sound/AI_vox/shut.ogg',
"side" = 'sound/AI_vox/side.ogg',
"sierra" = 'sound/AI_vox/sierra.ogg',
"sight" = 'sound/AI_vox/sight.ogg',
"silo" = 'sound/AI_vox/silo.ogg',
"six" = 'sound/AI_vox/six.ogg',
"sixteen" = 'sound/AI_vox/sixteen.ogg',
"sixty" = 'sound/AI_vox/sixty.ogg',
"slime" = 'sound/AI_vox/slime.ogg',
"slow" = 'sound/AI_vox/slow.ogg',
"soldier" = 'sound/AI_vox/soldier.ogg',
"some" = 'sound/AI_vox/some.ogg',
"someone" = 'sound/AI_vox/someone.ogg',
"something" = 'sound/AI_vox/something.ogg',
"son" = 'sound/AI_vox/son.ogg',
"sorry" = 'sound/AI_vox/sorry.ogg',
"south" = 'sound/AI_vox/south.ogg',
"squad" = 'sound/AI_vox/squad.ogg',
"square" = 'sound/AI_vox/square.ogg',
"stairway" = 'sound/AI_vox/stairway.ogg',
"status" = 'sound/AI_vox/status.ogg',
"sterile" = 'sound/AI_vox/sterile.ogg',
"sterilization" = 'sound/AI_vox/sterilization.ogg',
"stolen" = 'sound/AI_vox/stolen.wav',
"storage" = 'sound/AI_vox/storage.ogg',
"sub" = 'sound/AI_vox/sub.ogg',
"subsurface" = 'sound/AI_vox/subsurface.ogg',
"sudden" = 'sound/AI_vox/sudden.ogg',
"suit" = 'sound/AI_vox/suit.ogg',
"superconducting" = 'sound/AI_vox/superconducting.ogg',
"supercooled" = 'sound/AI_vox/supercooled.ogg',
"supply" = 'sound/AI_vox/supply.ogg',
"surface" = 'sound/AI_vox/surface.ogg',
"surrender" = 'sound/AI_vox/surrender.ogg',
"surround" = 'sound/AI_vox/surround.ogg',
"surrounded" = 'sound/AI_vox/surrounded.ogg',
"switch" = 'sound/AI_vox/switch.ogg',
"system" = 'sound/AI_vox/system.ogg',
"systems" = 'sound/AI_vox/systems.ogg',
"tactical" = 'sound/AI_vox/tactical.ogg',
"take" = 'sound/AI_vox/take.ogg',
"talk" = 'sound/AI_vox/talk.ogg',
"tango" = 'sound/AI_vox/tango.ogg',
"tank" = 'sound/AI_vox/tank.ogg',
"target" = 'sound/AI_vox/target.ogg',
"team" = 'sound/AI_vox/team.ogg',
"temperature" = 'sound/AI_vox/temperature.ogg',
"temporal" = 'sound/AI_vox/temporal.ogg',
"ten" = 'sound/AI_vox/ten.ogg',
"terminal" = 'sound/AI_vox/terminal.ogg',
"terminated" = 'sound/AI_vox/terminated.ogg',
"termination" = 'sound/AI_vox/termination.ogg',
"test" = 'sound/AI_vox/test.ogg',
"that" = 'sound/AI_vox/that.ogg',
"the" = 'sound/AI_vox/the.ogg',
"then" = 'sound/AI_vox/then.ogg',
"there" = 'sound/AI_vox/there.ogg',
"third" = 'sound/AI_vox/third.ogg',
"thirteen" = 'sound/AI_vox/thirteen.ogg',
"thirty" = 'sound/AI_vox/thirty.ogg',
"this" = 'sound/AI_vox/this.ogg',
"those" = 'sound/AI_vox/those.ogg',
"thousand" = 'sound/AI_vox/thousand.ogg',
"threat" = 'sound/AI_vox/threat.ogg',
"three" = 'sound/AI_vox/three.ogg',
"through" = 'sound/AI_vox/through.ogg',
"time" = 'sound/AI_vox/time.ogg',
"to" = 'sound/AI_vox/to.ogg',
"top" = 'sound/AI_vox/top.ogg',
"topside" = 'sound/AI_vox/topside.ogg',
"touch" = 'sound/AI_vox/touch.ogg',
"towards" = 'sound/AI_vox/towards.ogg',
"track" = 'sound/AI_vox/track.ogg',
"train" = 'sound/AI_vox/train.ogg',
"transportation" = 'sound/AI_vox/transportation.ogg',
"truck" = 'sound/AI_vox/truck.ogg',
"tunnel" = 'sound/AI_vox/tunnel.ogg',
"turn" = 'sound/AI_vox/turn.ogg',
"turret" = 'sound/AI_vox/turret.ogg',
"twelve" = 'sound/AI_vox/twelve.ogg',
"twenty" = 'sound/AI_vox/twenty.ogg',
"two" = 'sound/AI_vox/two.ogg',
"unauthorized" = 'sound/AI_vox/unauthorized.ogg',
"under" = 'sound/AI_vox/under.ogg',
"uniform" = 'sound/AI_vox/uniform.ogg',
"unlocked" = 'sound/AI_vox/unlocked.ogg',
"until" = 'sound/AI_vox/until.ogg',
"up" = 'sound/AI_vox/up.ogg',
"upper" = 'sound/AI_vox/upper.ogg',
"uranium" = 'sound/AI_vox/uranium.ogg',
"us" = 'sound/AI_vox/us.ogg',
"usa" = 'sound/AI_vox/usa.ogg',
"use" = 'sound/AI_vox/use.ogg',
"used" = 'sound/AI_vox/used.ogg',
"user" = 'sound/AI_vox/user.ogg',
"vacate" = 'sound/AI_vox/vacate.ogg',
"valid" = 'sound/AI_vox/valid.ogg',
"vapor" = 'sound/AI_vox/vapor.ogg',
"vent" = 'sound/AI_vox/vent.ogg',
"ventillation" = 'sound/AI_vox/ventillation.ogg',
"victor" = 'sound/AI_vox/victor.ogg',
"violated" = 'sound/AI_vox/violated.ogg',
"violation" = 'sound/AI_vox/violation.ogg',
"voltage" = 'sound/AI_vox/voltage.ogg',
"vox_login" = 'sound/AI_vox/vox_login.ogg',
"walk" = 'sound/AI_vox/walk.ogg',
"wall" = 'sound/AI_vox/wall.ogg',
"want" = 'sound/AI_vox/want.ogg',
"wanted" = 'sound/AI_vox/wanted.ogg',
"warm" = 'sound/AI_vox/warm.ogg',
"warn" = 'sound/AI_vox/warn.ogg',
"warning" = 'sound/AI_vox/warning.ogg',
"waste" = 'sound/AI_vox/waste.ogg',
"water" = 'sound/AI_vox/water.ogg',
"we" = 'sound/AI_vox/we.ogg',
"weapon" = 'sound/AI_vox/weapon.ogg',
"west" = 'sound/AI_vox/west.ogg',
"whiskey" = 'sound/AI_vox/whiskey.ogg',
"white" = 'sound/AI_vox/white.ogg',
"wilco" = 'sound/AI_vox/wilco.ogg',
"will" = 'sound/AI_vox/will.ogg',
"with" = 'sound/AI_vox/with.ogg',
"without" = 'sound/AI_vox/without.ogg',
"woop" = 'sound/AI_vox/woop.ogg',
"xeno" = 'sound/AI_vox/xeno.ogg',
"yankee" = 'sound/AI_vox/yankee.ogg',
"yards" = 'sound/AI_vox/yards.ogg',
"year" = 'sound/AI_vox/year.ogg',
"yellow" = 'sound/AI_vox/yellow.ogg',
"yes" = 'sound/AI_vox/yes.ogg',
"you" = 'sound/AI_vox/you.ogg',
"your" = 'sound/AI_vox/your.ogg',
"yourself" = 'sound/AI_vox/yourself.ogg',
"zero" = 'sound/AI_vox/zero.ogg',
"zone" = 'sound/AI_vox/zone.ogg',
"zulu" = 'sound/AI_vox/zulu.ogg',
)
#endif


code:
/mob/living/silicon/spawn_gibs()
	robogibs(loc, viruses)

/mob/living/silicon/gib(var/animation = 0) // Please don't remove this thinking this proc does nothing, it is changing the default value for animation.
	..()

/mob/living/silicon/spawn_dust()
	new /obj/effect/decal/remains/robot(loc)


code:
/mob/living/silicon/proc/show_laws() //Redefined in ai/laws.dm and robot/laws.dm
	return

/mob/living/silicon/proc/laws_sanity_check()
	if (!laws)
		make_laws()

/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
	src.laws_sanity_check()
	src.laws.set_zeroth_law(law, law_borg)

/mob/living/silicon/proc/add_inherent_law(var/law)
	laws_sanity_check()
	laws.add_inherent_law(law)

/mob/living/silicon/proc/clear_inherent_laws()
	laws_sanity_check()
	laws.clear_inherent_laws()

/mob/living/silicon/proc/add_supplied_law(var/number, var/law)
	laws_sanity_check()
	laws.add_supplied_law(number, law)

/mob/living/silicon/proc/clear_supplied_laws()
	laws_sanity_check()
	laws.clear_supplied_laws()

/mob/living/silicon/proc/add_ion_law(var/law)
	laws_sanity_check()
	laws.add_ion_law(law)

/mob/living/silicon/proc/clear_ion_laws()
	laws_sanity_check()
	laws.clear_ion_laws()

/mob/living/silicon/proc/make_laws()
	switch(config.default_laws)
		if(0)	laws = new /datum/ai_laws/default/asimov()
		if(1)	laws = new /datum/ai_laws/custom()
		if(2)
			var/datum/ai_laws/lawtype = pick(typesof(/datum/ai_laws/default) - /datum/ai_laws/default)
			laws = new lawtype()


code:
/mob/living/silicon/Login()
	if(mind && ticker && ticker.mode)
		ticker.mode.remove_cultist(mind, 0)
		ticker.mode.remove_revolutionary(mind, 0)
		ticker.mode.remove_gangster(mind, 0)
	..()


code:
/mob/living/silicon/robot/mommi/gib(var/animation = 1)
	if(generated)
		src.dust()
	if(src.module && istype(src.module))
		var/obj/item/found = locate(tool_state) in src.module.modules
		if(!found && tool_state != src.module.emag)
			var/obj/item/TS = tool_state
			drop_item()
			if(TS && TS.loc)
				TS.loc = src.loc

	..()

/mob/living/silicon/robot/mommi/dust(var/animation = 1)
	if(src.module && istype(src.module)) //Drop what it's holding if it isn't a module
		var/obj/item/found = locate(tool_state) in src.module.modules
		if(!found && tool_state != src.module.emag)
			var/obj/item/TS = tool_state
			drop_item()
			if(TS && TS.loc)
				TS.loc = src.loc
	if(mmi)
		qdel(mmi)
	..()

/mob/living/silicon/robot/mommi/death(gibbed)
	if(stat == DEAD)	return
	if(!gibbed)
		emote("deathgasp")
	stat = DEAD
	update_canmove()
	if(camera)
		camera.status = 0
/*
	if(in_contents_of(/obj/machinery/recharge_station))//exit the recharge station
		var/obj/machinery/recharge_station/RC = loc
		if(RC.upgrading)
			RC.upgrading = 0
			RC.upgrade_finished = -1
		RC.go_out()
*/
	if(blind)	blind.layer = 0
	sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS
	see_in_dark = 8
	see_invisible = SEE_INVISIBLE_LEVEL_TWO
	updateicon()

	tod = worldtime2text() //weasellos time of death patch
	if(mind)	mind.store_memory("Time of death: [tod]", 0)

	sql_report_cyborg_death(src)
	return ..(gibbed)


code:
#define HEARABLE 2
#define VISIBLE 1

/mob/living/silicon/robot/mommi/emote(var/act,var/m_type=1,var/message = null)
	var/param = null
	if (findtext(act, "-", 1, null))
		var/t1 = findtext(act, "-", 1, null)
		param = copytext(act, t1 + 1, length(act) + 1)
		act = copytext(act, 1, t1)

	if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
		act = copytext(act,1,length(act))
//whyyyyy isn't this sorted alphabetically
//now fixed
	switch(act)
		if ("aflap")
			if (!src.restrained())
				message = "[src] flaps his utility arms ANGRILY!"
				m_type = 2

		if("beep")
			var/M = null
			if(param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if(!M)
				param = null

			if (param)
				message = "[src] beeps at [param]."
			else
				message = "[src] beeps."
			playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
			m_type = 2

		if ("bow")
			if (!src.buckled)
				var/M = null
				if (param)
					for (var/mob/A in view(1, src))
						if (param == A.name)
							M = A
							break
				if (!M)
					param = null
				if (param)
					message = "[src] bows to [param]."
				else
					message = "[src] bows."
			m_type = 1

		if ("buzz")
			var/M = null
			if(param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if(!M)
				param = null

			if (param)
				message = "[src] buzzes at [param]."
			else
				message = "[src] buzzes."
			playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
			m_type = 2

		if ("buzz2")
			message = "[src] buzzes twice."
			playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
			m_type = 2

		if ("chime") //You have mail!
			message = "[src] chimes."
			playsound(loc, 'sound/machines/chime.ogg', 50, 0)
			m_type = 2

		if ("chitter") //The authentic drone experience
			message = "[src] chitters."
			m_type = 2

		if ("clap")
			if (!src.restrained())
				message = "[src] clangs \his utility claws together in a crude simulation of applause."
				m_type = 2

		if ("custom")
			var/input = copytext(sanitize(input("Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN)
			if (!input)
				return
			var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
			if (input2 == "Visible")
				m_type = 1
			else if (input2 == "Hearable")
				m_type = 2
			else
				alert("Unable to use this emote, must be either hearable or visible.")
				return
			message = "[src] [input]"

		if ("deathgasp")
			message = "[src] shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
			m_type = 1

		if ("flap")
			if (!src.restrained())
				message = "[src] flaps \his utility arms as through they were wings."
				m_type = 2

		if ("glare")
			var/M = null
			if (param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if (!M)
				param = null
			if (param)
				message = "[src] glares at [param]."
			else
				message = "[src] glares."

		if ("honk") //Honk!
			message = "[src] honks!"
			playsound(loc, 'sound/items/bikehorn.ogg', 50, 1)
			m_type = 2

		if ("look")
			var/M = null
			if (param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if (!M)
				param = null
			if (param)
				message = "[src] looks at [param]."
			else
				message = "[src] looks."

		if ("me")
			if (src.client)
				if(client.prefs.muted & MUTE_IC)
					src << "You cannot send IC messages (muted)."
					return
				if (src.client.handle_spam_prevention(message,MUTE_IC))
					return
			if (stat)
				return
			if(!(message))
				return
			else
				message = "[src] [message]"

		if ("nod")
			message = "[src] bobs \his body in a rough approximation of nodding."
			m_type = 1

		if ("ping")
			var/M = null
			if(param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if(!M)
				param = null
			if (param)
				message = "[src] pings at [param]."
			else
				message = "[src] pings."
			playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
			m_type = 2

		if ("sad") //When words cannot express...
			message = "[src] plays a sad trombone."
			playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 0)
			m_type = 2

		if ("salute")
			if (!src.buckled)
				var/M = null
				if (param)
					for (var/mob/A in view(1, src))
						if (param == A.name)
							M = A
							break
				if (!M)
					param = null

				if (param)
					message = "[src] salutes to [param]."
				else
					message = "[src] salutes."

		if ("stare")
			var/M = null
			if (param)
				for (var/mob/A in view(1, src))
					if (param == A.name)
						M = A
						break
			if (!M)
				param = null
			if (param)
				message = "[src] stares at [param]."
			else
				message = "[src] stares."
			m_type = 1

		if ("twitch")
			message = "[src] twitches violently."
			m_type = 1

		if ("twitch_s")
			message = "[src] twitches."
			m_type = 1

		if ("warn") //HUMAN HARM DETECTED. PLEASE DIE IN AN ORDERLY FASHION.
			message = "[src] blares an alarm!"
			playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
			m_type = 2

		if ("help")
			src << "Help for cyborg emotes. You can use these emotes with say \"*emote\":\n\naflap, beep-(none)/mob, bow-(none)/mob, buzz-(none)/mob,buzz2,chime, chitter, clap, custom, deathgasp, flap, glare-(none)/mob, honk, look-(none)/mob, me, nod, ping-(none)/mob, sad, \nsalute-(none)/mob, twitch, twitch_s, warn,"

		else
			src << "Unusable emote '[act]'. Say *help for a list."
/*
		if("comment")
			var/M = null
			if(param)
				for (var/mob/A in view(null, null))
					if (param == A.name)
						M = A
						break
			if(!M)
				param = null

			if (param)
				message = "[src] cheerily vocalizes at [param]."
			else
				message = "[src] vocalizes."
			playsound(src, get_sfx("mommicomment"),50, 0)
			m_type = VISIBLE
*/
		else
			src << text("Invalid Emote: [], use *help", act)
	if ((message && src.stat == 0))
		if (m_type & 1)
			for(var/mob/O in viewers(src, null))
				O.show_message(message, m_type)
		else
			for(var/mob/O in hearers(src, null))
				O.show_message(message, m_type)
	return


code:
/mob/living/silicon/robot/mommi/examine()
	set src in oview()

	if(!usr || !src)	return
//	if( (usr.sdisabilities & BLIND || usr.blinded || usr.stat) && !istype(usr,/mob/dead/observer) )
//		usr << "Something is there but you can't see it."
//		return

	var/msg = "*---------*\nThis is \icon[src] \a [src]!\n"

	// AUTOFIXED BY fix_string_idiocy.py
	// C:\Users\Rob\Documents\Projects\vgstation13\code\modules\mob\living\silicon\mommi\examine.dm:10: msg += "
It's like a crab, but it has a utility tool on one arm and a crude metal claw on the other.  That, and you doubt it'd survive in an ocean for very long.
"
	msg += {"
It's like a crab, but it has a utility tool on one arm and a crude metal claw on the other.  That, and you doubt it'd survive in an ocean for very long.
"}
	// END AUTOFIX
	if (src.getBruteLoss())
		if (src.getBruteLoss() < 20)
			msg += "It looks slightly dented.\n"
		else
			msg += "It looks severely dented!\n"
	if (src.getFireLoss())
		if (src.getFireLoss() < 20)
			msg += "It looks slightly charred.\n"
		else
			msg += "It looks severely burnt and heat-warped!\n"
	msg += ""

	if(tool_state)
		var/obj/item/I = tool_state
		msg += "Its utitility claw is gripping \icon[I] [I.gender==PLURAL?"some":"a"] [I.name].\n"

	if(opened)
		msg += "Its cover is open and the power cell is [cell ? "installed" : "missing"].\n"
	else
		msg += "Its cover is closed.\n"

	switch(src.stat)
		if(CONSCIOUS)
			if(!src.client)	msg += "It appears to be in stand-by mode.\n" //afk
		if(UNCONSCIOUS)		msg += "It doesn't seem to be responding.\n"
		if(DEAD)			msg += "It looks completely unsalvageable.\n"
	msg += "*---------*"

	usr << msg
	return