anchor.diff:  
   /obj/item/device/uplink
   	var/welcome 					// Welcoming menu message
  -	var/items						// List of items
  -	var/item_data					// raw item text
  -	var/list/ItemList				// Parsed list of items
   	var/uses 						// Numbers of crystals
  -	var/nanoui_items[0]
   	// List of items not to shove in their hands.
  -	var/list/NotInHand = list(/obj/machinery/singularity_beacon/syndicate)
  +	var/list/purchase_log = list()
  +	var/show_description = null
  +	var/active = 0
  +	var/job = null
   
   /obj/item/device/uplink/New()
  +	..()
   	welcome = ticker.mode.uplink_welcome
  -	if(!item_data)
  -		items = replacetext(ticker.mode.uplink_items, "\n", "")	// Getting the text string of items
  -	else
  -		items = replacetext(item_data)
  -	ItemList = text2list(src.items, ";")	// Parsing the items text string
   	uses = ticker.mode.uplink_uses
  -	nanoui_items = generate_nanoui_items()
  -
  -/*
  -	Built the Items List for use with NanoUI
  -*/
  -
  -/obj/item/device/uplink/proc/generate_nanoui_items()
  -	var/items_nano[0]
  -	for(var/D in ItemList)
  -		var/list/O = stringsplit(D, ":")
  -		if(O.len != 3)  //If it is not an actual item, make a break in the menu.
  -			if(O.len == 1)  //If there is one item, it's probably a title
  -				items_nano[++items_nano.len] = list("Category" = "[O[1]]", "items" = list())
  -			continue
  -
  -		var/path_text = O[1]
  -		var/cost = text2num(O[2])
  -
  -		var/path_obj = text2path(path_text)
  -
  -		// Because we're using strings, this comes up if item paths change.
  -		// Failure to handle this error borks uplinks entirely.  -Sayu
  -		if(!path_obj)
  -			error("Syndicate item is not a valid path: [path_text]")
  -		else
  -			var/itemname = O[3]
  -			items_nano[items_nano.len]["items"] += list(list("Name" = itemname, "Cost" = cost, "obj_path" = path_text))
  -
  -	return items_nano
  -
  -
  -
  -
   
   //Let's build a menu!
  -/obj/item/device/uplink/proc/generate_menu()
  -
  +/obj/item/device/uplink/proc/generate_menu(mob/user as mob)
  +	if(!job)
  +		job = user.mind.assigned_role
   	var/dat = "<B>[src.welcome]</B><BR>"
  -	dat += "Tele-Crystals left: [src.uses]<BR>"
  -	dat += "<HR>"
  -	dat += "<B>Request item:</B><BR>"
  -	dat += "<I>Each item costs a number of tele-crystals as indicated by the number following their name.</I><br><BR>"
  -
  -	var/cost
  -	var/item
  -	var/name
  -	var/path_obj
  -	var/path_text
  -	var/category_items = 1 //To prevent stupid :P
  -
  -	for(var/D in ItemList)
  -		var/list/O = stringsplit(D, ":")
  -		if(O.len != 3)	//If it is not an actual item, make a break in the menu.
  -			if(O.len == 1)	//If there is one item, it's probably a title
  -				dat += "<b>[O[1]]</b><br>"
  -				category_items = 0
  -			else	//Else, it's a white space.
  -				if(category_items < 1)	//If there were no itens in the last category...
  -					dat += "<i>We apologize, as you could not afford anything from this category.</i><br>"
  -				dat += "<br>"
  -			continue
  -
  -		path_text = O[1]
  -		cost = text2num(O[2])
  -
  -		if(cost>uses)
  -			continue
  -
  -		path_obj = text2path(path_text)
  -
  -		// Because we're using strings, this comes up if item paths change.
  -		// Failure to handle this error borks uplinks entirely.  -Sayu
  -		if(!path_obj)
  -			error("Syndicate item is not a valid path: [path_text]")
  -		else
  -			item = new path_obj()
  -			name = O[3]
  -			del item
  -
  -			dat += "<A href='byond://?src=\ref[src];buy_item=[path_text];cost=[cost]'>[name]</A> ([cost])<BR>"
  -			category_items++
  -
  -	dat += "<A href='byond://?src=\ref[src];buy_item=random'>Random Item (??)</A><br>"
  +
  +	// AUTOFIXED BY fix_string_idiocy.py
  +	// C:\Users\Rob\Documents\Projects\vgstation13\code\game\objects\items\devices\uplinks.dm:26: dat += "Tele-Crystals left: [src.uses]<BR>"
  +	dat += {"Tele-Crystals left: [src.uses]<BR>
  +		<HR>
  +		<B>Request item:</B><BR>
  +		<I>Each item costs a number of tele-crystals as indicated by the number following their name.</I><br><BR>"}
  +	// END AUTOFIX
  +	var/list/buyable_items = get_uplink_items()
  +
  +	// Loop through categories
  +	var/index = 0
  +	for(var/category in buyable_items)
  +
  +		index++
  +		dat += "<b>[category]</b><br>"
  +
  +		var/i = 0
  +
  +		// Loop through items in category
  +		for(var/datum/uplink_item/item in buyable_items[category])
  +			i++
  +
  +			var/cost_text = ""
  +			var/desc = "[item.desc]"
  +			if(item.job && item.job.len)
  +				if(!(item.job.Find(job)))
  +					//world.log << "Skipping job item that doesn't match"
  +					continue
  +				else
  +					//world.log << "Found matching job item"
  +			if(item.cost > 0)
  +				cost_text = "([item.cost])"
  +			if(item.cost <= uses)
  +				dat += "<A href='byond://?src=\ref[src];buy_item=[category]:[i];'>[item.name]</A> [cost_text] "
  +			else
  +				dat += "<font color='grey'><i>[item.name] [cost_text] </i></font>"
  +			if(item.desc)
  +				if(show_description == 2)
  +					dat += "<A href='byond://?src=\ref[src];show_desc=1'><font size=2>\[-\]</font></A><BR><font size=2>[desc]</font>"
  +				else
  +					dat += "<A href='byond://?src=\ref[src];show_desc=2'><font size=2>\[?\]</font></A>"
  +			dat += "<BR>"
  +
  +		// Break up the categories, if it isn't the last.
  +		if(buyable_items.len != index)
  +			dat += "<br>"
  +
   	dat += "<HR>"
   	return dat
   
  -//If 'random' was selected
  -/obj/item/device/uplink/proc/chooseRandomItem()
  -	var/list/randomItems = list()
  -
  -	//Sorry for all the ifs, but it makes it 1000 times easier for other people/servers to add or remove items from this list
  -	//Add only items the player can afford:
  -	if(uses > 19)
  -		randomItems.Add("/obj/item/weapon/circuitboard/teleporter") //Teleporter Circuit Board (costs 20, for nuke ops)
  -
  -	if(uses > 9)
  -		randomItems.Add("/obj/item/toy/syndicateballoon")//Syndicate Balloon
  -		randomItems.Add("/obj/item/weapon/storage/box/syndie_kit/imp_uplink") //Uplink Implanter
  -		randomItems.Add("/obj/item/weapon/storage/box/syndicate") //Syndicate bundle
  -
  -	//if(uses > 8)	//Nothing... yet.
  -	//if(uses > 7)	//Nothing... yet.
  -
  -	if(uses > 6)
  -		randomItems.Add("/obj/item/weapon/aiModule/syndicate") //Hacked AI Upload Module
  -		randomItems.Add("/obj/item/device/radio/beacon/syndicate") //Singularity Beacon
  -
  -	if(uses > 5)
  -		randomItems.Add("/obj/item/weapon/gun/projectile") //Revolver
  -
  -	if(uses > 4)
  -		randomItems.Add("/obj/item/weapon/gun/energy/crossbow") //Energy Crossbow
  -		randomItems.Add("/obj/item/device/powersink") //Powersink
  -
  -	if(uses > 3)
  -		randomItems.Add("/obj/item/weapon/melee/energy/sword") //Energy Sword
  -		randomItems.Add("/obj/item/clothing/mask/gas/voice") //Voice Changer
  -		randomItems.Add("/obj/item/device/chameleon") //Chameleon Projector
  -
  -	if(uses > 2)
  -		randomItems.Add("/obj/item/weapon/storage/box/emps") //EMP Grenades
  -		randomItems.Add("/obj/item/weapon/pen/paralysis") //Paralysis Pen
  -		randomItems.Add("/obj/item/weapon/cartridge/syndicate") //Detomatix Cartridge
  -		randomItems.Add("/obj/item/clothing/under/chameleon") //Chameleon Jumpsuit
  -		randomItems.Add("/obj/item/weapon/card/id/syndicate") //Agent ID Card
  -		randomItems.Add("/obj/item/weapon/card/emag") //Cryptographic Sequencer
  -		randomItems.Add("/obj/item/weapon/storage/box/syndie_kit/space") //Syndicate Space Suit
  -		randomItems.Add("/obj/item/device/encryptionkey/binary") //Binary Translator Key
  -		randomItems.Add("/obj/item/weapon/storage/box/syndie_kit/imp_freedom") //Freedom Implant
  -		randomItems.Add("/obj/item/clothing/glasses/thermal/syndi") //Thermal Imaging Goggles
  -
  -	if(uses > 1)
  -/*
  -		var/list/usrItems = usr.get_contents() //Checks to see if the user has a revolver before giving ammo
  -		var/hasRevolver = 0
  -		for(var/obj/I in usrItems) //Only add revolver ammo if the user has a gun that can shoot it
  -			if(istype(I,/obj/item/weapon/gun/projectile))
  -				hasRevolver = 1
  -
  -		if(hasRevolver) randomItems.Add("/obj/item/ammo_magazine/a357") //Revolver ammo
  -*/
  -		randomItems.Add("/obj/item/ammo_magazine/a357") //Revolver ammo
  -		randomItems.Add("/obj/item/clothing/shoes/syndigaloshes") //No-Slip Syndicate Shoes
  -		randomItems.Add("/obj/item/weapon/plastique") //C4
  -
  -	if(uses > 0)
  -		randomItems.Add("/obj/item/weapon/soap/syndie") //Syndicate Soap
  -		randomItems.Add("/obj/item/weapon/storage/toolbox/syndicate") //Syndicate Toolbox
  -
  -	if(!randomItems.len)
  -		del(randomItems)
  -		return 0
  -	else
  -		var/buyItem = pick(randomItems)
  -
  -		switch(buyItem) //Ok, this gets a little messy, sorry.
  -			if("/obj/item/weapon/circuitboard/teleporter")
  -				uses -= 20
  -			if("/obj/item/toy/syndicateballoon" , "/obj/item/weapon/storage/box/syndie_kit/imp_uplink" , "/obj/item/weapon/storage/box/syndicate")
  -				uses -= 10
  -			if("/obj/item/weapon/aiModule/syndicate" , "/obj/item/device/radio/beacon/syndicate")
  -				uses -= 7
  -			if("/obj/item/weapon/gun/projectile")
  -				uses -= 6
  -			if("/obj/item/weapon/gun/energy/crossbow" , "/obj/item/device/powersink")
  -				uses -= 5
  -			if("/obj/item/weapon/melee/energy/sword" , "/obj/item/clothing/mask/gas/voice" , "/obj/item/device/chameleon")
  -				uses -= 4
  -			if("/obj/item/weapon/storage/box/emps" , "/obj/item/weapon/pen/paralysis" , "/obj/item/weapon/cartridge/syndicate" , "/obj/item/clothing/under/chameleon" , \
  -			"/obj/item/weapon/card/emag" , "/obj/item/weapon/storage/box/syndie_kit/space" , "/obj/item/device/encryptionkey/binary" , \
  -			"/obj/item/weapon/storage/box/syndie_kit/imp_freedom" , "/obj/item/clothing/glasses/thermal/syndi")
  -				uses -= 3
  -			if("/obj/item/ammo_magazine/a357" , "/obj/item/clothing/shoes/syndigaloshes" , "/obj/item/weapon/plastique", "/obj/item/weapon/card/id/syndicate")
  -				uses -= 2
  -			if("/obj/item/weapon/soap/syndie" , "/obj/item/weapon/storage/toolbox/syndicate")
  -				uses -= 1
  -		del(randomItems)
  -		return buyItem
  -
  -/obj/item/device/uplink/proc/handleStatTracking(var/boughtItem)
  -//For stat tracking, sorry for making it so ugly
  -	if(!boughtItem) return
  -
  -	switch(boughtItem)
  -		if("/obj/item/weapon/circuitboard/teleporter")
  -			feedback_add_details("traitor_uplink_items_bought","TP")
  -		if("/obj/item/toy/syndicateballoon")
  -			feedback_add_details("traitor_uplink_items_bought","BS")
  -		if("/obj/item/weapon/storage/box/syndie_kit/imp_uplink")
  -			feedback_add_details("traitor_uplink_items_bought","UI")
  -		if("/obj/item/weapon/storage/box/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","BU")
  -		if("/obj/item/weapon/aiModule/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","AI")
  -		if("/obj/item/device/radio/beacon/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","SB")
  -		if("/obj/item/weapon/gun/projectile")
  -			feedback_add_details("traitor_uplink_items_bought","RE")
  -		if("/obj/item/weapon/gun/energy/crossbow")
  -			feedback_add_details("traitor_uplink_items_bought","XB")
  -		if("/obj/item/device/powersink")
  -			feedback_add_details("traitor_uplink_items_bought","PS")
  -		if("/obj/item/weapon/melee/energy/sword")
  -			feedback_add_details("traitor_uplink_items_bought","ES")
  -		if("/obj/item/clothing/mask/gas/voice")
  -			feedback_add_details("traitor_uplink_items_bought","VC")
  -		if("/obj/item/device/chameleon")
  -			feedback_add_details("traitor_uplink_items_bought","CP")
  -		if("/obj/item/weapon/storage/box/emps")
  -			feedback_add_details("traitor_uplink_items_bought","EM")
  -		if("/obj/item/weapon/pen/paralysis")
  -			feedback_add_details("traitor_uplink_items_bought","PP")
  -		if("/obj/item/weapon/cartridge/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","DC")
  -		if("/obj/item/clothing/under/chameleon")
  -			feedback_add_details("traitor_uplink_items_bought","CJ")
  -		if("/obj/item/weapon/card/id/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","AC")
  -		if("/obj/item/weapon/card/emag")
  -			feedback_add_details("traitor_uplink_items_bought","EC")
  -		if("/obj/item/weapon/storage/box/syndie_kit/space")
  -			feedback_add_details("traitor_uplink_items_bought","SS")
  -		if("/obj/item/device/encryptionkey/binary")
  -			feedback_add_details("traitor_uplink_items_bought","BT")
  -		if("/obj/item/weapon/storage/box/syndie_kit/imp_freedom")
  -			feedback_add_details("traitor_uplink_items_bought","FI")
  -		if("/obj/item/clothing/glasses/thermal/syndi")
  -			feedback_add_details("traitor_uplink_items_bought","TM")
  -		if("/obj/item/ammo_magazine/a357")
  -			feedback_add_details("traitor_uplink_items_bought","RA")
  -		if("/obj/item/clothing/shoes/syndigaloshes")
  -			feedback_add_details("traitor_uplink_items_bought","SH")
  -		if("/obj/item/weapon/plastique")
  -			feedback_add_details("traitor_uplink_items_bought","C4")
  -		if("/obj/item/weapon/soap/syndie")
  -			feedback_add_details("traitor_uplink_items_bought","SP")
  -		if("/obj/item/weapon/storage/toolbox/syndicate")
  -			feedback_add_details("traitor_uplink_items_bought","ST")
  +// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
  +/obj/item/device/uplink/interact(mob/user as mob)
  +
  +	var/dat = "<body link='yellow' alink='white' bgcolor='#601414'><font color='white'>"
  +	dat += src.generate_menu(user)
  +
  +	// AUTOFIXED BY fix_string_idiocy.py
  +	// C:\Users\Rob\Documents\Projects\vgstation13\code\game\objects\items\devices\uplinks.dm:72: dat += "<A href='byond://?src=\ref[src];lock=1'>Lock</a>"
  +	dat += {"<A href='byond://?src=\ref[src];lock=1'>Lock</a>
  +		</font></body>"}
  +	// END AUTOFIX
  +	user << browse(dat, "window=hidden")
  +	onclose(user, "hidden")
  +	return
  +
   
   /obj/item/device/uplink/Topic(href, href_list)
  +	..()
  +	if(!active)
  +		return
  +
   	if (href_list["buy_item"])
   
  -		if(href_list["buy_item"] == "random")
  -			var/boughtItem = chooseRandomItem()
  -			if(boughtItem)
  -				href_list["buy_item"] = boughtItem
  -				feedback_add_details("traitor_uplink_items_bought","RN")
  -				return 1
  +		var/item = href_list["buy_item"]
  +		var/list/split = stringsplit(item, ":") // throw away variable
  +
  +		if(split.len == 2)
  +			// Collect category and number
  +			var/category = split[1]
  +			var/number = text2num(split[2])
  +
  +			var/list/buyable_items = get_uplink_items()
  +
  +			var/list/uplink = buyable_items[category]
  +			if(uplink && uplink.len >= number)
  +				var/datum/uplink_item/I = uplink[number]
  +				if(I)
  +					I.buy(src, usr)
   			else
  -				return 0
  -
  -		else
  -			if(text2num(href_list["cost"]) > uses) // Not enough crystals for the item
  -				return 0
  -
  -			//if(usr:mind && ticker.mode.traitors[usr:mind])
  -				//var/datum/traitorinfo/info = ticker.mode.traitors[usr:mind]
  -				//info.spawnlist += href_list["buy_item"]
  -
  -			uses -= text2num(href_list["cost"])
  -			handleStatTracking(href_list["buy_item"]) //Note: chooseRandomItem handles it's own stat tracking. This proc is not meant for 'random'.
  -		return 1
  -
  -
  +				var/text = "[key_name(usr)] tried to purchase an uplink item that doesn't exist"
  +				var/textalt = "[key_name(usr)] tried to purchase an uplink item that doesn't exist [item]"
  +				message_admins(text)
  +				log_game(textalt)
  +				admin_log.Add(textalt)
  +
  +	else if(href_list["show_desc"])
  +		show_description = text2num(href_list["show_desc"])
  +		interact(usr)
   
   // HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it.
   /* How to create an uplink in 3 easy steps!
  
positive.code: /obj/item/device/uplink/hidden
  	name = "Hidden Uplink."
  	desc = "There is something wrong if you're examining this."
  	var/active = 0
  	var/list/purchase_log = list()
  
  // The hidden uplink MUST be inside an obj/item's contents.
  /obj/item/device/uplink/hidden/New()
  	spawn(2)
  		if(!istype(src.loc, /obj/item))
  			del(src)
  	..()
  
  // Toggles the uplink on and off. Normally this will bypass the item's normal functions and go to the uplink menu, if activated.
  /obj/item/device/uplink/hidden/proc/toggle()
  
negative.code: 		trigger(user)
  		return 1
  	return 0
  
  // I placed this here because of how relevant it is.
  // You place this in your uplinkable item to check if an uplink is active or not.
  