code:
/proc/keywords_lookup(msg)

	//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
	var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")

	//explode the input msg into a list
	var/list/msglist = splittext(msg, " ")

	//generate keywords lookup
	var/list/surnames = list()
	var/list/forenames = list()
	var/list/ckeys = list()
	for(var/mob/M in mob_list)
		var/list/indexing = list(M.real_name, M.name)
		if(M.mind)
			indexing += M.mind.name

		for(var/string in indexing)
			var/list/L = splittext(string, " ")
			var/surname_found = 0
			//surnames
			for(var/i=L.len, i>=1, i--)
				var/word = ckey(L[i])
				if(word)
					surnames[word] = M
					surname_found = i
					break
			//forenames
			for(var/i=1, i<surname_found, i++)
				var/word = ckey(L[i])
				if(word)
					forenames[word] = M
			//ckeys
			ckeys[M.ckey] = M

	var/ai_found = 0
	msg = ""
	var/list/mobs_found = list()
	for(var/original_word in msglist)
		var/word = ckey(original_word)
		if(word)
			if(!(word in adminhelp_ignored_words))
				if(word == "ai")
					ai_found = 1
				else
					var/mob/found = ckeys[word]
					if(!found)
						found = surnames[word]
						if(!found)
							found = forenames[word]
					if(found)
						if(!(found in mobs_found))
							mobs_found += found
							if(!ai_found && isAI(found))
								ai_found = 1
							var/is_antag = 0
							if(found.mind && found.mind.special_role)
								is_antag = 1
							msg += "[original_word](?|F) "
							continue
		msg += "[original_word] "
	return msg

/client/var/adminhelptimerid = 0

/client/proc/giveadminhelpverb()
	src.verbs |= /client/verb/adminhelp
	adminhelptimerid = 0

/client/verb/adminhelp(msg as text)
	set category = "Admin"
	set name = "Adminhelp"

	if(say_disabled)	//This is here to try to identify lag problems
		usr << "Speech is currently admin-disabled."
		return

	//handle muting and automuting
	if(prefs.muted & MUTE_ADMINHELP)
		src << "Error: Admin-PM: You cannot send adminhelps (Muted)."
		return
	if(src.handle_spam_prevention(msg,MUTE_ADMINHELP))
		return

	//clean the input msg
	if(!msg)
		return
	msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
	if(!msg)	return
	var/original_msg = msg

	//remove our adminhelp verb temporarily to prevent spamming of admins.
	src.verbs -= /client/verb/adminhelp
	adminhelptimerid = addtimer(src, "giveadminhelpverb", 1200, FALSE) //2 minute cooldown of admin helps

	msg = keywords_lookup(msg)

	if(!mob)
		return						//this doesn't happen

	var/ref_mob = "\ref[mob]"
	var/ref_client = "\ref[src]"
	msg = "HELP: [key_name(src)] (?) (PP) (VV) (SM) (FLW) (TP) (REJT): [msg]"

	//send this msg to all admins

	for(var/client/X in admins)
		if(X.prefs.toggles & SOUND_ADMINHELP)
			X << 'sound/effects/adminhelp.ogg'
		X << msg

	//show it to the person adminhelping too
	src << "PM to-Admins: [original_msg]"

	//send it to irc if nobody is on and tell us how many were on
	var/admin_number_present = send2irc_adminless_only(ckey,original_msg)
	log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.")
	feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	return

/proc/get_admin_counts(requiredflags = R_BAN)
	. = list("total" = 0, "noflags" = 0, "afk" = 0, "stealth" = 0, "present" = 0)
	for(var/client/X in admins)
		.["total"]++
		if(requiredflags != 0 && !check_rights_for(X, requiredflags))
			.["noflags"]++
		else if(X.is_afk())
			.["afk"]++
		else if(X.holder.fakekey)
			.["stealth"]++
		else
			.["present"]++

/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
	var/list/adm = get_admin_counts(requiredflags)
	. = adm["present"]
	if(. <= 0)
		if(!adm["afk"] && !adm["stealth"] && !adm["noflags"])
			send2irc(source, "[msg] - No admins online")
		else
			send2irc(source, "[msg] - All admins AFK ([adm["afk"]]/[adm["total"]]), stealthminned ([adm["stealth"]]/[adm["total"]]), or lack[rights2text(requiredflags, " ")] ([adm["noflags"]]/[adm["total"]])")

/proc/send2irc(msg,msg2)
	if(config.useircbot)
		shell("python nudge.py [msg] [msg2]")
	return


code:
/client/proc/jumptoarea(area/A in sortedAreas)
	set name = "Jump to Area"
	set desc = "Area to jump to"
	set category = "Admin"
	if(!src.holder)
		src << "Only administrators may use this command."
		return

	if(!A)
		return

	var/list/turfs = list()
	for(var/area/Ar in A.related)
		for(var/turf/T in Ar)
			if(T.density)
				continue
			turfs.Add(T)

	var/turf/T = safepick(turfs)
	if(!T)
		src << "Nowhere to jump to!"
		return
	usr.forceMove(T)
	log_admin("[key_name(usr)] jumped to [A]")
	message_admins("[key_name_admin(usr)] jumped to [A]")
	feedback_add_details("admin_verb","JA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/jumptoturf(turf/T in world)
	set name = "Jump to Turf"
	set category = "Admin"
	if(!src.holder)
		src << "Only administrators may use this command."
		return

	log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]")
	message_admins("[key_name_admin(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]")
	usr.loc = T
	feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	return

/client/proc/jumptomob(mob/M in mob_list)
	set category = "Admin"
	set name = "Jump to Mob"

	if(!src.holder)
		src << "Only administrators may use this command."
		return

	log_admin("[key_name(usr)] jumped to [key_name(M)]")
	message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]")
	if(src.mob)
		var/mob/A = src.mob
		var/turf/T = get_turf(M)
		if(T && isturf(T))
			feedback_add_details("admin_verb","JM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
			A.forceMove(M.loc)
		else
			A << "This mob is not located in the game world."

/client/proc/jumptocoord(tx as num, ty as num, tz as num)
	set category = "Admin"
	set name = "Jump to Coordinate"

	if (!holder)
		src << "Only administrators may use this command."
		return

	if(src.mob)
		var/mob/A = src.mob
		A.x = tx
		A.y = ty
		A.z = tz
		feedback_add_details("admin_verb","JC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	message_admins("[key_name_admin(usr)] jumped to coordinates [tx], [ty], [tz]")

/client/proc/jumptokey()
	set category = "Admin"
	set name = "Jump to Key"

	if(!src.holder)
		src << "Only administrators may use this command."
		return

	var/list/keys = list()
	for(var/mob/M in player_list)
		keys += M.client
	var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys)
	if(!selection)
		src << "No keys found."
		return
	var/mob/M = selection:mob
	log_admin("[key_name(usr)] jumped to [key_name(M)]")
	message_admins("[key_name_admin(usr)] jumped to [key_name_admin(M)]")

	usr.forceMove(M.loc)

	feedback_add_details("admin_verb","JK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/Getmob(mob/M in mob_list)
	set category = "Admin"
	set name = "Get Mob"
	set desc = "Mob to teleport"
	if(!src.holder)
		src << "Only administrators may use this command."
		return

	log_admin("[key_name(usr)] teleported [key_name(M)]")
	message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)]")
	M.forceMove(get_turf(usr))
	feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/Getkey()
	set category = "Admin"
	set name = "Get Key"
	set desc = "Key to teleport"

	if(!src.holder)
		src << "Only administrators may use this command."
		return

	var/list/keys = list()
	for(var/mob/M in player_list)
		keys += M.client
	var/selection = input("Please, select a player!", "Admin Jumping", null, null) as null|anything in sortKey(keys)
	if(!selection)
		return
	var/mob/M = selection:mob

	if(!M)
		return
	log_admin("[key_name(usr)] teleported [key_name(M)]")
	message_admins("[key_name_admin(usr)] teleported [key_name(M)]")
	if(M)
		M.forceMove(get_turf(usr))
		usr.loc = M.loc
		feedback_add_details("admin_verb","GK") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/sendmob(mob/M in sortmobs())
	set category = "Admin"
	set name = "Send Mob"
	if(!src.holder)
		src << "Only administrators may use this command."
		return
	var/area/A = input(usr, "Pick an area.", "Pick an area") in sortedAreas|null
	if(A && istype(A))
		if(M.forceMove(safepick(get_area_turfs(A))))

			log_admin("[key_name(usr)] teleported [key_name(M)] to [A]")
			message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)] to [A]")
		else
			src << "Failed to move mob to a valid location."
		feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

license: mit


code:
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M in mob_list)
	set category = null
	set name = "Admin PM Mob"
	if(!holder)
		src << "Error: Admin-PM-Context: Only administrators may use this command."
		return
	if( !ismob(M) || !M.client )
		return
	cmd_admin_pm(M.client,null)
	feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm
/client/proc/cmd_admin_pm_panel()
	set category = "Admin"
	set name = "Admin PM"
	if(!holder)
		src << "Error: Admin-PM-Panel: Only administrators may use this command."
		return
	var/list/client/targets[0]
	for(var/client/T)
		if(T.mob)
			if(istype(T.mob, /mob/new_player))
				targets["(New Player) - [T]"] = T
			else if(istype(T.mob, /mob/dead/observer))
				targets["[T.mob.name](Ghost) - [T]"] = T
			else
				targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
		else
			targets["(No Mob) - [T]"] = T
	var/list/sorted = sortList(targets)
	var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null
	cmd_admin_pm(targets[target],null)
	feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_ahelp_reply(whom)
	if(prefs.muted & MUTE_ADMINHELP)
		src << "Error: Admin-PM: You are unable to use admin PM-s (muted)."
		return
	var/client/C
	if(istext(whom))
		if(cmptext(copytext(whom,1,2),"@"))
			whom = findStealthKey(whom)
		C = directory[whom]
	else if(istype(whom,/client))
		C = whom
	if(!C)
		if(holder)
			src << "Error: Admin-PM: Client not found."
		return
	message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.")
	var/msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as text|null
	if (!msg)
		message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.")
		return
	cmd_admin_pm(whom, msg)

//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM.
//Fetching a message if needed. src is the sender and C is the target client
/client/proc/cmd_admin_pm(whom, msg)
	if(prefs.muted & MUTE_ADMINHELP)
		src << "Error: Admin-PM: You are unable to use admin PM-s (muted)."
		return

	var/client/C
	if(istext(whom))
		if(cmptext(copytext(whom,1,2),"@"))
			whom = findStealthKey(whom)
		C = directory[whom]
	else if(istype(whom,/client))
		C = whom
	if(!C)
		if(holder)
			src << "Error: Admin-PM: Client not found."
		else
			adminhelp(msg)	//admin we are replying to left. adminhelp instead
		return

	//get message text, limit it's length.and clean/escape html
	if(!msg)
		msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as text|null

		if(!msg)
			return
		if(!C)
			if(holder)
				src << "Error: Admin-PM: Client not found."
			else
				adminhelp(msg)	//admin we are replying to has vanished, adminhelp instead
			return

	if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
		return

	//clean the message if it's not sent by a high-rank admin
	if(!check_rights(R_SERVER|R_DEBUG,0))
		msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
		if(!msg)
			return

	var/rawmsg = msg
	if(holder)
		msg = emoji_parse(msg)

	var/keywordparsedmsg = keywords_lookup(msg)

	if(C.holder)
		if(holder)	//both are admins
			C << "Admin PM from-[key_name(src, C, 1)]: [keywordparsedmsg]"
			src << "Admin PM to-[key_name(C, src, 1)]: [keywordparsedmsg]"

		else		//recipient is an admin but sender is not
			C << "Reply PM from-[key_name(src, C, 1)]: [keywordparsedmsg]"
			src << "PM to-Admins: [msg]"

		//play the recieving admin the adminhelp sound (if they have them enabled)
		if(C.prefs.toggles & SOUND_ADMINHELP)
			C << 'sound/effects/adminhelp.ogg'

	else
		if(holder)	//sender is an admin but recipient is not. Do BIG RED TEXT
			C << "-- Administrator private message --"
			C << "Admin PM from-[key_name(src, C, 0)]: [msg]"
			C << "Click on the administrator's name to reply."
			src << "Admin PM to-[key_name(C, src, 1)]: [msg]"

			//always play non-admin recipients the adminhelp sound
			C << 'sound/effects/adminhelp.ogg'

			//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
			if(config.popup_admin_pm)
				spawn()	//so we don't hold the caller proc up
					var/sender = src
					var/sendername = key
					var/reply = input(C, msg,"Admin PM from-[sendername]", "") as text|null		//show message and await a reply
					if(C && reply)
						if(sender)
							C.cmd_admin_pm(sender,reply)										//sender is still about, let's reply to them
						else
							adminhelp(reply)													//sender has left, adminhelp instead
					return

		else		//neither are admins
			src << "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden."
			return

	log_admin("PM: [key_name(src)]->[key_name(C)]: [rawmsg]")

	//we don't use message_admins here because the sender/receiver might get it too
	for(var/client/X in admins)
		if(X.key!=key && X.key!=C.key)	//check client/X is an admin and isn't the sender or recipient
			X << "PM: [key_name(src, X, 0)]->[key_name(C, X, 0)]: \blue [keywordparsedmsg]" //inform X


code:
/client/proc/cmd_admin_say(msg as text)
	set category = "Special Verbs"
	set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite
	set hidden = 1
	if(!check_rights(0))
		return

	msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
	if(!msg)
		return

	log_adminsay("[key_name(src)] : [msg]")
	msg = keywords_lookup(msg)
	if(check_rights(R_ADMIN,0))
		msg = "ADMIN: [key_name(usr, 1)] (FLW): [msg]"
		admins << msg
	else
		msg = "ADMIN: [key_name(usr, 1)]: [msg]"
		admins << msg

	feedback_add_details("admin_verb","M") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!


code:
/client/proc/atmosscan()
	set category = "Mapping"
	set name = "Check Plumbing"
	if(!src.holder)
		src << "Only administrators may use this command."
		return
	feedback_add_details("admin_verb","CP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

	//all plumbing - yes, some things might get stated twice, doesn't matter.
	for (var/obj/machinery/atmospherics/plumbing in machines)
		if (plumbing.nodealert)
			usr << "Unconnected [plumbing.name] located at [plumbing.x],[plumbing.y],[plumbing.z] ([get_area(plumbing.loc)])"

	//Manifolds
	for (var/obj/machinery/atmospherics/pipe/manifold/pipe in machines)
		if (!pipe.NODE1 || !pipe.NODE2 || !pipe.NODE3)
			usr << "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])"

	//Pipes
	for (var/obj/machinery/atmospherics/pipe/simple/pipe in machines)
		if (!pipe.NODE1 || !pipe.NODE2)
			usr << "Unconnected [pipe.name] located at [pipe.x],[pipe.y],[pipe.z] ([get_area(pipe.loc)])"

/client/proc/powerdebug()
	set category = "Mapping"
	set name = "Check Power"
	if(!src.holder)
		src << "Only administrators may use this command."
		return
	feedback_add_details("admin_verb","CPOW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

	for (var/datum/powernet/PN in powernets)
		if (!PN.nodes || !PN.nodes.len)
			if(PN.cables && (PN.cables.len > 1))
				var/obj/structure/cable/C = PN.cables[1]
				usr << "Powernet with no nodes! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]"

		if (!PN.cables || (PN.cables.len < 10))
			if(PN.cables && (PN.cables.len > 1))
				var/obj/structure/cable/C = PN.cables[1]
				usr << "Powernet with fewer than 10 cables! (number [PN.number]) - example cable at [C.x], [C.y], [C.z] in area [get_area(C.loc)]"


code:
/client/proc/bluespace_artillery(mob/M in mob_list)
	set name = "Bluespace Artillery"
	set category = "Fun"

	if(!holder || !check_rights(R_FUN))
		return

	var/mob/living/target = M

	if(!isliving(target))
		usr << "This can only be used on instances of type /mob/living"
		return

	if(alert(usr, "Are you sure you wish to hit [key_name(target)] with Blue Space Artillery?",  "Confirm Firing?" , "Yes" , "No") != "Yes")
		return

	explosion(target.loc, 0, 0, 0, 0)

	var/turf/open/floor/T = get_turf(target)
	if(istype(T))
		if(prob(80))
			T.break_tile_to_plating()
		else
			T.break_tile()

	target << "You're hit by bluespace artillery!"
	log_admin("[target.name] has been hit by Bluespace Artillery fired by [usr]")
	message_admins("[target.name] has been hit by Bluespace Artillery fired by [usr]")

	if(target.health <= 1)
		target.gib()
	else
		target.adjustBruteLoss(min(99,(target.health - 1)))
		target.Stun(20)
		target.Weaken(20)
		target.stuttering = 20


code:
#define BASIC_BUILDMODE 1
#define ADV_BUILDMODE 2
#define VAR_BUILDMODE 3
#define THROW_BUILDMODE 4
#define AREA_BUILDMODE 5
#define COPY_BUILDMODE 6
#define NUM_BUILDMODES 6

//Buildmode Shuttle
//Builmode Move

/obj/screen/buildmode
	icon = 'icons/misc/buildmode.dmi'
	var/datum/buildmode/bd

/obj/screen/buildmode/New(bd)
	..()
	src.bd = bd

/obj/screen/buildmode/mode
	icon_state = "buildmode1"
	name = "Toggle Mode"
	screen_loc = "NORTH,WEST"

/obj/screen/buildmode/mode/Click(location, control, params)
	var/list/pa = params2list(params)

	if(pa.Find("left"))
		bd.toggle_modes()
	else if(pa.Find("right"))
		bd.change_settings(usr)
	update_icon()
	return 1

/obj/screen/buildmode/mode/update_icon()
	icon_state = "buildmode[bd.mode]"
	return

/obj/screen/buildmode/help
	icon_state = "buildhelp"
	screen_loc = "NORTH,WEST+1"
	name = "Buildmode Help"

/obj/screen/buildmode/help/Click()
	bd.show_help(usr)
	return 1

/obj/screen/buildmode/bdir
	icon_state = "build"
	screen_loc = "NORTH,WEST+2"
	name = "Change Dir"

/obj/screen/buildmode/bdir/update_icon()
	dir = bd.build_dir
	return

/obj/screen/buildmode/quit
	icon_state = "buildquit"
	screen_loc = "NORTH,WEST+3"
	name = "Quit Buildmode"

/obj/screen/buildmode/quit/Click()
	bd.quit()
	return 1

/obj/screen/buildmode/bdir/Click()
	bd.change_dir()
	update_icon()
	return 1

/datum/buildmode
	var/mode = BASIC_BUILDMODE
	var/client/holder = null
	var/list/obj/screen/buttons = list()
	var/build_dir = SOUTH
	var/atom/movable/throw_atom = null
	var/turf/cornerA = null
	var/turf/cornerB = null
	var/generator_path = null
	var/varholder = "name"
	var/valueholder = "derp"
	var/objholder = /obj/structure/closet
	var/atom/movable/stored = null

/datum/buildmode/New(client/c)
	create_buttons()
	holder = c
	holder.click_intercept = src
	holder.show_popup_menus = 0
	holder.screen += buttons

/datum/buildmode/proc/quit()
	holder.screen -= buttons
	holder.click_intercept = null
	holder.show_popup_menus = 1
	qdel(src)
	return

/datum/buildmode/Destroy()
	stored = null
	for(var/button in buttons)
		qdel(button)

/datum/buildmode/proc/create_buttons()
	buttons += new /obj/screen/buildmode/mode(src)
	buttons += new /obj/screen/buildmode/help(src)
	buttons += new /obj/screen/buildmode/bdir(src)
	buttons += new /obj/screen/buildmode/quit(src)

/datum/buildmode/proc/toggle_modes()
	mode = (mode % NUM_BUILDMODES) +1
	Reset()
	return

/datum/buildmode/proc/show_help(mob/user)
	switch(mode)
		if(BASIC_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Left Mouse Button        = Construct / Upgrade"
			user << "\blue Right Mouse Button       = Deconstruct / Delete / Downgrade"
			user << "\blue Left Mouse Button + ctrl = R-Window"
			user << "\blue Left Mouse Button + alt  = Airlock"
			user << ""
			user << "\blue Use the button in the upper left corner to"
			user << "\blue change the direction of built objects."
			user << "\blue ***********************************************************"
		if(ADV_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Right Mouse Button on buildmode button = Set object type"
			user << "\blue Left Mouse Button on turf/obj          = Place objects"
			user << "\blue Right Mouse Button                     = Delete objects"
			user << ""
			user << "\blue Use the button in the upper left corner to"
			user << "\blue change the direction of built objects."
			user << "\blue ***********************************************************"
		if(VAR_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Right Mouse Button on buildmode button = Select var(type) & value"
			user << "\blue Left Mouse Button on turf/obj/mob      = Set var(type) & value"
			user << "\blue Right Mouse Button on turf/obj/mob     = Reset var's value"
			user << "\blue ***********************************************************"
		if(THROW_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Left Mouse Button on turf/obj/mob      = Select"
			user << "\blue Right Mouse Button on turf/obj/mob     = Throw"
			user << "\blue ***********************************************************"
		if(AREA_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Left Mouse Button on turf/obj/mob      = Select corner"
			user << "\blue Right Mouse Button on buildmode button = Select generator"
			user << "\blue ***********************************************************"
		if(COPY_BUILDMODE)
			user << "\blue ***********************************************************"
			user << "\blue Left Mouse Button on obj/turf/mob   = Spawn a Copy of selected target"
			user << "\blue Right Mouse Button on obj/mob = Select target to copy"
			user << "\blue ***********************************************************"

/datum/buildmode/proc/change_settings(mob/user)
	switch(mode)
		if(BASIC_BUILDMODE)
			return 1
		if(ADV_BUILDMODE)
			var/target_path = input(user,"Enter typepath:" ,"Typepath","/obj/structure/closet")
			objholder = text2path(target_path)
			if(!ispath(objholder))
				objholder = pick_closest_path(target_path)
				if(!objholder)
					objholder = /obj/structure/closet
					alert("That path is not allowed.")
			else
				if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0))
					objholder = /obj/structure/closet
		if(VAR_BUILDMODE)
			var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")

			varholder = input(user,"Enter variable name:" ,"Name", "name")
			if(varholder in locked && !check_rights(R_DEBUG,0))
				return 1
			var/thetype = input(user,"Select variable type:" ,"Type") in list("text","number","mob-reference","obj-reference","turf-reference")
			if(!thetype) return 1
			switch(thetype)
				if("text")
					valueholder = input(user,"Enter variable value:" ,"Value", "value") as text
				if("number")
					valueholder = input(user,"Enter variable value:" ,"Value", 123) as num
				if("mob-reference")
					valueholder = input(user,"Enter variable value:" ,"Value") as mob in mob_list
				if("obj-reference")
					valueholder = input(user,"Enter variable value:" ,"Value") as obj in world
				if("turf-reference")
					valueholder = input(user,"Enter variable value:" ,"Value") as turf in world
		if(AREA_BUILDMODE)
			var/list/gen_paths = subtypesof(/datum/mapGenerator)

			var/type = input(user,"Select Generator Type","Type") as null|anything in gen_paths
			if(!type) return

			generator_path = type
			cornerA = null
			cornerB = null

/datum/buildmode/proc/change_dir()
	switch(build_dir)
		if(NORTH)
			build_dir = EAST
		if(EAST)
			build_dir = SOUTH
		if(SOUTH)
			build_dir = WEST
		if(WEST)
			build_dir = NORTHWEST
		if(NORTHWEST)
			build_dir = NORTH
	return 1

/datum/buildmode/proc/Reset()//Reset temporary variables
	cornerA = null
	cornerB = null

/proc/togglebuildmode(mob/M in player_list)
	set name = "Toggle Build Mode"
	set category = "Special Verbs"
	if(M.client)
		if(istype(M.client.click_intercept,/datum/buildmode))
			var/datum/buildmode/B = M.client.click_intercept
			B.quit()
			log_admin("[key_name(usr)] has left build mode.")
		else
			new/datum/buildmode(M.client)
			message_admins("[key_name(usr)] has entered build mode.")
			log_admin("[key_name(usr)] has entered build mode.")

/datum/buildmode/proc/InterceptClickOn(user,params,atom/object) //Click Intercept
	var/list/pa = params2list(params)
	var/right_click = pa.Find("right")
	var/left_click = pa.Find("left")
	var/alt_click = pa.Find("alt")
	var/ctrl_click = pa.Find("ctrl")

	. = 1
	switch(mode)
		if(BASIC_BUILDMODE)
			if(istype(object,/turf) && left_click && !alt_click && !ctrl_click)
				var/turf/T = object
				if(istype(object,/turf/open/space))
					T.ChangeTurf(/turf/open/floor/plasteel)
				else if(istype(object,/turf/open/floor))
					T.ChangeTurf(/turf/closed/wall)
				else if(istype(object,/turf/closed/wall))
					T.ChangeTurf(/turf/closed/wall/r_wall)
				log_admin("Build Mode: [key_name(user)] built [T] at ([T.x],[T.y],[T.z])")
				return
			else if(right_click)
				log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])")
				if(istype(object,/turf/closed/wall))
					var/turf/T = object
					T.ChangeTurf(/turf/open/floor/plasteel)
				else if(istype(object,/turf/open/floor))
					var/turf/T = object
					T.ChangeTurf(/turf/open/space)
				else if(istype(object,/turf/closed/wall/r_wall))
					var/turf/T = object
					T.ChangeTurf(/turf/closed/wall)
				else if(istype(object,/obj))
					qdel(object)
				return
			else if(istype(object,/turf) && alt_click && left_click)
				log_admin("Build Mode: [key_name(user)] built an airlock at ([object.x],[object.y],[object.z])")
				new/obj/machinery/door/airlock(get_turf(object))
			else if(istype(object,/turf) && ctrl_click && left_click)
				switch(build_dir)
					if(NORTH)
						var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
						WIN.dir = NORTH
					if(SOUTH)
						var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
						WIN.dir = SOUTH
					if(EAST)
						var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
						WIN.dir = EAST
					if(WEST)
						var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
						WIN.dir = WEST
					if(NORTHWEST)
						var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
						WIN.dir = NORTHWEST
				log_admin("Build Mode: [key_name(user)] built a window at ([object.x],[object.y],[object.z])")
		if(ADV_BUILDMODE)
			if(left_click)
				if(ispath(objholder,/turf))
					var/turf/T = get_turf(object)
					log_admin("Build Mode: [key_name(user)] modified [T] ([T.x],[T.y],[T.z]) to [objholder]")
					T.ChangeTurf(objholder)
				else
					var/obj/A = new objholder (get_turf(object))
					A.dir = build_dir
					log_admin("Build Mode: [key_name(user)] modified [A]'s ([A.x],[A.y],[A.z]) dir to [build_dir]")
			else if(right_click)
				if(isobj(object))
					log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])")
					qdel(object)

		if(VAR_BUILDMODE)
			if(left_click) //I cant believe this shit actually compiles.
				if(object.vars.Find(varholder))
					log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]")
					object.vars[varholder] = valueholder
				else
					user << "[initial(object.name)] does not have a var called '[varholder]'"
			if(right_click)
				if(object.vars.Find(varholder))
					log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]")
					object.vars[varholder] = initial(object.vars[varholder])
				else
					user << "[initial(object.name)] does not have a var called '[varholder]'"

		if(THROW_BUILDMODE)
			if(left_click)
				if(isturf(object))
					return
				throw_atom = object
			if(right_click)
				if(throw_atom)
					throw_atom.throw_at(object, 10, 1,user)
					log_admin("Build Mode: [key_name(user)] threw [throw_atom] at [object] ([object.x],[object.y],[object.z])")
		if(AREA_BUILDMODE)
			if(!cornerA)
				cornerA = get_turf(object)
				return
			if(cornerA && !cornerB)
				cornerB = get_turf(object)

			if(left_click) //rectangular
				if(cornerA && cornerB)
					if(!generator_path)
						user << "Select generator type first."
					var/datum/mapGenerator/G = new generator_path
					G.defineRegion(cornerA,cornerB,1)
					G.generate()
					cornerA = null
					cornerB = null
					return
			//Something wrong - Reset
			cornerA = null
			cornerB = null
		if(COPY_BUILDMODE)
			if(left_click)
				var/turf/T = get_turf(object)
				if(stored)
					DuplicateObject(stored,perfectcopy=1,newloc=T)
			else if(right_click)
				if(ismovableatom(object)) // No copying turfs for now.
					stored = object


code:
/client/proc/cinematic(cinematic as anything in list("explosion",null))
	set name = "cinematic"
	set category = "Fun"
	set desc = "Shows a cinematic."	// Intended for testing but I thought it might be nice for events on the rare occasion Feel free to comment it out if it's not wanted.
	set hidden = 1
	if(!ticker)
		return
	switch(cinematic)
		if("explosion")
			var/parameter = input(src,"station_missed = ?","Enter Parameter",0) as num
			var/override
			switch(parameter)
				if(1)
					override = input(src,"mode = ?","Enter Parameter",null) as anything in list("nuclear emergency","gang war","fake","no override")
				if(0)
					override = input(src,"mode = ?","Enter Parameter",null) as anything in list("blob","nuclear emergency","AI malfunction","no override")
			ticker.station_explosion_cinematic(parameter,override)
	return


code:
/client/proc/dsay(msg as text)
	set category = "Special Verbs"
	set name = "Dsay" //Gave this shit a shorter name so you only have to time out "dsay" rather than "dead say" to use it --NeoFite
	set hidden = 1
	if(!src.holder)
		src << "Only administrators may use this command."
		return
	if(!src.mob)
		return
	if(prefs.muted & MUTE_DEADCHAT)
		src << "You cannot send DSAY messages (muted)."
		return

	if (src.handle_spam_prevention(msg,MUTE_DEADCHAT))
		return

	msg = copytext(sanitize(msg), 1, MAX_MESSAGE_LEN)
	log_dsay("[key_name(src)] : [msg]")

	if (!msg)
		return
	var/nicknames = file2list("config/admin_nicknames.txt")

	var/rendered = "DEAD: ADMIN([src.holder.fakekey ? pick(nicknames) : src.key]) says, \"[msg]\""

	for (var/mob/M in player_list)
		if (istype(M, /mob/new_player))
			continue
		if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
			M.show_message(rendered, 2)

	feedback_add_details("admin_verb","D") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!


code:
/client/proc/Debug2()
	set category = "Debug"
	set name = "Debug-Game"
	if(!check_rights(R_DEBUG))
		return

	if(Debug2)
		Debug2 = 0
		message_admins("[key_name(src)] toggled debugging off.")
		log_admin("[key_name(src)] toggled debugging off.")
	else
		Debug2 = 1
		message_admins("[key_name(src)] toggled debugging on.")
		log_admin("[key_name(src)] toggled debugging on.")

	feedback_add_details("admin_verb","DG2") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/* 21st Sept 2010
Updated by Skie -- Still not perfect but better!
Stuff you can't do:
Call proc /mob/proc/Dizzy() for some player
Because if you select a player mob as owner it tries to do the proc for
/mob/living/carbon/human/ instead. And that gives a run-time error.
But you can call procs that are of type /mob/living/carbon/human/proc/ for that player.
*/

/client/proc/callproc()
	set category = "Debug"
	set name = "Advanced ProcCall"
	set waitfor = 0

	if(!check_rights(R_DEBUG)) return

	var/target = null
	var/targetselected = 0
	var/returnval = null
	var/class = null

	switch(alert("Proc owned by something?",,"Yes","No"))
		if("Yes")
			targetselected = 1
			if(src.holder && src.holder.marked_datum)
				class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client","Marked datum ([holder.marked_datum.type])")
				if(class == "Marked datum ([holder.marked_datum.type])")
					class = "Marked datum"
			else
				class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client")
			switch(class)
				if("Obj")
					target = input("Enter target:","Target",usr) as obj in world
				if("Mob")
					target = input("Enter target:","Target",usr) as mob in world
				if("Area or Turf")
					target = input("Enter target:","Target",usr.loc) as area|turf in world
				if("Client")
					var/list/keys = list()
					for(var/client/C)
						keys += C
					target = input("Please, select a player!", "Selection", null, null) as null|anything in keys
				if("Marked datum")
					target = holder.marked_datum
				else
					return
		if("No")
			target = null
			targetselected = 0

	var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
	if(!procname)
		return
	if(targetselected && !hascall(target,procname))
		usr << "Error: callproc(): target has no such call [procname]."
		return
	else
		var/procpath = text2path(procname)
		if (!procpath)
			usr << "Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)"
			return
	var/list/lst = get_callproc_args()
	if(!lst)
		return

	if(targetselected)
		if(!target)
			usr << "Error: callproc(): owner of proc no longer exists."
			return
		log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
		message_admins("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
		returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
	else
		//this currently has no hascall protection. wasn't able to get it working.
		log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
		message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
		returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc
	. = get_callproc_returnval(returnval, procname)
	if(.)
		usr << .
	feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/callproc_datum(A as null|area|mob|obj|turf)
	set category = "Debug"
	set name = "Atom ProcCall"
	set waitfor = 0

	if(!check_rights(R_DEBUG))
		return

	var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
	if(!procname)
		return
	if(!hascall(A,procname))
		usr << "Error: callproc_datum(): target has no such call [procname]."
		return
	var/list/lst = get_callproc_args()
	if(!lst)
		return

	if(!A || !IsValidSrc(A))
		usr << "Error: callproc_datum(): owner of proc no longer exists."
		return
	log_admin("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
	message_admins("[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
	feedback_add_details("admin_verb","DPC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

	var/returnval = call(A,procname)(arglist(lst)) // Pass the lst as an argument list to the proc
	. = get_callproc_returnval(returnval,procname)
	if(.)
		usr << .

/client/proc/get_callproc_args()
	var/argnum = input("Number of arguments","Number:",0) as num|null
	if(!argnum && (argnum!=0))
		return

	var/list/lst = list()
	//TODO: make a list to store whether each argument was initialised as null.
	//Reason: So we can abort the proccall if say, one of our arguments was a mob which no longer exists
	//this will protect us from a fair few errors ~Carn

	while(argnum--)
		var/class = null
		// Make a list with each index containing one variable, to be given to the proc
		if(src.holder && src.holder.marked_datum)
			class = input("What kind of variable?","Variable Type") in list("text","num","type","reference","mob reference","icon","file","client","mob's area","Marked datum ([holder.marked_datum.type])","CANCEL")
			if(holder.marked_datum && class == "Marked datum ([holder.marked_datum.type])")
				class = "Marked datum"
		else
			class = input("What kind of variable?","Variable Type") in list("text","num","type","reference","mob reference","icon","file","client","mob's area","CANCEL")
		switch(class)
			if("CANCEL")
				return null

			if("text")
				lst += input("Enter new text:","Text",null) as text

			if("num")
				lst += input("Enter new number:","Num",0) as num

			if("type")
				lst += input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf)

			if("reference")
				lst += input("Select reference:","Reference",src) as mob|obj|turf|area in world

			if("mob reference")
				lst += input("Select reference:","Reference",usr) as mob in world

			if("file")
				lst += input("Pick file:","File") as file

			if("icon")
				lst += input("Pick icon:","Icon") as icon

			if("client")
				var/list/keys = list()
				for(var/mob/M in world)
					keys += M.client
				lst += input("Please, select a player!", "Selection", null, null) as null|anything in keys

			if("mob's area")
				var/mob/temp = input("Select mob", "Selection", usr) as mob in world
				lst += temp.loc
			if("Marked datum")
				lst += holder.marked_datum
	return lst

/client/proc/get_callproc_returnval(returnval,procname)
	. = ""
	if(islist(returnval))
		var/list/returnedlist = returnval
		. = ""
		if(returnedlist.len)
			var/assoc_check = returnedlist[1]
			if(istext(assoc_check) && (returnedlist[assoc_check] != null))
				. += "[procname] returned an associative list:"
				for(var/key in returnedlist)
					. += "\n[key] = [returnedlist[key]]"

			else
				. += "[procname] returned a list:"
				for(var/elem in returnedlist)
					. += "\n[elem]"
		else
			. = "[procname] returned an empty list"
		. += ""

	else
		. = "[procname] returned: [returnval ? returnval : "null"]"

/client/proc/Cell()
	set category = "Debug"
	set name = "Air Status in Location"
	if(!mob)
		return
	var/turf/T = mob.loc

	if (!( istype(T, /turf) ))
		return

	var/datum/gas_mixture/env = T.return_air()
	var/list/env_gases = env.gases

	var/t = ""
	for(var/id in env_gases)
		if(id in hardcoded_gases || env_gases[id][MOLES])
			t+= "[env_gases[id][GAS_META][META_GAS_NAME]] : [env_gases[id][MOLES]]\n"

	usr << t
	feedback_add_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_admin_robotize(mob/M in mob_list)
	set category = "Fun"
	set name = "Make Robot"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return
	if(istype(M, /mob/living/carbon/human))
		log_admin("[key_name(src)] has robotized [M.key].")
		var/mob/living/carbon/human/H = M
		spawn(0)
			H.Robotize()

	else
		alert("Invalid mob")

/client/proc/cmd_admin_blobize(mob/M in mob_list)
	set category = "Fun"
	set name = "Make Blob"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return
	if(istype(M, /mob/living/carbon/human))
		log_admin("[key_name(src)] has blobized [M.key].")
		var/mob/living/carbon/human/H = M
		spawn(0)
			var/mob/camera/blob/B = H.become_overmind()
			B.place_blob_core(B.base_point_rate, -1) //place them wherever they are

	else
		alert("Invalid mob")

/client/proc/cmd_admin_animalize(mob/M in mob_list)
	set category = "Fun"
	set name = "Make Simple Animal"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return

	if(!M)
		alert("That mob doesn't seem to exist, close the panel and try again.")
		return

	if(istype(M, /mob/new_player))
		alert("The mob must not be a new_player.")
		return

	log_admin("[key_name(src)] has animalized [M.key].")
	spawn(0)
		M.Animalize()

/client/proc/makepAI(turf/T in mob_list)
	set category = "Fun"
	set name = "Make pAI"
	set desc = "Specify a location to spawn a pAI device, then specify a key to play that pAI"

	var/list/available = list()
	for(var/mob/C in mob_list)
		if(C.key)
			available.Add(C)
	var/mob/choice = input("Choose a player to play the pAI", "Spawn pAI") in available
	if(!choice)
		return 0
	if(!istype(choice, /mob/dead/observer))
		var/confirm = input("[choice.key] isn't ghosting right now. Are you sure you want to yank him out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", "No") in list("Yes", "No")
		if(confirm != "Yes")
			return 0
	var/obj/item/device/paicard/card = new(T)
	var/mob/living/silicon/pai/pai = new(card)
	pai.name = input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text
	pai.real_name = pai.name
	pai.key = choice.key
	card.setPersonality(pai)
	for(var/datum/paiCandidate/candidate in SSpai.candidates)
		if(candidate.key == choice.key)
			SSpai.candidates.Remove(candidate)
	feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_admin_alienize(mob/M in mob_list)
	set category = "Fun"
	set name = "Make Alien"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return
	if(ishuman(M))
		log_admin("[key_name(src)] has alienized [M.key].")
		spawn(0)
			M:Alienize()
			feedback_add_details("admin_verb","MKAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
		log_admin("[key_name(usr)] made [key_name(M)] into an alien.")
		message_admins("[key_name_admin(usr)] made [key_name(M)] into an alien.")
	else
		alert("Invalid mob")

/client/proc/cmd_admin_slimeize(mob/M in mob_list)
	set category = "Fun"
	set name = "Make slime"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return
	if(ishuman(M))
		log_admin("[key_name(src)] has slimeized [M.key].")
		spawn(0)
			M:slimeize()
			feedback_add_details("admin_verb","MKMET") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
		log_admin("[key_name(usr)] made [key_name(M)] into a slime.")
		message_admins("[key_name_admin(usr)] made [key_name(M)] into a slime.")
	else
		alert("Invalid mob")

var/list/TYPES_SHORTCUTS = list(
	/obj/effect/decal/cleanable = "CLEANABLE",
	/obj/item/device/radio/headset = "HEADSET",
	/obj/item/clothing/head/helmet/space = "SPESSHELMET",
	/obj/item/weapon/book/manual = "MANUAL",
	/obj/item/weapon/reagent_containers/food/drinks = "DRINK", //longest paths comes first
	/obj/item/weapon/reagent_containers/food = "FOOD",
	/obj/item/weapon/reagent_containers = "REAGENT_CONTAINERS",
	/obj/machinery/atmospherics = "ATMOS",
	/obj/machinery/portable_atmospherics = "PORT_ATMOS",
	/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/missile_rack = "MECHA_MISSILE_RACK",
	/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
	/obj/item/organ/internal = "ORGAN_INT",
)

var/global/list/g_fancy_list_of_types = null
/proc/get_fancy_list_of_types()
	if (isnull(g_fancy_list_of_types)) //init
		var/list/temp = sortList(subtypesof(/atom) - typesof(/area) - /atom/movable)
		g_fancy_list_of_types = new(temp.len)
		for(var/type in temp)
			var/typename = "[type]"
			for (var/tn in TYPES_SHORTCUTS)
				if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
					typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/"))
					break
			g_fancy_list_of_types[typename] = type
	return g_fancy_list_of_types

/proc/filter_fancy_list(list/L, filter as text)
	var/list/matches = new
	for(var/key in L)
		var/value = L[key]
		if(findtext("[key]", filter) || findtext("[value]", filter))
			matches[key] = value
	return matches

//TODO: merge the vievars version into this or something maybe mayhaps
/client/proc/cmd_debug_del_all(object as text)
	set category = "Debug"
	set name = "Del-All"

	var/list/matches = get_fancy_list_of_types()
	if (!isnull(object) && object!="")
		matches = filter_fancy_list(matches, object)

	if(matches.len==0)
		return
	var/hsbitem = input(usr, "Choose an object to delete.", "Delete:") as null|anything in matches
	if(hsbitem)
		hsbitem = matches[hsbitem]
		var/counter = 0
		for(var/atom/O in world)
			if(istype(O, hsbitem))
				counter++
				qdel(O)
			CHECK_TICK
		log_admin("[key_name(src)] has deleted all ([counter]) instances of [hsbitem].")
		message_admins("[key_name_admin(src)] has deleted all ([counter]) instances of [hsbitem].", 0)
		feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_debug_make_powernets()
	set category = "Debug"
	set name = "Make Powernets"
	SSmachine.makepowernets()
	log_admin("[key_name(src)] has remade the powernet. makepowernets() called.")
	message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.", 0)
	feedback_add_details("admin_verb","MPWN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_admin_grantfullaccess(mob/M in mob_list)
	set category = "Admin"
	set name = "Grant Full Access"

	if(!ticker || !ticker.mode)
		alert("Wait until the game starts")
		return
	if (istype(M, /mob/living/carbon/human))
		var/mob/living/carbon/human/H = M
		var/obj/item/worn = H.wear_id
		var/obj/item/weapon/card/id/id = null
		if(worn)
			id = worn.GetID()
		if(id)
			id.icon_state = "gold"
			id.access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
		else
			id = new /obj/item/weapon/card/id/gold(H.loc)
			id.access = get_all_accesses()+get_all_centcom_access()+get_all_syndicate_access()
			id.registered_name = H.real_name
			id.assignment = "Captain"
			id.update_label()

			if(worn)
				if(istype(worn,/obj/item/device/pda))
					worn:id = id
					id.loc = worn
				else if(istype(worn,/obj/item/weapon/storage/wallet))
					worn:front_id = id
					id.loc = worn
					worn.update_icon()
			else
				H.equip_to_slot(id,slot_wear_id)

	else
		alert("Invalid mob")
	feedback_add_details("admin_verb","GFA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	log_admin("[key_name(src)] has granted [M.key] full access.")
	message_admins("[key_name_admin(usr)] has granted [M.key] full access.")

/client/proc/cmd_assume_direct_control(mob/M in mob_list)
	set category = "Admin"
	set name = "Assume direct control"
	set desc = "Direct intervention"

	if(M.ckey)
		if(alert("This mob is being controlled by [M.ckey]. Are you sure you wish to assume control of it? [M.ckey] will be made a ghost.",,"Yes","No") != "Yes")
			return
		else
			var/mob/dead/observer/ghost = new/mob/dead/observer(M,1)
			ghost.ckey = M.ckey
	message_admins("[key_name_admin(usr)] assumed direct control of [M].")
	log_admin("[key_name(usr)] assumed direct control of [M].")
	var/mob/adminmob = src.mob
	M.ckey = src.ckey
	if( isobserver(adminmob) )
		qdel(adminmob)
	feedback_add_details("admin_verb","ADC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_admin_areatest()
	set category = "Mapping"
	set name = "Test areas"

	var/list/areas_all = list()
	var/list/areas_with_APC = list()
	var/list/areas_with_air_alarm = list()
	var/list/areas_with_RC = list()
	var/list/areas_with_light = list()
	var/list/areas_with_LS = list()
	var/list/areas_with_intercom = list()
	var/list/areas_with_camera = list()

	for(var/area/A in world)
		if(!(A.type in areas_all))
			areas_all.Add(A.type)

	for(var/obj/machinery/power/apc/APC in apcs_list)
		var/area/A = get_area(APC)
		if(!(A.type in areas_with_APC))
			areas_with_APC.Add(A.type)

	for(var/obj/machinery/airalarm/AA in machines)
		var/area/A = get_area(AA)
		if(!(A.type in areas_with_air_alarm))
			areas_with_air_alarm.Add(A.type)

	for(var/obj/machinery/requests_console/RC in machines)
		var/area/A = get_area(RC)
		if(!(A.type in areas_with_RC))
			areas_with_RC.Add(A.type)

	for(var/obj/machinery/light/L in machines)
		var/area/A = get_area(L)
		if(!(A.type in areas_with_light))
			areas_with_light.Add(A.type)

	for(var/obj/machinery/light_switch/LS in machines)
		var/area/A = get_area(LS)
		if(!(A.type in areas_with_LS))
			areas_with_LS.Add(A.type)

	for(var/obj/item/device/radio/intercom/I in machines)
		var/area/A = get_area(I)
		if(!(A.type in areas_with_intercom))
			areas_with_intercom.Add(A.type)

	for(var/obj/machinery/camera/C in machines)
		var/area/A = get_area(C)
		if(!(A.type in areas_with_camera))
			areas_with_camera.Add(A.type)

	var/list/areas_without_APC = areas_all - areas_with_APC
	var/list/areas_without_air_alarm = areas_all - areas_with_air_alarm
	var/list/areas_without_RC = areas_all - areas_with_RC
	var/list/areas_without_light = areas_all - areas_with_light
	var/list/areas_without_LS = areas_all - areas_with_LS
	var/list/areas_without_intercom = areas_all - areas_with_intercom
	var/list/areas_without_camera = areas_all - areas_with_camera

	world << "AREAS WITHOUT AN APC:"
	for(var/areatype in areas_without_APC)
		world << "* [areatype]"

	world << "AREAS WITHOUT AN AIR ALARM:"
	for(var/areatype in areas_without_air_alarm)
		world << "* [areatype]"

	world << "AREAS WITHOUT A REQUEST CONSOLE:"
	for(var/areatype in areas_without_RC)
		world << "* [areatype]"

	world << "AREAS WITHOUT ANY LIGHTS:"
	for(var/areatype in areas_without_light)
		world << "* [areatype]"

	world << "AREAS WITHOUT A LIGHT SWITCH:"
	for(var/areatype in areas_without_LS)
		world << "* [areatype]"

	world << "AREAS WITHOUT ANY INTERCOMS:"
	for(var/areatype in areas_without_intercom)
		world << "* [areatype]"

	world << "AREAS WITHOUT ANY CAMERAS:"
	for(var/areatype in areas_without_camera)
		world << "* [areatype]"

/client/proc/cmd_admin_dress(mob/living/carbon/human/M in mob_list)
	set category = "Fun"
	set name = "Select equipment"
	if(!ishuman(M))
		alert("Invalid mob")
		return
	//log_admin("[key_name(src)] has alienized [M.key].")

	var/list/outfits = list("Naked","Custom","As Job...")
	var/list/paths = subtypesof(/datum/outfit) - typesof(/datum/outfit/job)
	for(var/path in paths)
		var/datum/outfit/O = path //not much to initalize here but whatever
		outfits[initial(O.name)] = path

	var/dresscode = input("Select dress for [M]", "Robust quick dress shop") as null|anything in outfits
	if (isnull(dresscode))
		return

	var/datum/job/jobdatum
	if (dresscode == "As Job...")
		var/jobname = input("Select job", "Robust quick dress shop") as null|anything in get_all_jobs()
		if(isnull(jobname))
			return
		jobdatum = SSjob.GetJob(jobname)

	var/datum/outfit/custom = null
	if (dresscode == "Custom")
		var/list/custom_names = list()
		for(var/datum/outfit/D in custom_outfits)
			custom_names[D.name] = D
		var/selected_name = input("Select outfit", "Robust quick dress shop") as null|anything in custom_names
		custom = custom_names[selected_name]
		if(isnull(custom))
			return

	feedback_add_details("admin_verb","SEQ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	for (var/obj/item/I in M)
		if (istype(I, /obj/item/weapon/implant))
			continue
		qdel(I)
	switch(dresscode)
		if ("Naked")
			//do nothing
		if ("Custom")
			//use custom one
			M.equipOutfit(custom)
		if ("As Job...")
			if(jobdatum)
				dresscode = jobdatum.title
				M.job = jobdatum.title
				jobdatum.equip(M)

		else
			M.equipOutfit(outfits[dresscode])

	M.regenerate_icons()

	log_admin("[key_name(usr)] changed the equipment of [key_name(M)] to [dresscode].")
	message_admins("[key_name_admin(usr)] changed the equipment of [key_name_admin(M)] to [dresscode]..")
	return

/client/proc/startSinglo()

	set category = "Debug"
	set name = "Start Singularity"
	set desc = "Sets up the singularity and all machines to get power flowing through the station"

	if(alert("Are you sure? This will start up the engine. Should only be used during debug!",,"Yes","No") != "Yes")
		return

	for(var/obj/machinery/power/emitter/E in machines)
		if(E.anchored)
			E.active = 1

	for(var/obj/machinery/field/generator/F in machines)
		if(F.active == 0)
			F.active = 1
			F.state = 2
			F.power = 250
			F.anchored = 1
			F.warming_up = 3
			F.start_fields()
			F.update_icon()

	spawn(30)
		for(var/obj/machinery/the_singularitygen/G in machines)
			if(G.anchored)
				var/obj/singularity/S = new /obj/singularity(get_turf(G), 50)
//				qdel(G)
				S.energy = 1750
				S.current_size = 7
				S.icon = 'icons/effects/224x224.dmi'
				S.icon_state = "singularity_s7"
				S.pixel_x = -96
				S.pixel_y = -96
				S.grav_pull = 0
				//S.consume_range = 3
				S.dissipate = 0
				//S.dissipate_delay = 10
				//S.dissipate_track = 0
				//S.dissipate_strength = 10

	for(var/obj/machinery/power/rad_collector/Rad in machines)
		if(Rad.anchored)
			if(!Rad.P)
				var/obj/item/weapon/tank/internals/plasma/Plasma = new/obj/item/weapon/tank/internals/plasma(Rad)
				Plasma.air_contents.assert_gas("plasma")
				Plasma.air_contents.gases["plasma"][MOLES] = 70
				Rad.drainratio = 0
				Rad.P = Plasma
				Plasma.loc = Rad

			if(!Rad.active)
				Rad.toggle_power()

	for(var/obj/machinery/power/smes/SMES in machines)
		if(SMES.anchored)
			SMES.input_attempt = 1

/client/proc/cmd_debug_mob_lists()
	set category = "Debug"
	set name = "Debug Mob Lists"
	set desc = "For when you just gotta know"

	switch(input("Which list?") in list("Players","Admins","Mobs","Living Mobs","Dead Mobs","Clients","Joined Clients"))
		if("Players")
			usr << jointext(player_list,",")
		if("Admins")
			usr << jointext(admins,",")
		if("Mobs")
			usr << jointext(mob_list,",")
		if("Living Mobs")
			usr << jointext(living_mob_list,",")
		if("Dead Mobs")
			usr << jointext(dead_mob_list,",")
		if("Clients")
			usr << jointext(clients,",")
		if("Joined Clients")
			usr << jointext(joined_player_list,",")

/client/proc/cmd_display_del_log()
	set category = "Debug"
	set name = "Display del() Log"
	set desc = "Displays a list of things that have failed to GC this round"

	var/dat = "List of things that failed to GC this round

"

	for(var/path in SSgarbage.didntgc)
		dat += "[path] - [SSgarbage.didntgc[path]] times
"

	dat += "List of paths that did not return a qdel hint in Destroy()

"
	for(var/path in SSgarbage.noqdelhint)
		dat += "[path]
"

	usr << browse(dat, "window=dellog")

/client/proc/debug_huds(i as num)
	set category = "Debug"
	set name = "Debug HUDs"
	set desc = "Debug the data or antag HUDs"

	if(!holder)
		return
	debug_variables(huds[i])


code:
/client/proc/air_status(turf/target)
	set category = "Debug"
	set name = "Display Air Status"

	if(!isturf(target))
		return

	var/datum/gas_mixture/GM = target.return_air()
	var/list/GM_gases
	var/burning = 0
	if(istype(target, /turf/open))
		var/turf/open/T = target
		if(T.active_hotspot)
			burning = 1

	usr << "@[target.x],[target.y]: [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("\red BURNING"):(null)]"
	for(var/id in GM_gases)
		if(id in hardcoded_gases || GM_gases[id][MOLES])
			usr << "[GM_gases[id][GAS_META][META_GAS_NAME]]: [GM_gases[id][MOLES]]"
	feedback_add_details("admin_verb","DAST") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/fix_next_move()
	set category = "Debug"
	set name = "Unfreeze Everyone"
	var/largest_move_time = 0
	var/largest_click_time = 0
	var/mob/largest_move_mob = null
	var/mob/largest_click_mob = null
	for(var/mob/M in world)
		if(!M.client)
			continue
		if(M.next_move >= largest_move_time)
			largest_move_mob = M
			if(M.next_move > world.time)
				largest_move_time = M.next_move - world.time
			else
				largest_move_time = 1
		if(M.next_click >= largest_click_time)
			largest_click_mob = M
			if(M.next_click > world.time)
				largest_click_time = M.next_click - world.time
			else
				largest_click_time = 0
		log_admin("DEBUG: [key_name(M)]  next_move = [M.next_move]  lastDblClick = [M.next_click]  world.time = [world.time]")
		M.next_move = 1
		M.next_click = 0
	message_admins("[key_name_admin(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [largest_move_time/10] seconds!")
	message_admins("[key_name_admin(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [largest_click_time/10] seconds!")
	message_admins("world.time = [world.time]")
	feedback_add_details("admin_verb","UFE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	return

/client/proc/radio_report()
	set category = "Debug"
	set name = "Radio report"

	var/filters = list(
		"1" = "RADIO_TO_AIRALARM",
		"2" = "RADIO_FROM_AIRALARM",
		"3" = "RADIO_CHAT",
		"4" = "RADIO_ATMOSIA",
		"5" = "RADIO_NAVBEACONS",
		"6" = "RADIO_AIRLOCK",
		"7" = "RADIO_SECBOT",
		"8" = "RADIO_MULEBOT",
		"_default" = "NO_FILTER"
		)
	var/output = "Radio Report
"
	for (var/fq in SSradio.frequencies)
		output += "Freq: [fq]
"
		var/list/datum/radio_frequency/fqs = SSradio.frequencies[fq]
		if (!fqs)
			output += "  ERROR
"
			continue
		for (var/filter in fqs.devices)
			var/list/f = fqs.devices[filter]
			if (!f)
				output += "  [filters[filter]]: ERROR
"
				continue
			output += "  [filters[filter]]: [f.len]
"
			for (var/device in f)
				if (isobj(device))
					output += "    [device] ([device:x],[device:y],[device:z] in area [get_area(device:loc)])
"
				else
					output += "    [device]
"

	usr << browse(output,"window=radioreport")
	feedback_add_details("admin_verb","RR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/reload_admins()
	set name = "Reload Admins"
	set category = "Admin"

	if(!src.holder)
		return

	var/confirm = alert(src, "Are you sure you want to reload all admins?", "Confirm", "Yes", "No")
	if(confirm !="Yes")
		return

	message_admins("[key_name_admin(usr)] manually reloaded admins")
	load_admins()
	feedback_add_details("admin_verb","RLDA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!


code:
//replaces the old Ticklag verb, fps is easier to understand
/client/proc/fps()
	set category = "Debug"
	set name = "Set fps"
	set desc = "Sets game speed in frames-per-second. Can potentially break the game"

	if(!check_rights(R_DEBUG))
		return

	var/fps = round(input("Sets game frames-per-second. Can potentially break the game","FPS", config.fps) as num|null)

	if(fps <= 0)
		src << "Error: ticklag(): Invalid world.ticklag value. No changes made."
		return
	if(fps > config.fps)
		if(alert(src, "You are setting fps to a high value:\n\t[fps] frames-per-second\n\tconfig.fps = [config.fps]","Warning!","Confirm","ABORT-ABORT-ABORT") != "Confirm")
			return

	var/msg = "[key_name(src)] has modified world.fps to [fps]"
	log_admin(msg, 0)
	message_admins(msg, 0)
	feedback_add_details("admin_verb","TICKLAG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

	world.fps = fps


code:
/*
	HOW DO I LOG RUNTIMES?
	Firstly, start dreamdeamon if it isn't already running. Then select "world>Log Session" (or press the F3 key)
	navigate the popup window to the data/logs/runtimes/ folder from where your tgstation .dmb is located.
	(you may have to make this folder yourself)

	OPTIONAL: 	you can select the little checkbox down the bottom to make dreamdeamon save the log everytime you
				start a world. Just remember to repeat these steps with a new name when you update to a new revision!

	Save it with the name of the revision your server uses (e.g. r3459.txt).
	Game Masters will now be able to grant access any runtime logs you have archived this way!
	This will allow us to gather information on bugs across multiple servers and make maintaining the TG
	codebase for the entire /TG/station commuity a TONNE easier :3 Thanks for your help!
*/

//This proc allows Game Masters to grant a client access to the .getruntimelog verb
//Permissions expire at the end of each round.
//Runtimes can be used to meta or spot game-crashing exploits so it's advised to only grant coders that
//you trust access. Also, it may be wise to ensure that they are not going to play in the current round.
/client/proc/giveruntimelog()
	set name = ".giveruntimelog"
	set desc = "Give somebody access to any session logfiles saved to the /log/runtime/ folder."
	set category = null

	if(!src.holder)
		src << "Only Admins may use this command."
		return

	var/client/target = input(src,"Choose somebody to grant access to the server's runtime logs (permissions expire at the end of each round):","Grant Permissions",null) as null|anything in clients
	if(!istype(target,/client))
		src << "Error: giveruntimelog(): Client not found."
		return

	target.verbs |= /client/proc/getruntimelog
	target << "You have been granted access to runtime logs. Please use them responsibly or risk being banned."
	return

//This proc allows download of runtime logs saved within the data/logs/ folder by dreamdeamon.
//It works similarly to show-server-log.
/client/proc/getruntimelog()
	set name = ".getruntimelog"
	set desc = "Retrieve any session logfiles saved by dreamdeamon."
	set category = null

	var/path = browse_files("data/logs/runtimes/")
	if(!path)
		return

	if(file_spam_check())
		return

	message_admins("[key_name_admin(src)] accessed file: [path]")
	src << ftp( file(path) )
	src << "Attempting to send file, this may take a fair few minutes if the file is very large."
	return

//This proc allows download of past server logs saved within the data/logs/ folder.
//It works similarly to show-server-log.
/client/proc/getserverlog()
	set name = ".getserverlog"
	set desc = "Fetch logfiles from data/logs"
	set category = null

	var/path = browse_files("data/logs/")
	if(!path)
		return

	if(file_spam_check())
		return

	message_admins("[key_name_admin(src)] accessed file: [path]")
	src << ftp( file(path) )
	src << "Attempting to send file, this may take a fair few minutes if the file is very large."
	return

//Other log stuff put here for the sake of organisation

//Shows today's server log
/datum/admins/proc/view_txt_log()
	set category = "Admin"
	set name = "Show Server Log"
	set desc = "Shows today's server log."

	if(fexists("[diary]"))
		src << ftp(diary)
	else
		src << "Server log not found, try using .getserverlog."
		return
	feedback_add_details("admin_verb","VTL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	return

//Shows today's attack log
/datum/admins/proc/view_atk_log()
	set category = "Admin"
	set name = "Show Server Attack Log"
	set desc = "Shows today's server attack log."

	if(fexists("[diaryofmeanpeople]"))
		src << ftp(diaryofmeanpeople)
	else
		src << "Server attack log not found, try using .getserverlog."
		return
	feedback_add_details("admin_verb","SSAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
	return


code:
/proc/machine_upgrade(obj/machinery/M in world)
	set name = "Tweak Component Ratings"
	set category = "Debug"
	var/new_rating = input("Enter new rating:","Num") as num
	if(new_rating && M.component_parts)
		for(var/obj/item/weapon/stock_parts/P in M.component_parts)
			P.rating = new_rating
		M.RefreshParts()

	feedback_add_details("admin_verb","MU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!


code:
/client/proc/manipulate_organs(mob/living/carbon/C in world)
	set name = "Manipulate Organs"
	set category = "Debug"
	var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add organ", "add implant", "drop organ/implant", "remove organ/implant", "cancel")

	var/list/organs = list()
	switch(operation)
		if("add organ")
			for(var/path in subtypesof(/obj/item/organ/internal))
				var/dat = replacetext("[path]", "/obj/item/organ/internal/", ":")
				organs[dat] = path

			var/obj/item/organ/internal/organ = input("Select organ type:", "Organ Manipulation", null) in organs
			organ = organs[organ]
			organ = new organ
			organ.Insert(C)

		if("add implant")
			for(var/path in subtypesof(/obj/item/weapon/implant))
				var/dat = replacetext("[path]", "/obj/item/weapon/implant/", ":")
				organs[dat] = path

			var/obj/item/weapon/implant/organ = input("Select implant type:", "Organ Manipulation", null) in organs
			organ = organs[organ]
			organ = new organ
			organ.implant(C)

		if("drop organ/implant", "remove organ/implant")
			for(var/obj/item/organ/internal/I in C.internal_organs)
				organs["[I.name] ([I.type])"] = I

			for(var/obj/item/weapon/implant/I in C)
				organs["[I.name] ([I.type])"] = I

			var/obj/item/organ = input("Select organ/implant:", "Organ Manipulation", null) in organs
			organ = organs[organ]
			if(!organ) return
			var/obj/item/organ/internal/O
			var/obj/item/weapon/implant/I

			if(isorgan(organ))
				O = organ
				O.Remove(C)
			else
				I = organ
				I.removed(C)

			organ.loc = get_turf(C)

			if(operation == "remove organ/implant")
				qdel(organ)
			else if(I) // Put the implant in case.
				var/obj/item/weapon/implantcase/case = new(get_turf(C))
				case.imp = I
				I.loc = case
				case.update_icon()


code:
/client/proc/map_template_load()
	set category = "Debug"
	set name = "Map template - Place"

	var/datum/map_template/template

	var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in map_templates
	if(!map)
		return
	template = map_templates[map]

	var/turf/T = get_turf(mob)
	if(!T)
		return

	var/list/preview = list()
	for(var/S in template.get_affected_turfs(T,centered = TRUE))
		preview += image('icons/turf/overlays.dmi',S,"greenOverlay")
	usr.client.images += preview
	if(alert(usr,"Confirm location.","Template Confirm","Yes","No") == "Yes")
		template.load(T, centered = TRUE)
		message_admins("[key_name_admin(usr)] has placed a map template ([template.name]) at (JMP)")
	usr.client.images -= preview

/client/proc/map_template_upload()
	set category = "Debug"
	set name = "Map Template - Upload"

	var/map = input(usr, "Choose a Map Template to upload to template storage","Upload Map Template") as null|file
	if(!map)
		return
	if(copytext("[map]",-4) != ".dmm")
		usr << "Bad map file: [map]"
		return

	var/datum/map_template/M = new(map=map, rename="[map]")
	M.preload_size(map)
	map_templates[M.name] = M
	message_admins("[key_name_admin(usr)] has uploaded a map template ([map])")


code:
//- Are all the floors with or without air, as they should be? (regular or airless)
//- Does the area have an APC?
//- Does the area have an Air Alarm?
//- Does the area have a Request Console?
//- Does the area have lights?
//- Does the area have a light switch?
//- Does the area have enough intercoms?
//- Does the area have enough security cameras? (Use the 'Camera Range Display' verb under Debug)
//- Is the area connected to the scrubbers air loop?
//- Is the area connected to the vent air loop? (vent pumps)
//- Is everything wired properly?
//- Does the area have a fire alarm and firedoors?
//- Do all pod doors work properly?
//- Are accesses set properly on doors, pod buttons, etc.
//- Are all items placed properly? (not below vents, scrubbers, tables)
//- Does the disposal system work properly from all the disposal units in this room and all the units, the pipes of which pass through this room?
//- Check for any misplaced or stacked piece of pipe (air and disposal)
//- Check for any misplaced or stacked piece of wire
//- Identify how hard it is to break into the area and where the weak points are
//- Check if the area has too much empty space. If so, make it smaller and replace the rest with maintenance tunnels.
var/intercom_range_display_status = 0

var/list/admin_verbs_debug_mapping = list(
	/client/proc/do_not_use_these, 			//-errorage
	/client/proc/camera_view, 				//-errorage
	/client/proc/sec_camera_report, 		//-errorage
	/client/proc/intercom_view, 			//-errorage
	/client/proc/air_status, //Air things
	/client/proc/Cell, //More air things
	/client/proc/atmosscan, //check plumbing
	/client/proc/powerdebug, //check power
	/client/proc/count_objects_on_z_level,
	/client/proc/count_objects_all,
	/client/proc/cmd_assume_direct_control,	//-errorage
	/client/proc/startSinglo,
	/client/proc/fps,	//allows you to set the ticklag.
	/client/proc/cmd_admin_grantfullaccess,
	/client/proc/cmd_admin_areatest,
	/client/proc/cmd_admin_rejuvenate,
	/datum/admins/proc/show_traitor_panel,
	/client/proc/disable_communication,
	/client/proc/print_pointers,
	/client/proc/cmd_show_at_list,
	/client/proc/cmd_show_at_list,
	/client/proc/manipulate_organs
)

/obj/effect/debugging/marker
	icon = 'icons/turf/areas.dmi'
	icon_state = "yellow"

/obj/effect/debugging/marker/Move()
	return 0

/client/proc/do_not_use_these()
	set category = "Mapping"
	set name = "-None of these are for ingame use!!"

	..()

/client/proc/camera_view()
	set category = "Mapping"
	set name = "Camera Range Display"

	var/on = 0
	for(var/turf/T in world)
		if(T.maptext)
			on = 1
		T.maptext = null

	if(!on)
		var/list/seen = list()
		for(var/obj/machinery/camera/C in cameranet.cameras)
			for(var/turf/T in C.can_see())
				seen[T]++
		for(var/turf/T in seen)
			T.maptext = "[seen[T]]"
	feedback_add_details("admin_verb","mCRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/sec_camera_report()
	set category = "Mapping"
	set name = "Camera Report"

	if(!Master)
		alert(usr,"Master_controller not found.","Sec Camera Report")
		return 0

	var/list/obj/machinery/camera/CL = list()

	for(var/obj/machinery/camera/C in cameranet.cameras)
		CL += C

	var/output = {"CAMERA ANNOMALITIES REPORT

The following annomalities have been detected. The ones in red need immediate attention: Some of those in black may be intentional.

"}

	for(var/obj/machinery/camera/C1 in CL)
		for(var/obj/machinery/camera/C2 in CL)
			if(C1 != C2)
				if(C1.c_tag == C2.c_tag)
					output += "
c_tag match for sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) and \[[C2.x], [C2.y], [C2.z]\] ([C2.loc.loc]) - c_tag is [C1.c_tag]
"
				if(C1.loc == C2.loc && C1.dir == C2.dir && C1.pixel_x == C2.pixel_x && C1.pixel_y == C2.pixel_y)
					output += "
FULLY overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
"
				if(C1.loc == C2.loc)
					output += "
overlapping sec. cameras at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Networks: [C1.network] and [C2.network]
"
		var/turf/T = get_step(C1,turn(C1.dir,180))
		if(!T || !isturf(T) || !T.density )
			if(!(locate(/obj/structure/grille,T)))
				var/window_check = 0
				for(var/obj/structure/window/W in T)
					if (W.dir == turn(C1.dir,180) || W.dir in list(5,6,9,10) )
						window_check = 1
						break
				if(!window_check)
					output += "
Camera not connected to wall at \[[C1.x], [C1.y], [C1.z]\] ([C1.loc.loc]) Network: [C1.network]</color>
"

	output += "
"
	usr << browse(output,"window=airreport;size=1000x500")
	feedback_add_details("admin_verb","mCRP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/intercom_view()
	set category = "Mapping"
	set name = "Intercom Range Display"

	if(intercom_range_display_status)
		intercom_range_display_status = 0
	else
		intercom_range_display_status = 1

	for(var/obj/effect/debugging/marker/M in world)
		qdel(M)

	if(intercom_range_display_status)
		for(var/obj/item/device/radio/intercom/I in world)
			for(var/turf/T in orange(7,I))
				var/obj/effect/debugging/marker/F = new/obj/effect/debugging/marker(T)
				if (!(F in view(7,I.loc)))
					qdel(F)
	feedback_add_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/cmd_show_at_list()
	set category = "Mapping"
	set name = "Show roundstart AT list"
	set desc = "Displays a list of active turfs coordinates at roundstart"

	var/dat = {"Coordinate list of Active Turfs at Roundstart

Real-time Active Turfs list you can see in Air Subsystem at active_turfs var
"}

	for(var/i=1; i<=active_turfs_startlist.len; i++)
		dat += active_turfs_startlist[i]
		dat += "
"

	usr << browse(dat, "window=at_list")

	feedback_add_details("admin_verb","mATL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/enable_debug_verbs()
	set category = "Debug"
	set name = "Debug verbs - Enable"
	if(!check_rights(R_DEBUG))
		return
	verbs -= /client/proc/enable_debug_verbs
	verbs.Add(/client/proc/disable_debug_verbs, admin_verbs_debug_mapping)
	feedback_add_details("admin_verb","mDVE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/disable_debug_verbs()
	set category = "Debug"
	set name = "Debug verbs - Disable"
	verbs.Remove(/client/proc/disable_debug_verbs, admin_verbs_debug_mapping)
	verbs += /client/proc/enable_debug_verbs
	feedback_add_details("admin_verb", "mDVD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/count_objects_on_z_level()
	set category = "Mapping"
	set name = "Count Objects On Level"
	var/level = input("Which z-level?","Level?") as text
	if(!level) return
	var/num_level = text2num(level)
	if(!num_level) return
	if(!isnum(num_level)) return

	var/type_text = input("Which type path?","Path?") as text
	if(!type_text) return
	var/type_path = text2path(type_text)
	if(!type_path) return

	var/count = 0

	var/list/atom/atom_list = list()

	for(var/atom/A in world)
		if(istype(A,type_path))
			var/atom/B = A
			while(!(isturf(B.loc)))
				if(B && B.loc)
					B = B.loc
				else
					break
			if(B)
				if(B.z == num_level)
					count++
					atom_list += A
	/*
	var/atom/temp_atom
	for(var/i = 0; i <= (atom_list.len/10); i++)
		var/line = ""
		for(var/j = 1; j <= 10; j++)
			if(i*10+j <= atom_list.len)
				temp_atom = atom_list[i*10+j]
				line += " no.[i+10+j]@\[[temp_atom.x], [temp_atom.y], [temp_atom.z]\]; "
		world << line*/

	world << "There are [count] objects of type [type_path] on z-level [num_level]"
	feedback_add_details("admin_verb","mOBJZ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/count_objects_all()
	set category = "Mapping"
	set name = "Count Objects All"

	var/type_text = input("Which type path?","") as text
	if(!type_text) return
	var/type_path = text2path(type_text)
	if(!type_path) return

	var/count = 0

	for(var/atom/A in world)
		if(istype(A,type_path))
			count++
	/*
	var/atom/temp_atom
	for(var/i = 0; i <= (atom_list.len/10); i++)
		var/line = ""
		for(var/j = 1; j <= 10; j++)
			if(i*10+j <= atom_list.len)
				temp_atom = atom_list[i*10+j]
				line += " no.[i+10+j]@\[[temp_atom.x], [temp_atom.y], [temp_atom.z]\]; "
		world << line*/

	world << "There are [count] objects of type [type_path] in the game world"
	feedback_add_details("admin_verb","mOBJ") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

//This proc is intended to detect lag problems relating to communication procs
var/global/say_disabled = 0
/client/proc/disable_communication()
	set category = "Mapping"
	set name = "Disable all communication verbs"

	say_disabled = !say_disabled
	if(say_disabled)
		message_admins("[src.ckey] used 'Disable all communication verbs', killing all communication methods.")
	else
		message_admins("[src.ckey] used 'Disable all communication verbs', restoring all communication methods.")


code:
/client/proc/forcerandomrotate()
	set category = "Server"
	set name = "Trigger Random Map Rotation"
	var/rotate = alert("Force a random map rotation to trigger?", "Rotate map?", "Yes", "Cancel")
	if (rotate != "Yes")
		return
	message_admins("[key_name_admin(usr)] is forcing a random map rotation.")
	log_admin("[key_name(usr)] is forcing a random map rotation.")
	ticker.maprotatechecked = 1
	maprotate()

/client/proc/adminchangemap()
	set category = "Server"
	set name = "Change Map"
	var/list/maprotatechoices = list()
	for (var/map in config.maplist)
		var/datum/votablemap/VM = config.maplist[map]
		var/mapname = VM.friendlyname
		if (VM == config.defaultmap)
			mapname += " (Default)"

		if (VM.minusers > 0 || VM.maxusers > 0)
			mapname += " \["
			if (VM.minusers > 0)
				mapname += "[VM.minusers]"
			else
				mapname += "0"
			mapname += "-"
			if (VM.maxusers > 0)
				mapname += "[VM.maxusers]"
			else
				mapname += "inf"
			mapname += "\]"

		maprotatechoices[mapname] = VM
	var/chosenmap = input("Choose a map to change to", "Change Map")  as null|anything in maprotatechoices
	if (!chosenmap)
		return
	ticker.maprotatechecked = 1
	var/datum/votablemap/VM = maprotatechoices[chosenmap]
	message_admins("[key_name_admin(usr)] is changing the map to [VM.name]([VM.friendlyname])")
	log_admin("[key_name(usr)] is changing the map to [VM.name]([VM.friendlyname])")
	if (changemap(VM) == 0)
		message_admins("[key_name_admin(usr)] has changed the map to [VM.name]([VM.friendlyname])")


code:
/client/proc/cmd_mass_modify_object_variables(atom/A, var_name)
	set category = "Debug"
	set name = "Mass Edit Variables"
	set desc="(target) Edit all instances of a target item's variables"

	var/method = 0	//0 means strict type detection while 1 means this type and all subtypes (IE: /obj/item with this set to 1 will set it to ALL itms)

	if(!check_rights(R_VAREDIT))
		return

	if(A && A.type)
		if(typesof(A.type))
			switch(input("Strict object type detection?") as null|anything in list("Strictly this type","This type and subtypes", "Cancel"))
				if("Strictly this type")
					method = 0
				if("This type and subtypes")
					method = 1
				if("Cancel")
					return
				if(null)
					return

	src.massmodify_variables(A, var_name, method)
	feedback_add_details("admin_verb","MEV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/client/proc/massmodify_variables(atom/O, var_name = "", method = 0)
	if(!check_rights(R_VAREDIT))
		return

	for(var/p in forbidden_varedit_object_types)
		if( istype(O,p) )
			usr << "It is forbidden to edit this object's variables."
			return

	var/list/names = list()
	for (var/V in O.vars)
		names += V

	names = sortList(names)

	var/variable = ""

	if(!var_name)
		variable = input("Which var?","Var") as null|anything in names
	else
		variable = var_name

	if(!variable)
		return
	var/default
	var/var_value = O.vars[variable]
	var/dir

	if(variable in VVckey_edit)
		usr << "It's forbidden to mass-modify ckeys. I'll crash everyone's client you dummy."
		return
	if(variable in VVlocked)
		if(!check_rights(R_DEBUG))
			return
	if(variable in VVicon_edit_lock)
		if(!check_rights(R_FUN|R_DEBUG))
			return

	if(isnull(var_value))
		usr << "Unable to determine variable type."

	else if(isnum(var_value))
		usr << "Variable appears to be NUM."
		default = "num"
		dir = 1

	else if(istext(var_value))
		usr << "Variable appears to be TEXT."
		default = "text"

	else if(isloc(var_value))
		usr << "Variable appears to be REFERENCE."
		default = "reference"

	else if(isicon(var_value))
		usr << "Variable appears to be ICON."
		var_value = "\icon[var_value]"
		default = "icon"

	else if(istype(var_value,/atom) || istype(var_value,/datum))
		usr << "Variable appears to be TYPE."
		default = "type"

	else if(istype(var_value,/list))
		usr << "Variable appears to be LIST."
		default = "list"

	else if(istype(var_value,/client))
		usr << "Variable appears to be CLIENT."
		default = "cancel"

	else
		usr << "Variable appears to be FILE."
		default = "file"

	usr << "Variable contains: [var_value]"
	if(dir)
		switch(var_value)
			if(1)
				dir = "NORTH"
			if(2)
				dir = "SOUTH"
			if(4)
				dir = "EAST"
			if(8)
				dir = "WEST"
			if(5)
				dir = "NORTHEAST"
			if(6)
				dir = "SOUTHEAST"
			if(9)
				dir = "NORTHWEST"
			if(10)
				dir = "SOUTHWEST"
			else
				dir = null
		if(dir)
			usr << "If a direction, direction is: [dir]"

	var/class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
		"num","type","icon","file","edit referenced object","restore to default")

	if(!class)
		return

	var/original_name

	if (!istype(O, /atom))
		original_name = "\ref[O] ([O])"
	else
		original_name = O:name

	switch(class)

		if("restore to default")
			O.vars[variable] = initial(O.vars[variable])
			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

		if("edit referenced object")
			return .(O.vars[variable])

		if("text")
			var/new_value = input("Enter new text:","Text",O.vars[variable]) as message|null
			if(new_value == null) return

			var/process_vars = 0
			var/unique = 0
			if(findtext(new_value,"\["))
				process_vars = alert(usr,"\[] detected in string, process as variables?","Process Variables?","Yes","No")
				if(process_vars == "Yes")
					process_vars = 1
					unique = alert(usr,"Process vars unique to each instance, or same for all?","Variable Association","Unique","Same")
					if(unique == "Unique")
						unique = 1
					else
						unique = 0
				else
					process_vars = 0

			var/pre_processing = new_value
			var/list/varsvars = list()

			if(process_vars)
				varsvars = string2listofvars(new_value, O)
				if(varsvars.len)
					for(var/V in varsvars)
						new_value = replacetext(new_value,"\[[V]]","[O.vars[V]]")

			O.vars[variable] = new_value

			//Convert the string vars for anything that's not O
			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							new_value = pre_processing //reset new_value, ready to convert it uniquely for the next iteration

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[M.vars[V]]")
								else
									new_value = O.vars[variable] //We already processed the non-unique form for O, reuse it

							M.vars[variable] = new_value
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							new_value = pre_processing

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[A.vars[V]]")
								else
									new_value = O.vars[variable]

							A.vars[variable] = new_value
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							new_value = pre_processing

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[A.vars[V]]")
								else
									new_value = O.vars[variable]

							A.vars[variable] = new_value
						CHECK_TICK
			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							new_value = pre_processing

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[M.vars[V]]")
								else
									new_value = O.vars[variable]

							M.vars[variable] = new_value
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							new_value = pre_processing

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[A.vars[V]]")
								else
									new_value = O.vars[variable]

							A.vars[variable] = new_value
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							new_value = pre_processing

							if(process_vars)
								if(unique)
									for(var/V in varsvars)
										new_value = replacetext(new_value,"\[[V]]","[A.vars[V]]")
								else
									new_value = O.vars[variable]

							A.vars[variable] = new_value
						CHECK_TICK

		if("num")
			var/new_value = input("Enter new number:","Num",\
					O.vars[variable]) as num|null
			if(new_value == null) return

			if(variable=="luminosity")
				O.SetLuminosity(new_value)
			else
				O.vars[variable] = new_value

			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							if(variable=="luminosity")
								M.SetLuminosity(new_value)
							else
								M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							if(variable=="luminosity")
								A.SetLuminosity(new_value)
							else
								A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							if(variable=="luminosity")
								A.SetLuminosity(new_value)
							else
								A.vars[variable] = O.vars[variable]
						CHECK_TICK

			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							if(variable=="luminosity")
								M.SetLuminosity(new_value)
							else
								M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							if(variable=="luminosity")
								A.SetLuminosity(new_value)
							else
								A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							if(variable=="luminosity")
								A.SetLuminosity(new_value)
							else
								A.vars[variable] = O.vars[variable]
						CHECK_TICK

		if("type")
			var/new_value
			new_value = input("Enter type:","Type",O.vars[variable]) as null|anything in typesof(/obj,/mob,/area,/turf)
			if(new_value == null) return
			O.vars[variable] = new_value
			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

		if("file")
			var/new_value = input("Pick file:","File",O.vars[variable]) as null|file
			if(new_value == null) return
			O.vars[variable] = new_value

			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O.type, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O.type, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK
			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

		if("icon")
			var/new_value = input("Pick icon:","Icon",O.vars[variable]) as null|icon
			if(new_value == null) return
			O.vars[variable] = new_value
			if(method)
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if ( istype(M , O.type) )
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if ( istype(A , O.type) )
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

			else
				if(istype(O, /mob))
					for(var/mob/M in mob_list)
						if (M.type == O.type)
							M.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /obj))
					for(var/obj/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

				else if(istype(O, /turf))
					for(var/turf/A in world)
						if (A.type == O.type)
							A.vars[variable] = O.vars[variable]
						CHECK_TICK

	if(method)
		if(istype(O,/mob))
			for(var/mob/M in mob_list)
				if(istype(M,O.type))
					M.on_varedit(variable)
				CHECK_TICK

		else if(istype(O,/obj))
			for(var/obj/A in world)
				if(istype(A,O.type))
					A.on_varedit(variable)
				CHECK_TICK

		else if(istype(O,/turf))
			for(var/turf/A in block(locate(1,1,1),locate(world.maxx,world.maxy,world.maxz)))
				if(istype(A,O.type))
					A.on_varedit(variable)
				CHECK_TICK

	else
		if(istype(O, /mob))
			for(var/mob/M in mob_list)
				if(M.type == O.type)
					M.on_varedit(variable)
				CHECK_TICK

		else if(istype(O, /obj))
			for(var/obj/A in world)
				if(A.type == O.type)
					A.on_varedit(variable)
				CHECK_TICK

		else if(istype(O, /turf))
			for(var/turf/A in world)
				if(A.type == O.type)
					A.on_varedit(variable)
				CHECK_TICK

	world.log << "### MassVarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
	log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]")
	message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]]")