code:
// the light switch
// can have multiple per area
// can also operate on non-loc area through "otherarea" var
/obj/machinery/light_switch
	name = "light switch"
	icon = 'icons/obj/power.dmi'
	icon_state = "light1"
	anchored = 1
	var/on = 1
	var/area/area = null
	var/otherarea = null
	//	luminosity = 1

/obj/machinery/light_switch/New()
	..()
	spawn(5)
		src.area = src.loc.loc

		if(otherarea)
			src.area = locate(text2path("/area/[otherarea]"))

		if(!name)
			name = "light switch ([area.name])"

		src.on = src.area.lightswitch
		updateicon()

/obj/machinery/light_switch/proc/updateicon()
	if(stat & NOPOWER)
		icon_state = "light-p"
	else
		if(on)
			icon_state = "light1"
		else
			icon_state = "light0"

/obj/machinery/light_switch/examine(mob/user)
	..()
	user << "It is [on? "on" : "off"]."

/obj/machinery/light_switch/attack_paw(mob/user)
	src.attack_hand(user)

/obj/machinery/light_switch/attack_hand(mob/user)

	on = !on

	for(var/area/A in area.master.related)
		A.lightswitch = on
		A.updateicon()

		for(var/obj/machinery/light_switch/L in A)
			L.on = on
			L.updateicon()

	area.master.power_change()

/obj/machinery/light_switch/power_change()

	if(!otherarea)
		if(powered(LIGHT))
			stat &= ~NOPOWER
		else
			stat |= NOPOWER

		updateicon()

/obj/machinery/light_switch/emp_act(severity)
	if(stat & (BROKEN|NOPOWER))
		..(severity)
		return
	power_change()
	..(severity)


code:
/*
Overview:
   Used to create objects that need a per step proc call.  Default definition of 'New()'
   stores a reference to src machine in global 'machines list'.  Default definition
   of 'Del' removes reference to src machine in global 'machines list'.

Class Variables:
   use_power (num)
      current state of auto power use.
      Possible Values:
         0 -- no auto power use
         1 -- machine is using power at its idle power level
         2 -- machine is using power at its active power level

   active_power_usage (num)
      Value for the amount of power to use when in active power mode

   idle_power_usage (num)
      Value for the amount of power to use when in idle power mode

   power_channel (num)
      What channel to draw from when drawing power for power mode
      Possible Values:
         EQUIP:0 -- Equipment Channel
         LIGHT:2 -- Lighting Channel
         ENVIRON:3 -- Environment Channel

   component_parts (list)
      A list of component parts of machine used by frame based machines.

   uid (num)
      Unique id of machine across all machines.

   gl_uid (global num)
      Next uid value in sequence

   stat (bitflag)
      Machine status bit flags.
      Possible bit flags:
         BROKEN:1 -- Machine is broken
         NOPOWER:2 -- No power is being supplied to machine.
         POWEROFF:4 -- tbd
         MAINT:8 -- machine is currently under going maintenance.
         EMPED:16 -- temporary broken by EMP pulse

Class Procs:
   New()                     'game/machinery/machine.dm'

   Destroy()                   'game/machinery/machine.dm'

   auto_use_power()            'game/machinery/machine.dm'
      This proc determines how power mode power is deducted by the machine.
      'auto_use_power()' is called by the 'master_controller' game_controller every
      tick.

      Return Value:
         return:1 -- if object is powered
         return:0 -- if object is not powered.

      Default definition uses 'use_power', 'power_channel', 'active_power_usage',
      'idle_power_usage', 'powered()', and 'use_power()' implement behavior.

   powered(chan = EQUIP)         'modules/power/power.dm'
      Checks to see if area that contains the object has power available for power
      channel given in 'chan'.

   use_power(amount, chan=EQUIP)   'modules/power/power.dm'
      Deducts 'amount' from the power channel 'chan' of the area that contains the object.

   power_change()               'modules/power/power.dm'
      Called by the area that contains the object when ever that area under goes a
      power state change (area runs out of power, or area channel is turned off).

   RefreshParts()               'game/machinery/machine.dm'
      Called to refresh the variables in the machine that are contributed to by parts
      contained in the component_parts list. (example: glass and material amounts for
      the autolathe)

      Default definition does nothing.

   assign_uid()               'game/machinery/machine.dm'
      Called by machine to assign a value to the uid variable.

   process()                  'game/machinery/machine.dm'
      Called by the 'machinery subsystem' once per machinery tick for each machine that is listed in its 'machines' list.

   process_atmos()
      Called by the 'air subsystem' once per atmos tick for each machine that is listed in its 'atmos_machines' list.

   is_operational()
		Returns 0 if the machine is unpowered, broken or undergoing maintenance, something else if not

	Compiled by Aygar
*/

/obj/machinery
	name = "machinery"
	icon = 'icons/obj/stationobjs.dmi'
	verb_yell = "blares"
	pressure_resistance = 10
	var/stat = 0
	var/emagged = 0
	var/use_power = 1
		//0 = dont run the auto
		//1 = run auto, use idle
		//2 = run auto, use active
	var/idle_power_usage = 0
	var/active_power_usage = 0
	var/power_channel = EQUIP
		//EQUIP,ENVIRON or LIGHT
	var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames.
	var/uid
	var/global/gl_uid = 1
	var/panel_open = 0
	var/state_open = 0
	var/mob/living/occupant = null
	var/unsecuring_tool = /obj/item/weapon/wrench
	var/interact_open = 0 // Can the machine be interacted with when in maint/when the panel is open.
	var/interact_offline = 0 // Can the machine be interacted with while de-powered.
	var/speed_process = 0 // Process as fast as possible?

/obj/machinery/New()
	..()
	machines += src
	if(!speed_process)
		SSmachine.processing += src
	else
		SSfastprocess.processing += src
	power_change()

/obj/machinery/Destroy()
	machines.Remove(src)
	if(!speed_process)
		SSmachine.processing -= src
	else
		SSfastprocess.processing -= src
	dropContents()
	return ..()

/obj/machinery/attackby(obj/item/weapon/W, mob/user, params)
	user.changeNext_move(CLICK_CD_MELEE)
	..()

/obj/machinery/proc/locate_machinery()
	return

/obj/machinery/process()//If you dont use process or power why are you here
	return PROCESS_KILL

/obj/machinery/proc/process_atmos()//If you dont use process why are you here
	return PROCESS_KILL

/obj/machinery/emp_act(severity)
	if(use_power && stat == 0)
		use_power(7500/severity)

		PoolOrNew(/obj/effect/overlay/temp/emp, loc)
	..()

/obj/machinery/proc/open_machine()
	state_open = 1
	density = 0
	dropContents()
	update_icon()
	updateUsrDialog()

/obj/machinery/proc/dropContents()
	var/turf/T = get_turf(src)
	for(var/mob/living/L in src)
		L.loc = T
		L.reset_perspective(null)
		L.update_canmove() //so the mob falls if he became unconscious inside the machine.
		. += L

	T.contents += contents
	occupant = null

/obj/machinery/proc/close_machine(mob/living/target = null)
	state_open = 0
	density = 1
	if(!target)
		for(var/mob/living/carbon/C in loc)
			if(C.buckled || C.buckled_mobs.len)
				continue
			else
				target = C
	if(target && !target.buckled && !target.buckled_mobs.len)
		occupant = target
		target.forceMove(src)
	updateUsrDialog()
	update_icon()

/obj/machinery/blob_act()
	if(!density)
		qdel(src)
	if(prob(75))
		qdel(src)

/obj/machinery/proc/auto_use_power()
	if(!powered(power_channel))
		return 0
	if(use_power == 1)
		use_power(idle_power_usage,power_channel)
	else if(use_power >= 2)
		use_power(active_power_usage,power_channel)
	return 1

/obj/machinery/proc/is_operational()
	return !(stat & (NOPOWER|BROKEN|MAINT))

/obj/machinery/proc/is_interactable()
	if((stat & (NOPOWER|BROKEN)) && !interact_offline)
		return FALSE
	if(panel_open && !interact_open)
		return FALSE
	return TRUE

////////////////////////////////////////////////////////////////////////////////////////////

/obj/machinery/interact(mob/user)
	add_fingerprint(user)
	ui_interact(user)

/obj/machinery/ui_status(mob/user)
	if(is_interactable())
		return ..()
	return UI_CLOSE

/obj/machinery/ui_act(action, params)
	add_fingerprint(usr)
	return ..()

/obj/machinery/Topic(href, href_list)
	..()
	if(!is_interactable())
		return 1
	if(!usr.canUseTopic(src))
		return 1
	add_fingerprint(usr)
	return 0

////////////////////////////////////////////////////////////////////////////////////////////

/obj/machinery/attack_ai(mob/user)
	if(isrobot(user))// For some reason attack_robot doesn't work
		var/mob/living/silicon/robot/R = user
		if(R.client && R.client.eye == R && !R.low_power_mode)// This is to stop robots from using cameras to remotely control machines; and from using machines when the borg has no power.
			return attack_hand(user)
	else
		return attack_hand(user)

/obj/machinery/attack_paw(mob/user)
	return attack_hand(user)

//set_machine must be 0 if clicking the machinery doesn't bring up a dialog
/obj/machinery/attack_hand(mob/user, check_power = 1, set_machine = 1)
	if(..())// unbuckling etc
		return 1
	if((user.lying || user.stat) && !IsAdminGhost(user))
		return 1
	if(!user.IsAdvancedToolUser() && !IsAdminGhost(user))
		usr << "You don't have the dexterity to do this!"
		return 1
	if(ishuman(user))
		var/mob/living/carbon/human/H = user
		if(prob(H.getBrainLoss()))
			user << "You momentarily forget how to use [src]!"
			return 1
	if(!is_interactable())
		return 1
	if(set_machine)
		user.set_machine(src)
	interact(user)
	add_fingerprint(user)
	return 0

/obj/machinery/CheckParts()
	RefreshParts()
	return

/obj/machinery/proc/RefreshParts() //Placeholder proc for machines that are built using frames.
	return

/obj/machinery/proc/assign_uid()
	uid = gl_uid
	gl_uid++

/obj/machinery/proc/default_pry_open(obj/item/weapon/crowbar/C)
	. = !(state_open || panel_open || is_operational() || (flags & NODECONSTRUCT)) && istype(C)
	if(.)
		playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
		visible_message("[usr] pries open \the [src].", "You pry open \the [src].")
		open_machine()
		return 1

/obj/machinery/proc/default_deconstruction_crowbar(obj/item/weapon/crowbar/C, ignore_panel = 0)
	. = istype(C) && (panel_open || ignore_panel) &&  !(flags & NODECONSTRUCT)
	if(.)
		deconstruction()
		playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
		var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(loc)
		transfer_fingerprints_to(M)
		M.state = 2
		M.icon_state = "box_1"
		for(var/obj/item/I in component_parts)
			if(I.reliability != 100 && crit_fail)
				I.crit_fail = 1
			I.loc = loc
		qdel(src)

/obj/machinery/proc/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/weapon/screwdriver/S)
	if(istype(S) &&  !(flags & NODECONSTRUCT))
		playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
		if(!panel_open)
			panel_open = 1
			icon_state = icon_state_open
			user << "You open the maintenance hatch of [src]."
		else
			panel_open = 0
			icon_state = icon_state_closed
			user << "You close the maintenance hatch of [src]."
		return 1
	return 0

/obj/machinery/proc/default_change_direction_wrench(mob/user, obj/item/weapon/wrench/W)
	if(panel_open && istype(W))
		playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
		dir = turn(dir,-90)
		user << "You rotate [src]."
		return 1
	return 0

/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20)
	if(istype(W) &&  !(flags & NODECONSTRUCT))
		user << "You begin [anchored ? "un" : ""]securing [name]..."
		playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
		if(do_after(user, time/W.toolspeed, target = src))
			user << "You [anchored ? "un" : ""]secure [name]."
			anchored = !anchored
			playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
		return 1
	return 0

/obj/machinery/proc/exchange_parts(mob/user, obj/item/weapon/storage/part_replacer/W)
	if(flags & NODECONSTRUCT)
		return
	var/shouldplaysound = 0
	if(istype(W) && component_parts)
		if(panel_open || W.works_from_distance)
			var/obj/item/weapon/circuitboard/CB = locate(/obj/item/weapon/circuitboard) in component_parts
			var/P
			if(W.works_from_distance)
				display_parts(user)
			for(var/obj/item/weapon/stock_parts/A in component_parts)
				for(var/D in CB.req_components)
					if(ispath(A.type, D))
						P = D
						break
				for(var/obj/item/weapon/stock_parts/B in W.contents)
					if(istype(B, P) && istype(A, P))
						if(B.rating > A.rating)
							W.remove_from_storage(B, src)
							W.handle_item_insertion(A, 1)
							component_parts -= A
							component_parts += B
							B.loc = null
							user << "[A.name] replaced with [B.name]."
							shouldplaysound = 1 //Only play the sound when parts are actually replaced!
							break
			RefreshParts()
		else
			display_parts(user)
		if(shouldplaysound)
			W.play_rped_sound()
		return 1
	return 0

/obj/machinery/proc/display_parts(mob/user)
	user << "Following parts detected in the machine:"
	for(var/obj/item/C in component_parts)
		user << "\icon[C] [C.name]"

/obj/machinery/examine(mob/user)
	..()
	if(user.research_scanner && component_parts)
		display_parts(user)

//called on machinery construction (i.e from frame to machinery) but not on initialization
/obj/machinery/proc/construction()
	return

//called on deconstruction before the final deletion
/obj/machinery/proc/deconstruction()
	return

/obj/machinery/allow_drop()
	return 0

// Hook for html_interface module to prevent updates to clients who don't have this as their active machine.
/obj/machinery/proc/hiIsValidClient(datum/html_interface_client/hclient, datum/html_interface/hi)
	if (hclient.client.mob && (hclient.client.mob.stat == 0 || IsAdminGhost(hclient.client.mob)))
		if (isAI(hclient.client.mob) || IsAdminGhost(hclient.client.mob)) return TRUE
		else                          return hclient.client.mob.machine == src && Adjacent(hclient.client.mob)
	else
		return FALSE

// Hook for html_interface module to unset the active machine when the window is closed by the player.
/obj/machinery/proc/hiOnHide(datum/html_interface_client/hclient)
	if (hclient.client.mob && hclient.client.mob.machine == src) hclient.client.mob.unset_machine()

/obj/machinery/proc/can_be_overridden()
	. = 1

/obj/machinery/tesla_act(var/power)
	..()
	if(prob(85))
		emp_act(2)
	else if(prob(50))
		ex_act(3)
	else if(prob(90))
		ex_act(2)
	else
		ex_act(1)

license: mit


code:
// Magnetic attractor, creates variable magnetic fields and attraction.
// Can also be used to emit electron/proton beams to create a center of magnetism on another tile

// tl;dr: it's magnets lol
// This was created for firing ranges, but I suppose this could have other applications - Doohl

/obj/machinery/magnetic_module

	icon = 'icons/obj/objects.dmi'
	icon_state = "floor_magnet-f"
	name = "electromagnetic generator"
	desc = "A device that uses station power to create points of magnetic energy."
	level = 1		// underfloor
	layer = 2.5
	anchored = 1
	use_power = 1
	idle_power_usage = 50

	var/freq = 1449		// radio frequency
	var/electricity_level = 1 // intensity of the magnetic pull
	var/magnetic_field = 1 // the range of magnetic attraction
	var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something
	var/turf/center // the center of magnetic attraction
	var/on = 0
	var/pulling = 0

	// x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down
	var/center_x = 0
	var/center_y = 0
	var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer

/obj/machinery/magnetic_module/New()
	..()
	var/turf/T = loc
	hide(T.intact)
	center = T

	spawn(10)	// must wait for map loading to finish
		if(SSradio)
			SSradio.add_object(src, freq, RADIO_MAGNETS)

	spawn()
		magnetic_process()

/obj/machinery/magnetic_module/Destroy()
	if(SSradio)
		SSradio.remove_object(src, freq)
	. = ..()
	center = null

// update the invisibility and icon
/obj/machinery/magnetic_module/hide(intact)
	invisibility = intact ? 101 : 0
	updateicon()

// update the icon_state
/obj/machinery/magnetic_module/proc/updateicon()
	var/state="floor_magnet"
	var/onstate=""
	if(!on)
		onstate="0"

	if(invisibility)
		icon_state = "[state][onstate]-f"	// if invisible, set icon to faded version
											// in case of being revealed by T-scanner
	else
		icon_state = "[state][onstate]"

/obj/machinery/magnetic_module/receive_signal(datum/signal/signal)

	var/command = signal.data["command"]
	var/modifier = signal.data["modifier"]
	var/signal_code = signal.data["code"]
	if(command && (signal_code == code))

		Cmd(command, modifier)

/obj/machinery/magnetic_module/proc/Cmd(command, modifier)

	if(command)
		switch(command)
			if("set-electriclevel")
				if(modifier)
					electricity_level = modifier
			if("set-magneticfield")
				if(modifier)
					magnetic_field = modifier

			if("add-elec")
				electricity_level++
				if(electricity_level > 12)
					electricity_level = 12
			if("sub-elec")
				electricity_level--
				if(electricity_level <= 0)
					electricity_level = 1
			if("add-mag")
				magnetic_field++
				if(magnetic_field > 4)
					magnetic_field = 4
			if("sub-mag")
				magnetic_field--
				if(magnetic_field <= 0)
					magnetic_field = 1

			if("set-x")
				if(modifier)
					center_x = modifier
			if("set-y")
				if(modifier)
					center_y = modifier

			if("N") // NORTH
				center_y++
			if("S")	// SOUTH
				center_y--
			if("E") // EAST
				center_x++
			if("W") // WEST
				center_x--
			if("C") // CENTER
				center_x = 0
				center_y = 0
			if("R") // RANDOM
				center_x = rand(-max_dist, max_dist)
				center_y = rand(-max_dist, max_dist)

			if("set-code")
				if(modifier)
					code = modifier
			if("toggle-power")
				on = !on

				if(on)
					spawn()
						magnetic_process()

/obj/machinery/magnetic_module/process()
	if(stat & NOPOWER)
		on = 0

	// Sanity checks:
	if(electricity_level <= 0)
		electricity_level = 1
	if(magnetic_field <= 0)
		magnetic_field = 1

	// Limitations:
	if(abs(center_x) > max_dist)
		center_x = max_dist
	if(abs(center_y) > max_dist)
		center_y = max_dist
	if(magnetic_field > 4)
		magnetic_field = 4
	if(electricity_level > 12)
		electricity_level = 12

	// Update power usage:
	if(on)
		use_power = 2
		active_power_usage = electricity_level*15
	else
		use_power = 0

		// Overload conditions:
		/* // Eeeehhh kinda stupid
		if(on)
			if(electricity_level > 11)
				if(prob(electricity_level))
					explosion(loc, 0, 1, 2, 3) // ooo dat shit EXPLODES son
					spawn(2)
						qdel(src)
		*/

	updateicon()

/obj/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling
	if(pulling) return
	while(on)

		pulling = 1
		center = locate(x+center_x, y+center_y, z)
		if(center)
			for(var/obj/M in orange(magnetic_field, center))
				if(!M.anchored && (M.flags & CONDUCT))
					step_towards(M, center)

			for(var/mob/living/silicon/S in orange(magnetic_field, center))
				if(istype(S, /mob/living/silicon/ai)) continue
				step_towards(S, center)

		use_power(electricity_level * 5)
		sleep(13 - electricity_level)

	pulling = 0

/obj/machinery/magnetic_controller
	name = "magnetic control console"
	icon = 'icons/obj/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING!
	icon_state = "airlock_control_standby"
	density = 0
	anchored = 1
	use_power = 1
	idle_power_usage = 45
	var/frequency = 1449
	var/code = 0
	var/list/magnets = list()
	var/title = "Magnetic Control Console"
	var/autolink = 0 // if set to 1, can't probe for other magnets!

	var/pathpos = 1 // position in the path
	var/path = "w;e;e;w;s;n;n;s" // text path of the magnet
	var/speed = 1 // lowest = 1, highest = 10
	var/list/rpath = list() // real path of the magnet, used in iterator

	var/moving = 0 // 1 if scheduled to loop
	var/looping = 0 // 1 if looping

	var/datum/radio_frequency/radio_connection

/obj/machinery/magnetic_controller/New()
	..()

	if(autolink)
		for(var/obj/machinery/magnetic_module/M in machines)
			if(M.freq == frequency && M.code == code)
				magnets.Add(M)

	spawn(45)	// must wait for map loading to finish
		if(SSradio)
			radio_connection = SSradio.add_object(src, frequency, RADIO_MAGNETS)

	if(path) // check for default path
		filter_path() // renders rpath

/obj/machinery/magnetic_controller/Destroy()
	if(SSradio)
		SSradio.remove_object(src, frequency)
	. = ..()
	magnets = null
	rpath = null

/obj/machinery/magnetic_controller/process()
	if(magnets.len == 0 && autolink)
		for(var/obj/machinery/magnetic_module/M in machines)
			if(M.freq == frequency && M.code == code)
				magnets.Add(M)

/obj/machinery/magnetic_controller/attack_ai(mob/user)
	return src.attack_hand(user)

/obj/machinery/magnetic_controller/attack_hand(mob/user)
	if(stat & (BROKEN|NOPOWER))
		return
	user.set_machine(src)
	var/dat = "Magnetic Control Console

"
	if(!autolink)
		dat += {"
		Frequency: [frequency]

		Code: [code]

		Probe Generators

		"}

	if(magnets.len >= 1)

		dat += "Magnets confirmed:
"
		var/i = 0
		for(var/obj/machinery/magnetic_module/M in magnets)
			i++
			dat += "     < \[[i]\] ([M.on ? "On":"Off"]) | Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] +
"

	dat += "
Speed: - [speed] +
"
	dat += "Path: {[path]}
"
	dat += "Moving: [moving ? "Enabled":"Disabled"]"

	user << browse(dat, "window=magnet;size=400x500")
	onclose(user, "magnet")

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

	if(href_list["radio-op"])

		// Prepare signal beforehand, because this is a radio operation
		var/datum/signal/signal = new
		signal.transmission_method = 1 // radio transmission
		signal.source = src
		signal.frequency = frequency
		signal.data["code"] = code

		// Apply any necessary commands
		switch(href_list["radio-op"])
			if("togglepower")
				signal.data["command"] = "toggle-power"

			if("minuselec")
				signal.data["command"] = "sub-elec"
			if("pluselec")
				signal.data["command"] = "add-elec"

			if("minusmag")
				signal.data["command"] = "sub-mag"
			if("plusmag")
				signal.data["command"] = "add-mag"

		// Broadcast the signal

		radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)

		spawn(1)
			updateUsrDialog() // pretty sure this increases responsiveness

	if(href_list["operation"])
		switch(href_list["operation"])
			if("plusspeed")
				speed ++
				if(speed > 10)
					speed = 10
			if("minusspeed")
				speed --
				if(speed <= 0)
					speed = 1
			if("setpath")
				var/newpath = copytext(sanitize(input(usr, "Please define a new path!",,path) as text|null),1,MAX_MESSAGE_LEN)
				if(newpath && newpath != "")
					moving = 0 // stop moving
					path = newpath
					pathpos = 1 // reset position
					filter_path() // renders rpath

			if("togglemoving")
				moving = !moving
				if(moving)
					spawn() MagnetMove()

	updateUsrDialog()

/obj/machinery/magnetic_controller/proc/MagnetMove()
	if(looping) return

	while(moving && rpath.len >= 1)

		if(stat & (BROKEN|NOPOWER))
			break

		looping = 1

		// Prepare the radio signal
		var/datum/signal/signal = new
		signal.transmission_method = 1 // radio transmission
		signal.source = src
		signal.frequency = frequency
		signal.data["code"] = code

		if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list!
			pathpos = 1

		var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive

		if(!(nextmove in list("N","S","E","W","C","R")))
			// N, S, E, W are directional
			// C is center
			// R is random (in magnetic field's bounds)
			qdel(signal)
			break // break the loop if the character located is invalid

		signal.data["command"] = nextmove

		pathpos++ // increase iterator

		// Broadcast the signal
		spawn()
			radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)

		if(speed == 10)
			sleep(1)
		else
			sleep(12-speed)

	looping = 0

/obj/machinery/magnetic_controller/proc/filter_path()
	// Generates the rpath variable using the path string, think of this as "string2list"
	// Doesn't use params2list() because of the akward way it stacks entities
	rpath = list() //  clear rpath
	var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length

	for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path

		var/nextchar = copytext(path, i, i+1) // find next character

		if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore
			rpath += copytext(path, i, i+1) // else, add to list

		// there doesn't HAVE to be separators but it makes paths syntatically visible


code:
/obj/machinery/mass_driver
	name = "mass driver"
	desc = "The finest in spring-loaded piston toy technology, now on a space station near you."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "mass_driver"
	anchored = 1
	use_power = 1
	idle_power_usage = 2
	active_power_usage = 50
	var/power = 1
	var/code = 1
	var/id = 1
	var/drive_range = 50	//this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.

/obj/machinery/mass_driver/proc/drive(amount)
	if(stat & (BROKEN|NOPOWER))
		return
	use_power(500)
	var/O_limit
	var/atom/target = get_edge_target_turf(src, dir)
	for(var/atom/movable/O in loc)
		if(!O.anchored || istype(O, /obj/mecha))	//Mechs need their launch platforms.
			O_limit++
			if(O_limit >= 20)
				audible_message("[src] lets out a screech, it doesn't seem to be able to handle the load.")
				break
			use_power(500)
			O.throw_at_fast(target, drive_range * power, power)
	flick("mass_driver1", src)

/obj/machinery/mass_driver/emp_act(severity)
	if(stat & (BROKEN|NOPOWER))
		return
	drive()
	..(severity)


code:
// Navigation beacon for AI robots
// No longer exists on the radio controller, it is managed by a global list.

/obj/machinery/navbeacon

	icon = 'icons/obj/objects.dmi'
	icon_state = "navbeacon0-f"
	name = "navigation beacon"
	desc = "A radio beacon used for bot navigation."
	level = 1		// underfloor
	layer = 2.5
	anchored = 1

	var/open = 0		// true if cover is open
	var/locked = 1		// true if controls are locked
	var/freq = 1445		// radio frequency
	var/location = ""	// location response text
	var/list/codes		// assoc. list of transponder codes
	var/codes_txt = ""	// codes as set on map: "tag1;tag2" or "tag1=value;tag2=value"

	req_access = list(access_engine, access_robotics)

/obj/machinery/navbeacon/New()
	..()

	set_codes()

	var/turf/T = loc
	hide(T.intact)
	if(codes["patrol"])
		if(!navbeacons["[z]"])
			navbeacons["[z]"] = list()
		navbeacons["[z]"] += src //Register with the patrol list!
	if(codes["delivery"])
		deliverybeacons += src
		deliverybeacontags += location

/obj/machinery/navbeacon/Destroy()
	navbeacons["[z]"] -= src //Remove from beacon list, if in one.
	deliverybeacons -= src
	return ..()

// set the transponder codes assoc list from codes_txt
/obj/machinery/navbeacon/proc/set_codes()
	if(!codes_txt)
		return

	codes = new()

	var/list/entries = splittext(codes_txt, ";")	// entries are separated by semicolons

	for(var/e in entries)
		var/index = findtext(e, "=")		// format is "key=value"
		if(index)
			var/key = copytext(e, 1, index)
			var/val = copytext(e, index+1)
			codes[key] = val
		else
			codes[e] = "1"

// called when turf state changes
// hide the object if turf is intact
/obj/machinery/navbeacon/hide(intact)
	invisibility = intact ? 101 : 0
	updateicon()

// update the icon_state
/obj/machinery/navbeacon/proc/updateicon()
	var/state="navbeacon[open]"

	if(invisibility)
		icon_state = "[state]-f"	// if invisible, set icon to faded version
									// in case revealed by T-scanner
	else
		icon_state = "[state]"

/obj/machinery/navbeacon/attackby(obj/item/I, mob/user, params)
	var/turf/T = loc
	if(T.intact)
		return		// prevent intraction when T-scanner revealed

	if(istype(I, /obj/item/weapon/screwdriver))
		open = !open

		user.visible_message("[user] [open ? "opens" : "closes"] the beacon's cover.", "You [open ? "open" : "close"] the beacon's cover.")

		updateicon()

	else if (istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
		if(open)
			if (src.allowed(user))
				src.locked = !src.locked
				user << "Controls are now [src.locked ? "locked" : "unlocked"]."
			else
				user << "Access denied."
			updateDialog()
		else
			user << "You must open the cover first!"
	return

/obj/machinery/navbeacon/attack_ai(mob/user)
	interact(user, 1)

/obj/machinery/navbeacon/attack_paw()
	return

/obj/machinery/navbeacon/attack_hand(mob/user)
	interact(user, 0)

/obj/machinery/navbeacon/interact(mob/user, ai = 0)
	var/turf/T = loc
	if(T.intact)
		return		// prevent intraction when T-scanner revealed

	if(!open && !ai)	// can't alter controls if not open, unless you're an AI
		user << "The beacon's control cover is closed!"
		return

	var/t

	if(locked && !ai)
		t = {"<TT>Navigation Beacon

(swipe card to unlock controls)

Location: [location ? location : "(none)"]

Transponder Codes:
"}

		for(var/key in codes)
			t += "
[key] ... [codes[key]]"
		t+= "
</TT>"

	else

		t = {"<TT>Navigation Beacon

(swipe card to lock controls)

Location: [location ? location : "None"]

Transponder Codes:
"}

		for(var/key in codes)
			t += "
[key] ... [codes[key]]"
			t += "	Edit"
			t += "	Delete
"
		t += "	Add New
"
		t+= "
</TT>"

	var/datum/browser/popup = new(user, "navbeacon", "Navigation Beacon", 300, 400)
	popup.set_content(t)
	popup.open()
	return

/obj/machinery/navbeacon/Topic(href, href_list)
	if(..())
		return
	if(open && !locked)
		usr.set_machine(src)

		if(href_list["locedit"])
			var/newloc = copytext(sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null),1,MAX_MESSAGE_LEN)
			if(newloc)
				location = newloc
				updateDialog()

		else if(href_list["edit"])
			var/codekey = href_list["code"]

			var/newkey = stripped_input(usr, "Enter Transponder Code Key", "Navigation Beacon", codekey)
			if(!newkey)
				return

			var/codeval = codes[codekey]
			var/newval = stripped_input(usr, "Enter Transponder Code Value", "Navigation Beacon", codeval)
			if(!newval)
				newval = codekey
				return

			codes.Remove(codekey)
			codes[newkey] = newval

			updateDialog()

		else if(href_list["delete"])
			var/codekey = href_list["code"]
			codes.Remove(codekey)
			updateDialog()

		else if(href_list["add"])

			var/newkey = stripped_input(usr, "Enter New Transponder Code Key", "Navigation Beacon")
			if(!newkey)
				return

			var/newval = stripped_input(usr, "Enter New Transponder Code Value", "Navigation Beacon")
			if(!newval)
				newval = "1"
				return

			if(!codes)
				codes = new()

			codes[newkey] = newval

			updateDialog()


code:
var/datum/newscaster/feed_network/news_network = new /datum/newscaster/feed_network
var/list/obj/machinery/newscaster/allCasters = list()

/datum/newscaster

/datum/newscaster/feed_comment
	var/author = ""
	var/body = ""
	var/time_stamp = ""

/datum/newscaster/feed_message
	var/author =""
	var/body =""
	var/list/authorCensorTime = list()
	var/list/bodyCensorTime = list()
	var/is_admin_message = 0
	var/icon/img = null
	var/time_stamp = ""
	var/list/datum/newscaster/feed_comment/comments = list()
	var/locked = 0
	var/caption = ""
	var/creationTime
	var/authorCensor
	var/bodyCensor

/datum/newscaster/feed_message/proc/returnAuthor(censor)
	if(censor == -1)
		censor = authorCensor
	var/txt = "[news_network.redactedText]"
	if(!censor)
		txt = author
	return txt

/datum/newscaster/feed_message/proc/returnBody(censor)
	if(censor == -1)
		censor = bodyCensor
	var/txt = "[news_network.redactedText]"
	if(!censor)
		txt = body
	return txt

/datum/newscaster/feed_message/proc/toggleCensorAuthor()
	if(authorCensor)
		authorCensorTime.Add(news_network.lastAction*-1)
	else
		authorCensorTime.Add(news_network.lastAction)
	authorCensor = !authorCensor
	news_network.lastAction ++

/datum/newscaster/feed_message/proc/toggleCensorBody()
	if(bodyCensor)
		bodyCensorTime.Add(news_network.lastAction*-1)
	else
		bodyCensorTime.Add(news_network.lastAction)
	bodyCensor = !bodyCensor
	news_network.lastAction ++

/datum/newscaster/feed_channel
	var/channel_name = ""
	var/list/datum/newscaster/feed_message/messages = list()
	var/locked = 0
	var/author = ""
	var/censored = 0
	var/list/authorCensorTime = list()
	var/list/DclassCensorTime = list()
	var/authorCensor
	var/is_admin_channel = 0

/datum/newscaster/feed_channel/proc/returnAuthor(censor)
	if(censor == -1)
		censor = authorCensor
	var/txt = "[news_network.redactedText]"
	if(!censor)
		txt = author
	return txt

/datum/newscaster/feed_channel/proc/toggleCensorDclass()
	if(censored)
		DclassCensorTime.Add(news_network.lastAction*-1)
	else
		DclassCensorTime.Add(news_network.lastAction)
	censored = !censored
	news_network.lastAction ++

/datum/newscaster/feed_channel/proc/toggleCensorAuthor()
	if(authorCensor)
		authorCensorTime.Add(news_network.lastAction*-1)
	else
		authorCensorTime.Add(news_network.lastAction)
	authorCensor = !authorCensor
	news_network.lastAction ++

/datum/newscaster/wanted_message
	var/active
	var/criminal
	var/body
	var/scannedUser
	var/isAdminMsg
	var/icon/img

/datum/newscaster/feed_network
	var/list/datum/newscaster/feed_channel/network_channels = list()
	var/datum/newscaster/wanted_message/wanted_issue
	var/lastAction
	var/redactedText = "\[REDACTED\]"

/datum/newscaster/feed_network/New()
	CreateFeedChannel("Station Announcements", "SS13", 1)
	wanted_issue = new /datum/newscaster/wanted_message

/datum/newscaster/feed_network/proc/CreateFeedChannel(channel_name, author, locked, adminChannel = 0)
	var/datum/newscaster/feed_channel/newChannel = new /datum/newscaster/feed_channel
	newChannel.channel_name = channel_name
	newChannel.author = author
	newChannel.locked = locked
	newChannel.is_admin_channel = adminChannel
	network_channels += newChannel

/datum/newscaster/feed_network/proc/SubmitArticle(msg, author, channel_name, obj/item/weapon/photo/photo, adminMessage = 0, allow_comments = 1)
	var/datum/newscaster/feed_message/newMsg = new /datum/newscaster/feed_message
	newMsg.author = author
	newMsg.body = msg
	newMsg.time_stamp = "[worldtime2text()]"
	newMsg.is_admin_message = adminMessage
	newMsg.locked = !allow_comments
	if(photo)
		newMsg.img = photo.img
		newMsg.caption = photo.scribble
	for(var/datum/newscaster/feed_channel/FC in network_channels)
		if(FC.channel_name == channel_name)
			FC.messages += newMsg
			break
	for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
		NEWSCASTER.newsAlert(channel_name)
	lastAction ++
	newMsg.creationTime = lastAction

/datum/newscaster/feed_network/proc/submitWanted(criminal, body, scanned_user, obj/item/weapon/photo/photo, adminMsg = 0, newMessage = 0)
	wanted_issue.active = 1
	wanted_issue.criminal = criminal
	wanted_issue.body = body
	wanted_issue.scannedUser = scanned_user
	wanted_issue.isAdminMsg = adminMsg
	if(photo)
		wanted_issue.img = photo.img
	if(newMessage)
		for(var/obj/machinery/newscaster/N in allCasters)
			N.newsAlert()
			N.update_icon()

/datum/newscaster/feed_network/proc/deleteWanted()
	wanted_issue.active = 0
	wanted_issue.criminal = null
	wanted_issue.body = null
	wanted_issue.scannedUser = null
	wanted_issue.img = null
	for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
		NEWSCASTER.update_icon()

/obj/item/wallframe/newscaster
	name = "newscaster frame"
	desc = "Used to build newscasters, just secure to the wall."
	icon_state = "newscaster"
	materials = list(MAT_METAL=14000, MAT_GLASS=8000)
	result_path = /obj/machinery/newscaster

/obj/machinery/newscaster
	name = "newscaster"
	desc = "A standard Nanotrasen-licensed newsfeed handler for use in commercial space stations. All the news you absolutely have no use for, in one place!"
	icon = 'icons/obj/terminals.dmi'
	icon_state = "newscaster_normal"
	verb_say = "beeps"
	verb_ask = "beeps"
	verb_exclaim = "beeps"
	var/isbroken = 0
	var/ispowered = 1
	var/screen = 0
	var/paper_remaining = 15
	var/securityCaster = 0
	var/unit_no = 0
	var/alert_delay = 500
	var/alert = 0
	var/scanned_user = "Unknown"
	var/msg = ""
	var/obj/item/weapon/photo/photo = null
	var/channel_name = ""
	var/c_locked=0
	var/hitstaken = 0
	var/datum/newscaster/feed_channel/viewing_channel = null
	var/allow_comments = 1
	luminosity = 0
	anchored = 1

/obj/machinery/newscaster/security_unit
	name = "security newscaster"
	securityCaster = 1

/obj/machinery/newscaster/New(loc, ndir, building)
	..()
	if(building)
		dir = ndir
		pixel_x = (dir & 3)? 0 : (dir == 4 ? -32 : 32)
		pixel_y = (dir & 3)? (dir ==1 ? -32 : 32) : 0

	allCasters += src
	for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
		unit_no++
	update_icon()

/obj/machinery/newscaster/Destroy()
	allCasters -= src
	viewing_channel = null
	photo = null
	return ..()

/obj/machinery/newscaster/update_icon()
	if(!ispowered || isbroken)
		icon_state = "newscaster_off"
		if(isbroken)
			overlays.Cut()
			overlays += image(icon, "crack3")
		return
	overlays.Cut()
	if(news_network.wanted_issue.active)
		icon_state = "newscaster_wanted"
		return
	if(alert)
		overlays += "newscaster_alert"
	if(hitstaken > 0)
		overlays += image(icon, "crack[hitstaken]")
	icon_state = "newscaster_normal"

/obj/machinery/newscaster/power_change()
	if(isbroken)
		return
	if(powered())
		ispowered = 1
		stat &= ~NOPOWER
		update_icon()
	else
		spawn(rand(0, 15))
			ispowered = 0
			stat |= NOPOWER
			update_icon()

/obj/machinery/newscaster/ex_act(severity, target)
	switch(severity)
		if(1)
			qdel(src)
		if(2)
			isbroken=1
			if(prob(50))
				qdel(src)
			else
				update_icon()
		else
			if(prob(50))
				isbroken=1
			update_icon()

/obj/machinery/newscaster/attack_ai(mob/user)
	return attack_hand(user)

/obj/machinery/newscaster/attack_hand(mob/user)
	if(!ispowered || isbroken)
		return
	if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon) )
		var/mob/living/human_or_robot_user = user
		var/dat
		scan_user(human_or_robot_user)
		switch(screen)
			if(0)
				dat += "Welcome to Newscasting Unit #[unit_no].
 Interface & News networks Operational."
				dat += "
Property of Nanotransen Inc"
				if(news_network.wanted_issue.active)
					dat+= "
Read Wanted Issue"
				dat+= "

Create Feed Channel"
				dat+= "
View Feed Channels"
				dat+= "
Submit new Feed story"
				dat+= "
Print newspaper"
				dat+= "
Re-scan User"
				dat+= "

Exit"
				if(securityCaster)
					var/wanted_already = 0
					if(news_network.wanted_issue.active)
						wanted_already = 1
					dat+="
Feed Security functions:
"
					dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue"
					dat+="
Censor Feed Stories"
					dat+="
Mark Feed Channel with Nanotrasen D-Notice"
				dat+="

The newscaster recognises you as: [scanned_user]"
			if(1)
				dat+= "Station Feed Channels
"
				if( isemptylist(news_network.network_channels) )
					dat+="No active channels found..."
				else
					for(var/datum/newscaster/feed_channel/CHANNEL in news_network.network_channels)
						if(CHANNEL.is_admin_channel)
							dat+="[CHANNEL.channel_name]
"
						else
							dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
				dat+="

Refresh"
				dat+="
Back"
			if(2)
				dat+="Creating new Feed Channel..."
				dat+="
Channel Name: [channel_name]
"
				dat+="Channel Author: [scanned_user]
"
				dat+="Will Accept Public Feeds: [(c_locked) ? ("NO") : ("YES")]

"
				dat+="
Submit

Cancel
"
			if(3)
				dat+="Creating new Feed Message..."
				dat+="
Receiving Channel: [channel_name]
"
				dat+="Message Author: [scanned_user]
"
				dat+="Message Body:
[parsepencode(msg, user, SIGNFONT)]
"
				dat+="Attach Photo:  [(photo ? "Photo Attached" : "No Photo")]
"
				dat+="Comments [allow_comments ? "Enabled" : "Disabled"]
"
				dat+="
Submit

Cancel
"
			if(4)
				dat+="Feed story successfully submitted to [channel_name].

"
				dat+="
Return
"
			if(5)
				dat+="Feed Channel [channel_name] created successfully.

"
				dat+="
Return
"
			if(6)
				dat+="ERROR: Could not submit Feed story to Network.

"
				if(channel_name=="")
					dat+="�Invalid receiving channel name.
"
				if(scanned_user=="Unknown")
					dat+="�Channel author unverified.
"
				if(msg == "" || msg == "\[REDACTED\]")
					dat+="�Invalid message body.
"
				dat+="
Return
"
			if(7)
				dat+="ERROR: Could not submit Feed Channel to Network.

"
				var/list/existing_authors = list()
				for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
					if(FC.authorCensor)
						existing_authors += news_network.redactedText
					else
						existing_authors += FC.author
				if(scanned_user in existing_authors)
					dat+="�There already exists a Feed channel under your name.
"
				if(channel_name=="" || channel_name == "\[REDACTED\]")
					dat+="�Invalid channel name.
"
				var/check = 0
				for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
					if(FC.channel_name == channel_name)
						check = 1
						break
				if(check)
					dat+="�Channel name already in use.
"
				if(scanned_user=="Unknown")
					dat+="�Channel author unverified.
"
				dat+="
Return
"
			if(8)
				var/total_num=length(news_network.network_channels)
				var/active_num=total_num
				var/message_num=0
				for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
					if(!FC.censored)
						message_num += length(FC.messages)
					else
						active_num--
				dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories."
				dat+="

Liquid Paper remaining: [(paper_remaining) *100 ] cm^3"
				dat+="

Print Paper"
				dat+="
Cancel"
			if(9)
				dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.returnAuthor(-1)]\]
"
				if(viewing_channel.censored)
					dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
"
					dat+="No further feed story additions are allowed while the D-Notice is in effect.

"
				else
					if( isemptylist(viewing_channel.messages) )
						dat+="No feed messages found in channel...
"
					else
						var/i = 0
						for(var/datum/newscaster/feed_message/MESSAGE in viewing_channel.messages)
							i++
							dat+="-[MESSAGE.returnBody(-1)]
"
							if(MESSAGE.img)
								usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
								dat+="
"
								if(MESSAGE.caption)
									dat+="[MESSAGE.caption]
"
								dat+="
"
							dat+="\[Story by [MESSAGE.returnAuthor(-1)] \] - ([MESSAGE.time_stamp])
"
							dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]
"
							for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
								dat+="[comment.body]
[comment.author] [comment.time_stamp]
"
							if(MESSAGE.locked)
								dat+="Comments locked
"
							else
								dat+="Comment
"
				dat+="

Refresh"
				dat+="
Back"
			if(10)
				dat+="Nanotrasen Feed Censorship Tool
"
				dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
"
				dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it."
				dat+="
Select Feed channel to get Stories from:
"
				if(isemptylist(news_network.network_channels))
					dat+="No feed channels found active...
"
				else
					for(var/datum/newscaster/feed_channel/CHANNEL in news_network.network_channels)
						dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
				dat+="
Cancel"
			if(11)
				dat+="Nanotrasen D-Notice Handler
"
				dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
				dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
				dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
"
				if(isemptylist(news_network.network_channels))
					dat+="No feed channels found active...
"
				else
					for(var/datum/newscaster/feed_channel/CHANNEL in news_network.network_channels)
						dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
"
				dat+="
Back"
			if(12)
				dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.returnAuthor(-1)] \]
"
				dat+="[(viewing_channel.authorCensor) ? ("Undo Author censorship") : ("Censor channel Author")]
"
				if(isemptylist(viewing_channel.messages))
					dat+="No feed messages found in channel...
"
				else
					for(var/datum/newscaster/feed_message/MESSAGE in viewing_channel.messages)
						dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
"
						dat+="[(MESSAGE.bodyCensor) ? ("Undo story censorship") : ("Censor story")]  -  [(MESSAGE.authorCensor) ? ("Undo Author Censorship") : ("Censor message Author")]
"
						dat+="[MESSAGE.comments.len] comment[MESSAGE.comments.len > 1 ? "s" : ""]: [MESSAGE.locked ? "Unlock" : "Lock"]
"
						for(var/datum/newscaster/feed_comment/comment in MESSAGE.comments)
							dat+="[comment.body] X
[comment.author] [comment.time_stamp]
"
				dat+="
Back"
			if(13)
				dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.returnAuthor(-1)] \]
"
				dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
"
				if(viewing_channel.censored)
					dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
"
					dat+="No further feed story additions are allowed while the D-Notice is in effect.

"
				else
					if(isemptylist(viewing_channel.messages))
						dat+="No feed messages found in channel...
"
					else
						for(var/datum/newscaster/feed_message/MESSAGE in viewing_channel.messages)
							dat+="-[MESSAGE.returnBody(-1)]
\[Story by [MESSAGE.returnAuthor(-1)]\]
"
				dat+="
Back"
			if(14)
				dat+="Wanted Issue Handler:"
				var/wanted_already = 0
				var/end_param = 1
				if(news_network.wanted_issue.active)
					wanted_already = 1
					end_param = 2
				if(wanted_already)
					dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below."
				dat+="
"
				dat+="Criminal Name: [channel_name]
"
				dat+="Description: [msg]
"
				dat+="Attach Photo: [(photo ? "Photo Attached" : "No Photo")]
"
				if(wanted_already)
					dat+="Wanted Issue created by:[news_network.wanted_issue.scannedUser]
"
				else
					dat+="Wanted Issue will be created under prosecutor:[scanned_user]
"
				dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]"
				if(wanted_already)
					dat+="
Take down Issue"
				dat+="
Cancel"
			if(15)
				dat+="Wanted issue for [channel_name] is now in Network Circulation.

"
				dat+="
Return
"
			if(16)
				dat+="ERROR: Wanted Issue rejected by Network.

"
				if(channel_name=="" || channel_name == "\[REDACTED\]")
					dat+="�Invalid name for person wanted.
"
				if(scanned_user=="Unknown")
					dat+="�Issue author unverified.
"
				if(msg == "" || msg == "\[REDACTED\]")
					dat+="�Invalid description.
"
				dat+="
Return
"
			if(17)
				dat+="Wanted Issue successfully deleted from Circulation
"
				dat+="
Return
"
			if(18)
				if(news_network.wanted_issue.active)
					dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [news_network.wanted_issue.scannedUser]\]
"
					dat+="Criminal: [news_network.wanted_issue.criminal]
"
					dat+="Description: [news_network.wanted_issue.body]
"
					dat+="Photo:: "
					if(news_network.wanted_issue.img)
						usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png")
						dat+="
"
					else
						dat+="None"
				else
					dat+="No current wanted issue found.

"
				dat+="

Back
"
			if(19)
				dat+="Wanted issue for [channel_name] successfully edited.

"
				dat+="
Return
"
			if(20)
				dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

"
				dat+="Return"
			if(21)
				dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

"
				dat+="Return"
		var/datum/browser/popup = new(human_or_robot_user, "newscaster_main", "Newscaster Unit #[unit_no]", 400, 600)
		popup.set_content(dat)
		popup.set_title_image(human_or_robot_user.browse_rsc_icon(icon, icon_state))
		popup.open()

/obj/machinery/newscaster/Topic(href, href_list)
	if(..())
		return
	if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon)))
		usr.set_machine(src)
		scan_user(usr)
		if(href_list["set_channel_name"])
			channel_name = stripped_input(usr, "Provide a Feed Channel Name", "Network Channel Handler", "", MAX_NAME_LEN)
			while (findtext(channel_name," ") == 1)
				channel_name = copytext(channel_name,2,lentext(channel_name)+1)
			updateUsrDialog()
		else if(href_list["set_channel_lock"])
			c_locked = !c_locked
			updateUsrDialog()
		else if(href_list["submit_new_channel"])
			var/list/existing_authors = list()
			for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
				if(FC.authorCensor)
					existing_authors += news_network.redactedText
				else
					existing_authors += FC.author
			var/check = 0
			for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
				if(FC.channel_name == channel_name)
					check = 1
					break
			if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors) )
				screen=7
			else
				var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
				if(choice=="Confirm")
					scan_user(usr)
					news_network.CreateFeedChannel(channel_name, scanned_user, c_locked)
					feedback_inc("newscaster_channels",1)
					screen=5
			updateUsrDialog()
		else if(href_list["set_channel_receiving"])
			var/list/available_channels = list()
			for(var/datum/newscaster/feed_channel/F in news_network.network_channels)
				if( (!F.locked || F.author == scanned_user) && !F.censored)
					available_channels += F.channel_name
			channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels
			updateUsrDialog()
		else if(href_list["set_new_message"])
			var/temp_message = trim(stripped_multiline_input(usr, "Write your Feed story", "Network Channel Handler", msg))
			if(temp_message)
				msg = temp_message
				updateUsrDialog()
		else if(href_list["set_attachment"])
			AttachPhoto(usr)
			updateUsrDialog()
		else if(href_list["submit_new_message"])
			if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "" )
				screen=6
			else
				news_network.SubmitArticle("[parsepencode(msg, usr, SIGNFONT)]", scanned_user, channel_name, photo, 0, allow_comments)
				feedback_inc("newscaster_stories",1)
				screen=4
				msg = ""
			updateUsrDialog()
		else if(href_list["create_channel"])
			screen=2
			updateUsrDialog()
		else if(href_list["create_feed_story"])
			screen=3
			updateUsrDialog()
		else if(href_list["menu_paper"])
			screen=8
			updateUsrDialog()
		else if(href_list["print_paper"])
			if(!paper_remaining)
				screen=21
			else
				print_paper()
				screen = 20
			updateUsrDialog()
		else if(href_list["menu_censor_story"])
			screen=10
			updateUsrDialog()
		else if(href_list["menu_censor_channel"])
			screen=11
			updateUsrDialog()
		else if(href_list["menu_wanted"])
			var/already_wanted = 0
			if(news_network.wanted_issue.active)
				already_wanted = 1
			if(already_wanted)
				channel_name = news_network.wanted_issue.criminal
				msg = news_network.wanted_issue.body
			screen = 14
			updateUsrDialog()
		else if(href_list["set_wanted_name"])
			channel_name = trim(stripped_input(usr, "Provide the name of the Wanted person", "Network Security Handler"))
			updateUsrDialog()
		else if(href_list["set_wanted_desc"])
			msg = trim(stripped_input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler"))
			updateUsrDialog()
		else if(href_list["submit_wanted"])
			var/input_param = text2num(href_list["submit_wanted"])
			if(msg == "" || channel_name == "" || scanned_user == "Unknown")
				screen = 16
			else
				var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel")
				if(choice=="Confirm")
					scan_user(usr)
					if(input_param==1)          //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one.
						news_network.submitWanted(channel_name, msg, scanned_user, photo, 0 , 1)
						screen = 15
					else
						if(news_network.wanted_issue.isAdminMsg)
							alert("The wanted issue has been distributed by a Nanotrasen higherup. You cannot edit it.","Ok")
							return
						news_network.submitWanted(channel_name, msg, scanned_user, photo)
						screen = 19
			updateUsrDialog()
		else if(href_list["cancel_wanted"])
			if(news_network.wanted_issue.isAdminMsg)
				alert("The wanted issue has been distributed by a Nanotrasen higherup. You cannot take it down.","Ok")
				return
			var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel")
			if(choice=="Confirm")
				news_network.deleteWanted()
				screen=17
			updateUsrDialog()
		else if(href_list["view_wanted"])
			screen=18
			updateUsrDialog()
		else if(href_list["censor_channel_author"])
			var/datum/newscaster/feed_channel/FC = locate(href_list["censor_channel_author"])
			if(FC.is_admin_channel)
				alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
				return
			FC.toggleCensorAuthor()
			updateUsrDialog()
		else if(href_list["censor_channel_story_author"])
			var/datum/newscaster/feed_message/MSG = locate(href_list["censor_channel_story_author"])
			if(MSG.is_admin_message)
				alert("This message was created by a Nanotrasen Officer. You cannot censor its author.","Ok")
				return
			MSG.toggleCensorAuthor()
			updateUsrDialog()
		else if(href_list["censor_channel_story_body"])
			var/datum/newscaster/feed_message/MSG = locate(href_list["censor_channel_story_body"])
			if(MSG.is_admin_message)
				alert("This channel was created by a Nanotrasen Officer. You cannot censor it.","Ok")
				return
			MSG.toggleCensorBody()
			updateUsrDialog()
		else if(href_list["pick_d_notice"])
			var/datum/newscaster/feed_channel/FC = locate(href_list["pick_d_notice"])
			viewing_channel = FC
			screen=13
			updateUsrDialog()
		else if(href_list["toggle_d_notice"])
			var/datum/newscaster/feed_channel/FC = locate(href_list["toggle_d_notice"])
			if(FC.is_admin_channel)
				alert("This channel was created by a Nanotrasen Officer. You cannot place a D-Notice upon it.","Ok")
				return
			FC.toggleCensorDclass()
			updateUsrDialog()
		else if(href_list["view"])
			screen=1
			updateUsrDialog()
		else if(href_list["setScreen"])
			screen = text2num(href_list["setScreen"])
			if (screen == 0)
				scanned_user = "Unknown";
				msg = "";
				c_locked=0;
				channel_name="";
				viewing_channel = null
			updateUsrDialog()
		else if(href_list["show_channel"])
			var/datum/newscaster/feed_channel/FC = locate(href_list["show_channel"])
			viewing_channel = FC
			screen = 9
			updateUsrDialog()
		else if(href_list["pick_censor_channel"])
			var/datum/newscaster/feed_channel/FC = locate(href_list["pick_censor_channel"])
			viewing_channel = FC
			screen = 12
			updateUsrDialog()
		else if(href_list["new_comment"])
			var/datum/newscaster/feed_message/FM = locate(href_list["new_comment"])
			var/cominput = copytext(stripped_input(usr, "Write your message:", "New comment", null),1,141)
			if(cominput)
				scan_user(usr)
				var/datum/newscaster/feed_comment/FC = new/datum/newscaster/feed_comment
				FC.author = scanned_user
				FC.body = cominput
				FC.time_stamp = worldtime2text()
				FM.comments += FC
				log_comment("[usr]/([usr.ckey]) as [scanned_user] commented on message [FM.returnBody(-1)] -- [FC.body]")
			updateUsrDialog()
		else if(href_list["del_comment"])
			var/datum/newscaster/feed_comment/FC = locate(href_list["del_comment"])
			var/datum/newscaster/feed_message/FM = locate(href_list["del_comment_msg"])
			FM.comments -= FC
			qdel(FC)
			updateUsrDialog()
		else if(href_list["lock_comment"])
			var/datum/newscaster/feed_message/FM = locate(href_list["lock_comment"])
			FM.locked ^= 1
			updateUsrDialog()
		else if(href_list["set_comment"])
			allow_comments ^= 1
			updateUsrDialog()
		else if(href_list["refresh"])
			updateUsrDialog()

/obj/machinery/newscaster/attackby(obj/item/I, mob/living/user, params)
	if(istype(I, /obj/item/weapon/wrench))
		user << "You start [anchored ? "un" : ""]securing [name]..."
		playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
		if(do_after(user, 60/I.toolspeed, target = src))
			user << "You [anchored ? "un" : ""]secure [name]."
			new /obj/item/wallframe/newscaster(loc)
			playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
			qdel(src)
		return
	if(isbroken)
		playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 100, 1)
		audible_message("[user.name] further abuses the shattered [name].", null, 5 )
	else
		if(istype(I, /obj/item/weapon))
			user.do_attack_animation(src)
			var/obj/item/weapon/W = I
			if(W.damtype == STAMINA)
				return
			if(W.force <15)
				audible_message("[user.name] hits the [name] with the [W.name] with no visible effect.", null , 5 )
				playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
			else
				hitstaken++
				if(hitstaken==3)
					audible_message("[user.name] smashes the [name]!", null, 5 )
					isbroken=1
					playsound(loc, 'sound/effects/Glassbr3.ogg', 100, 1)
				else
					audible_message("[user.name] forcefully slams the [name] with the [I.name]!", null, 5 )
					playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
		else
			user << "This does nothing!"
	update_icon()

/obj/machinery/newscaster/attack_paw(mob/user)
	user << "The newscaster controls are far too complicated for your tiny brain!"
	return

/obj/machinery/newscaster/proc/AttachPhoto(mob/user)
	if(photo)
		if(!photo.sillynewscastervar)
			photo.loc = loc
			if(!issilicon(user))
				user.put_in_inactive_hand(photo)
		else
			qdel(photo)
		photo = null
	if(istype(user.get_active_hand(), /obj/item/weapon/photo))
		photo = user.get_active_hand()
		if(!user.drop_item())
			return
		photo.loc = src
	if(istype(user,/mob/living/silicon))
		var/list/nametemp = list()
		var/find
		var/datum/picture/selection
		var/obj/item/device/camera/siliconcam/targetcam = null
		if(istype(user,/mob/living/silicon/ai))
			var/mob/living/silicon/ai/R = user
			targetcam = R.aicamera
		else if(istype(user,/mob/living/silicon/robot))
			var/mob/living/silicon/robot/R = user
			if(R.connected_ai)
				targetcam = R.connected_ai.aicamera
			else
				targetcam = R.aicamera
		else
			user << "You cannot interface with silicon photo uploading!"
		if(targetcam.aipictures.len == 0)
			usr << "No images saved"
			return
		for(var/datum/picture/t in targetcam.aipictures)
			nametemp += t.fields["name"]
		find = input("Select image (numbered in order taken)") in nametemp
		var/obj/item/weapon/photo/P = new/obj/item/weapon/photo()
		for(var/datum/picture/q in targetcam.aipictures)
			if(q.fields["name"] == find)
				selection = q
				break
		P.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"])
		P.sillynewscastervar = 1
		photo = P
		qdel(P)

/obj/machinery/newscaster/proc/scan_user(mob/living/user)
	if(ishuman(user))
		var/mob/living/carbon/human/human_user = user
		if(human_user.wear_id)
			if(istype(human_user.wear_id, /obj/item/device/pda))
				var/obj/item/device/pda/P = human_user.wear_id
				if(P.id)
					scanned_user = "[P.id.registered_name] ([P.id.assignment])"
				else
					scanned_user = "Unknown"
			else if(istype(human_user.wear_id, /obj/item/weapon/card/id) )
				var/obj/item/weapon/card/id/ID = human_user.wear_id
				scanned_user ="[ID.registered_name] ([ID.assignment])"
			else
				scanned_user ="Unknown"
		else
			scanned_user ="Unknown"
	else if(istype(user,/mob/living/silicon))
		var/mob/living/silicon/ai_user = user
		scanned_user = "[ai_user.name] ([ai_user.job])"
	else
		throw EXCEPTION("Invalid user for this proc")
		return

/obj/machinery/newscaster/proc/print_paper()
	feedback_inc("newscaster_newspapers_printed",1)
	var/obj/item/weapon/newspaper/NEWSPAPER = new /obj/item/weapon/newspaper
	for(var/datum/newscaster/feed_channel/FC in news_network.network_channels)
		NEWSPAPER.news_content += FC
	if(news_network.wanted_issue.active)
		NEWSPAPER.wantedAuthor = news_network.wanted_issue.scannedUser
		NEWSPAPER.wantedCriminal = news_network.wanted_issue.criminal
		NEWSPAPER.wantedBody = news_network.wanted_issue.body
		if(news_network.wanted_issue.img)
			NEWSPAPER.wantedPhoto = news_network.wanted_issue.img
	NEWSPAPER.loc = get_turf(src)
	NEWSPAPER.creationTime = news_network.lastAction
	paper_remaining--

/obj/machinery/newscaster/proc/newsAlert(channel)
	if(channel)
		say("Breaking news from [channel]!")
		alert ++
		update_icon()
		spawn(alert_delay)
			alert --
			update_icon()
		playsound(loc, 'sound/machines/twobeep.ogg', 75, 1)
	else
		say("Attention! Wanted issue distributed!")
		playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, 1)

/obj/item/weapon/newspaper
	name = "newspaper"
	desc = "An issue of The Griffon, the newspaper circulating aboard Nanotrasen Space Stations."
	icon = 'icons/obj/bureaucracy.dmi'
	icon_state = "newspaper"
	w_class = 2
	attack_verb = list("bapped")
	var/screen = 0
	var/pages = 0
	var/curr_page = 0
	var/list/datum/newscaster/feed_channel/news_content = list()
	var/scribble=""
	var/scribble_page = null
	var/wantedAuthor
	var/wantedCriminal
	var/wantedBody
	var/wantedPhoto
	var/creationTime

/obj/item/weapon/newspaper/suicide_act(mob/user)
	user.visible_message("[user] is focusing intently on [src]! It looks like they're trying to commit sudoku... until their eyes light up with realization!")
	user.say(";JOURNALISM IS MY CALLING! EVERYBODY APPRECIATES UNBIASED REPORTI-GLORF")
	var/mob/living/carbon/human/H = user
	var/obj/W = new /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey(H.loc)
	playsound(H.loc, 'sound/items/drink.ogg', rand(10,50), 1)
	W.reagents.trans_to(H, W.reagents.total_volume)
	user.visible_message("[user] downs the contents of [W.name] in one gulp! Shoulda stuck to sudoku!")

	return(TOXLOSS)

/obj/item/weapon/newspaper/attack_self(mob/user)
	if(ishuman(user))
		var/mob/living/carbon/human/human_user = user
		var/dat
		pages = 0
		switch(screen)
			if(0) //Cover
				dat+="
The Griffon
"
				dat+="
Nanotrasen-standard newspaper, for use on Nanotrasen� Space Facilities

"
				if(isemptylist(news_content))
					if(wantedAuthor)
						dat+="Contents:

**Important Security Announcement** \[page [pages+2]\]

"
					else
						dat+="Other than the title, the rest of the newspaper is unprinted..."
				else
					dat+="Contents:

"
					for(var/datum/newscaster/feed_channel/NP in news_content)
						pages++
					if(wantedAuthor)
						dat+="**Important Security Announcement** \[page [pages+2]\]
"
					var/temp_page=0
					for(var/datum/newscaster/feed_channel/NP in news_content)
						temp_page++
						dat+="[NP.channel_name] \[page [temp_page+1]\]
"
					dat+="
"
				if(scribble_page==curr_page)
					dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
				dat+= "

Next Page

Done reading
"
			if(1) // X channel pages inbetween.
				for(var/datum/newscaster/feed_channel/NP in news_content)
					pages++
				var/datum/newscaster/feed_channel/C = news_content[curr_page]
				dat += "[C.channel_name] \[created by: [C.returnAuthor(notContent(C.authorCensorTime))]\]

"
				if(notContent(C.DclassCensorTime))
					dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing."
				else
					if(isemptylist(C.messages))
						dat+="No Feed stories stem from this channel..."
					else
						var/i = 0
						for(var/datum/newscaster/feed_message/MESSAGE in C.messages)
							if(MESSAGE.creationTime > creationTime)
								if(i == 0)
									dat+="No Feed stories stem from this channel..."
								break
							if(i == 0)
								dat+="
"
							i++
							dat+="-[MESSAGE.returnBody(notContent(MESSAGE.bodyCensorTime))]
"
							if(MESSAGE.img)
								user << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
								dat+="
"
							dat+="\[Story by [MESSAGE.returnAuthor(notContent(MESSAGE.authorCensorTime))]\]

"
						dat+="
"
				if(scribble_page==curr_page)
					dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
				dat+= "

Previous Page

Next Page
"
			if(2) //Last page
				for(var/datum/newscaster/feed_channel/NP in news_content)
					pages++
				if(wantedAuthor!=null)
					dat+="
Wanted Issue:

"
					dat+="Criminal name: [wantedCriminal]
"
					dat+="Description: [wantedBody]
"
					dat+="Photo:: "
					if(wantedPhoto)
						user << browse_rsc(wantedPhoto, "tmp_photow.png")
						dat+="
"
					else
						dat+="None"
				else
					dat+="Apart from some uninteresting Classified ads, there's nothing on this page..."
				if(scribble_page==curr_page)
					dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
				dat+= "

Previous Page
"
		dat+="

[curr_page+1]
"
		human_user << browse(dat, "window=newspaper_main;size=300x400")
		onclose(human_user, "newspaper_main")
	else
		user << "The paper is full of intelligible symbols!"

/obj/item/weapon/newspaper/proc/notContent(list/L)
	if(!L.len)
		return 0
	for(var/i=L.len;i>0;i--)
		var/num = abs(L[i])
		if(creationTime <= num)
			continue
		else
			if(L[i] > 0)
				return 1
			else
				return 0
	return 0

/obj/item/weapon/newspaper/Topic(href, href_list)
	var/mob/living/U = usr
	..()
	if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ))
		U.set_machine(src)
		if(href_list["next_page"])
			if(curr_page == pages+1)
				return //Don't need that at all, but anyway.
			if(curr_page == pages) //We're at the middle, get to the end
				screen = 2
			else
				if(curr_page == 0) //We're at the start, get to the middle
					screen=1
			curr_page++
			playsound(loc, "pageturn", 50, 1)
		else if(href_list["prev_page"])
			if(curr_page == 0)
				return
			if(curr_page == 1)
				screen = 0
			else
				if(curr_page == pages+1) //we're at the end, let's go back to the middle.
					screen = 1
			curr_page--
			playsound(loc, "pageturn", 50, 1)
		if(ismob(loc))
			attack_self(loc)

/obj/item/weapon/newspaper/attackby(obj/item/weapon/W, mob/user, params)
	if(istype(W, /obj/item/weapon/pen))
		if(scribble_page == curr_page)
			user << "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?"
		else
			var/s = stripped_input(user, "Write something", "Newspaper")
			if (!s)
				return
			if (!in_range(src, usr) && loc != usr)
				return
			scribble_page = curr_page
			scribble = s
			attack_self(user)


code:
//#define AMAP

/obj/machinery/computer/security/verb/station_map()
	set name = ".map"
	set category = "Object"
	set src in view(1)
	usr.set_machine(src)
	if(!mapping)
		return

	log_game("[usr]([usr.key]) used station map L[z] in [src.loc.loc]")

	src.drawmap(usr)

/obj/machinery/computer/security/proc/drawmap(mob/user)

	var/icx = round(world.maxx/16) + 1
	var/icy = round(world.maxy/16) + 1

	var/xoff = round( (icx*16-world.maxx)-2)
	var/yoff = round( (icy*16-world.maxy)-2)

	var/icount = icx * icy

	var/list/imap = list()

#ifdef AMAP

	for(var/i = 0; i<icount; i++)
		imap += icon('icons/misc/imap.dmi', "blank")
		imap += icon('icons/misc/imap.dmi', "blank")

	//world << "[icount] images in list"

	for(var/wx = 1 ; wx <= world.maxx; wx++)

		for(var/wy = 1; wy <= world.maxy; wy++)

			var/turf/T = locate(wx, wy, z)

			var/colour
			var/colour2

			if(!T)
				colour = rgb(0,0,0)

			else
				var/sense = 1
				switch("[T.type]")
					if("/turf/open/space")
						colour = rgb(10,10,10)
						sense = 0

					if("/turf/open/floor")
						colour = rgb(150,150,150)
						var/turf/open/floor/TF = T
						if(TF.burnt == 1)
							sense = 0
							colour = rgb(130,130,130)

					if("/turf/open/floor/engine")
						colour = rgb(128,128,128)

					if("/turf/closed/wall")
						colour = rgb(96,96,96)

					if("/turf/closed/wall/r_wall")
						colour = rgb(128,96,96)

					else
						colour = rgb(0,40,0)

				if(sense)

					for(var/atom/AM in T.contents)

						if(istype(AM, /obj/machinery/door) && !istype(AM, /obj/machinery/door/window))
							if(AM.density)
								colour = rgb(96,96,192)
								colour2 = colour
							else
								colour = rgb(128,192,128)

						if(istype(AM, /obj/machinery/airalarm))
							colour = rgb(0,255,0)
							colour2 = colour
							if(AM.icon_state=="alarm:1")
								colour = rgb(255,255,0)
								colour2 = rgb(255,128,0)

						if(istype(AM, /mob))
							if(AM:client)
								colour = rgb(255,0,0)
							else
								colour = rgb(255,128,128)

							colour2 = rgb(192,0,0)

				var/area/A = T.loc

				if(A.fire)

					var/red = getr(colour)
					var/green = getg(colour)
					var/blue = getb(colour)

					green = min(255, green+40)
					blue = min(255, blue+40)

					colour = rgb(red, green, blue)

			if(!colour2 && !T.density)
				var/datum/gas_mixture/environment = T.return_air()
				var/turf_total = environment.total_moles()
				//var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2

				var/t1 = turf_total / MOLES_CELLSTANDARD * 150

				if(t1<=100)
					colour2 = rgb(t1*2.55,0,0)
				else
					t1 = min(100, t1-100)
					colour2 = rgb(255, t1*2.55, t1*2.55)

			if(!colour2)
				colour2 = colour

			var/ix = round((wx*2+xoff)/32)
			var/iy = round((wy*2+yoff)/32)

			var/rx = ((wx*2+xoff)%32) + 1
			var/ry = ((wy*2+yoff)%32) + 1

			//world << "trying [ix],[iy] : [ix+icx*iy]"
			var/icon/I = imap[1+(ix + icx*iy)*2]
			var/icon/I2 = imap[2+(ix + icx*iy)*2]

			//world << "icon: \icon[I]"

			I.DrawBox(colour, rx, ry, rx+1, ry+1)

			I2.DrawBox(colour2, rx, ry, rx+1, ry+1)

	user.clearmap()

	user.mapobjs = list()

	for(var/i=0; i<icount;i++)
		var/obj/screen/H = new /obj/screen()

		H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]"

		//world<<"\icon[I] at [H.screen_loc]"

		H.name = (i==0)?"maprefresh":"map"

		var/icon/HI = new/icon

		var/icon/I = imap[i*2+1]
		var/icon/J = imap[i*2+2]

		HI.Insert(I, frame=1, delay = 5)
		HI.Insert(J, frame=2, delay = 5)

		qdel(I)
		qdel(J)
		H.icon = HI
		H.layer = 25
		usr.mapobjs += H
#else

	for(var/i = 0; i<icount; i++)
		imap += icon('icons/misc/imap.dmi', "blank")

	for(var/wx = 1 ; wx <= world.maxx; wx++)

		for(var/wy = 1; wy <= world.maxy; wy++)

			var/turf/T = locate(wx, wy, z)

			var/colour

			if(!T)
				colour = rgb(0,0,0)

			else
				var/sense = 1
				switch("[T.type]")
					if("/turf/open/space")
						colour = rgb(10,10,10)
						sense = 0

					if("/turf/open/floor", "/turf/open/floor/engine")
						var/datum/gas_mixture/environment = T.return_air()
						var/turf_total = environment.total_moles()
						var/t1 = turf_total / MOLES_CELLSTANDARD * 175

						if(t1<=100)
							colour = rgb(0,0,t1*2.55)
						else
							t1 = min(100, t1-100)
							colour = rgb( t1*2.55, t1*2.55, 255)

					if("/turf/closed/wall")
						colour = rgb(96,96,96)

					if("/turf/closed/wall/r_wall")
						colour = rgb(128,96,96)

					else
						colour = rgb(0,40,0)

				if(sense)

					for(var/atom/AM in T.contents)

						if(istype(AM, /obj/machinery/door) && !istype(AM, /obj/machinery/door/window))
							if(AM.density)
								colour = rgb(0,96,192)
							else
								colour = rgb(96,192,128)

						if(istype(AM, /obj/machinery/airalarm))
							colour = rgb(0,255,0)

							if(AM.icon_state=="alarm:1")
								colour = rgb(255,255,0)

						if(istype(AM, /mob))
							if(AM:client)
								colour = rgb(255,0,0)
							else
								colour = rgb(255,128,128)

						//if(istype(AM, /obj/effect/blob))
						//	colour = rgb(255,0,255)

				var/area/A = T.loc

				if(A.fire)

					var/red = getr(colour)
					var/green = getg(colour)
					var/blue = getb(colour)

					green = min(255, green+40)
					blue = min(255, blue+40)

					colour = rgb(red, green, blue)

			var/ix = round((wx*2+xoff)/32)
			var/iy = round((wy*2+yoff)/32)

			var/rx = ((wx*2+xoff)%32) + 1
			var/ry = ((wy*2+yoff)%32) + 1

			//world << "trying [ix],[iy] : [ix+icx*iy]"
			var/icon/I = imap[1+(ix + icx*iy)]

			//world << "icon: \icon[I]"

			I.DrawBox(colour, rx, ry, rx, ry)

	user.clearmap()

	user.mapobjs = list()

	for(var/i=0; i<icount;i++)
		var/obj/screen/H = new /obj/screen()

		H.screen_loc = "[5 + i%icx],[6+ round(i/icx)]"

		//world<<"\icon[I] at [H.screen_loc]"

		H.name = (i==0)?"maprefresh":"map"

		var/icon/I = imap[i+1]

		H.icon = I
		qdel(I)
		H.layer = 25
		usr.mapobjs += H

#endif

	user.client.screen += user.mapobjs

	src.close(user)

/*			if(seccomp == src)
				drawmap(user)
			else
				user.clearmap()*/
	return

/obj/machinery/computer/security/proc/close(mob/user)
	spawn(20)
		var/using = null
		if(user.mapobjs)
			for(var/obj/machinery/computer/security/seccomp in oview(1,user))
				if(seccomp == src)
					using = 1
					break
			if(using)
				close(user)
			else
				user.clearmap()

		return

/proc/getr(col)
	return hex2num( copytext(col, 2,4))

/proc/getg(col)
	return hex2num( copytext(col, 4,6))

/proc/getb(col)
	return hex2num( copytext(col, 6))

/mob/proc/clearmap()
	src.client.screen -= src.mapobjs
	for(var/obj/screen/O in mapobjs)
		qdel(O)

	mapobjs = null
	src.unset_machine()


code:
/*CONTENTS
Buildable pipes
Buildable meters
*/

//construction defines are in __defines/pipe_construction.dm
//update those defines ANY TIME an atmos path is changed...
//...otherwise construction will stop working

/obj/item/pipe
	name = "pipe"
	desc = "A pipe"
	var/pipe_type = 0
	var/pipename
	force = 7
	icon = 'icons/obj/atmospherics/pipes/pipe_item.dmi'
	icon_state = "simple"
	item_state = "buildpipe"
	w_class = 3
	level = 2
	var/flipped = 0
	var/is_bent = 0

	var/global/list/pipe_types = list(
		PIPE_SIMPLE, \
		PIPE_MANIFOLD, \
		PIPE_4WAYMANIFOLD, \
		PIPE_HE, \
		PIPE_HE_MANIFOLD, \
		PIPE_HE_4WAYMANIFOLD, \
		PIPE_JUNCTION, \
		\
		PIPE_CONNECTOR, \
		PIPE_UVENT, \
		PIPE_SCRUBBER, \
		PIPE_HEAT_EXCHANGE, \
		\
		PIPE_PUMP, \
		PIPE_PASSIVE_GATE, \
		PIPE_VOLUME_PUMP, \
		PIPE_MVALVE, \
		PIPE_DVALVE, \
		\
		PIPE_GAS_FILTER, \
		PIPE_GAS_MIXER, \
	)

/obj/item/pipe/examine(mob/user)
	..()
	user << "Alt-click to rotate it clockwise."

/obj/item/pipe/New(loc, pipe_type, dir, obj/machinery/atmospherics/make_from)
	..()
	if(make_from)
		src.dir = make_from.dir
		src.pipename = make_from.name
		src.color = make_from.color

		if(make_from.type in pipe_types)
			src.pipe_type = make_from.type
		else //make pipe_type a value we can work with
			for(var/P in pipe_types)
				if(istype(make_from, P))
					src.pipe_type = P
					break

		var/obj/machinery/atmospherics/components/trinary/triP = make_from
		if(istype(triP) && triP.flipped)
			src.flipped = 1
			src.dir = turn(src.dir, -45)
	else
		src.pipe_type = pipe_type
		src.dir = dir

	if(src.dir in diagonals)
		is_bent = 1

	update()
	src.pixel_x = rand(-5, 5)
	src.pixel_y = rand(-5, 5)

//update the name and icon of the pipe item depending on the type
var/global/list/pipeID2State = list(
	"[PIPE_SIMPLE]"			 = "simple", \
	"[PIPE_MANIFOLD]"		 = "manifold", \
	"[PIPE_4WAYMANIFOLD]"	 = "manifold4w", \
	"[PIPE_HE]"				 = "he", \
	"[PIPE_HE_MANIFOLD]"	 = "he_manifold", \
	"[PIPE_HE_4WAYMANIFOLD]" = "he_manifold4w", \
	"[PIPE_JUNCTION]"		 = "junction", \
	\
	"[PIPE_CONNECTOR]"		 = "connector", \
	"[PIPE_UVENT]"			 = "uvent", \
	"[PIPE_SCRUBBER]"		 = "scrubber", \
	"[PIPE_HEAT_EXCHANGE]"	 = "heunary", \
	\
	"[PIPE_PUMP]"			 = "pump", \
	"[PIPE_PASSIVE_GATE]"	 = "passivegate", \
	"[PIPE_VOLUME_PUMP]"	 = "volumepump", \
	"[PIPE_MVALVE]"			 = "mvalve", \
	"[PIPE_DVALVE]"			 = "dvalve", \
	\
	"[PIPE_GAS_FILTER]"		 = "filter", \
	"[PIPE_GAS_MIXER]"		 = "mixer", \
)

/obj/item/pipe/proc/update()
	var/list/nlist = list(\
		"[PIPE_SIMPLE]" 		= "pipe", \
		"[PIPE_SIMPLE]_b" 		= "bent pipe", \
		"[PIPE_MANIFOLD]" 		= "manifold", \
		"[PIPE_4WAYMANIFOLD]" 	= "4-way manifold", \
		"[PIPE_HE]" 			= "h/e pipe", \
		"[PIPE_HE]_b" 			= "bent h/e pipe", \
		"[PIPE_HE_MANIFOLD]"	= "h/e manifold", \
		"[PIPE_HE_4WAYMANIFOLD]"= "h/e 4-way manifold", \
		"[PIPE_JUNCTION]" 		= "junction", \
		\
		"[PIPE_CONNECTOR]" 		= "connector", \
		"[PIPE_UVENT]" 			= "vent", \
		"[PIPE_SCRUBBER]" 		= "scrubber", \
		"[PIPE_HEAT_EXCHANGE]" 	= "heat exchanger", \
		\
		"[PIPE_PUMP]" 			= "pump", \
		"[PIPE_PASSIVE_GATE]" 	= "passive gate", \
		"[PIPE_VOLUME_PUMP]" 	= "volume pump", \
		"[PIPE_MVALVE]" 		= "manual valve", \
		"[PIPE_DVALVE]" 		= "digital valve", \
		\
		"[PIPE_GAS_FILTER]" 	= "gas filter", \
		"[PIPE_GAS_MIXER]" 		= "gas mixer", \
		)
	//fix_pipe_type()
	name = nlist["[pipe_type][is_bent ? "_b" : ""]"] + " fitting"
	icon_state = pipeID2State["[pipe_type]"]

// rotate the pipe item clockwise

/obj/item/pipe/verb/rotate()
	set category = "Object"
	set name = "Rotate Pipe"
	set src in view(1)

	if ( usr.stat || usr.restrained() || !usr.canmove )
		return

	src.dir = turn(src.dir, -90)

	fixdir()

	return

/obj/item/pipe/verb/flip()
	set category = "Object"
	set name = "Flip Pipe"
	set src in view(1)

	if ( usr.stat || usr.restrained() || !usr.canmove )
		return

	if (pipe_type in list(PIPE_GAS_FILTER, PIPE_GAS_MIXER))
		src.dir = turn(src.dir, flipped ? 45 : -45)
		flipped = !flipped
		return

	src.dir = turn(src.dir, -180)

	fixdir()

	return

/obj/item/pipe/AltClick(mob/user)
	..()
	if(user.incapacitated())
		user << "You can't do that right now!"
		return
	if(!in_range(src, user))
		return
	else
		rotate()

/obj/item/pipe/Move()
	var/old_dir = dir
	..()
	dir = old_dir //pipes changing direction when moved is just annoying and buggy

/obj/item/pipe/proc/unflip(direction)
	if(direction in diagonals)
		return turn(direction, 45)

	return direction

//Helper to clean up dir
/obj/item/pipe/proc/fixdir()
	if((pipe_type in list (PIPE_SIMPLE, PIPE_HE, PIPE_MVALVE, PIPE_DVALVE)) && !is_bent)
		if(dir==SOUTH)
			dir = NORTH
		else if(dir==WEST)
			dir = EAST

/obj/item/pipe/attack_self(mob/user)
	return rotate()

/obj/item/pipe/attackby(obj/item/weapon/W, mob/user, params)
	if (!istype(W, /obj/item/weapon/wrench))
		return ..()
	if (!isturf(src.loc))
		return 1

	fixdir()
	if(pipe_type in list(PIPE_GAS_MIXER, PIPE_GAS_FILTER))
		dir = unflip(dir)

	var/obj/machinery/atmospherics/A = new pipe_type(src.loc)
	A.dir = src.dir
	A.SetInitDirections()

	for(var/obj/machinery/atmospherics/M in src.loc)
		if(M == A) //we don't want to check to see if it interferes with itself
			continue
		if(M.GetInitDirections() & A.GetInitDirections())	// matches at least one direction on either type of pipe
			user << "There is already a pipe at that location!"
			qdel(A)
			return 1
	// no conflicts found

	if(pipename)
		A.name = pipename

	var/obj/machinery/atmospherics/components/trinary/T = A
	if(istype(T))
		T.flipped = flipped
	A.construction(pipe_type, color)

	playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
	user.visible_message( \
		"[user] fastens \the [src].", \
		"You fasten \the [src].", \
		"You hear ratchet.")

	qdel(src)

/obj/item/pipe/suicide_act(mob/user)
	if (pipe_type in list(PIPE_PUMP, PIPE_PASSIVE_GATE, PIPE_VOLUME_PUMP))
		user.visible_message("[user] shoved the [src] in \his mouth and turned it on!  It looks like \he's trying to commit suicide.")
		if(istype(user, /mob/living/carbon))
			var/mob/living/carbon/C = user
			for(var/i=1 to 20)
				C.vomit(0,1,0,4,0)
				sleep(5)
			if(istype(user, /mob/living/carbon/human))
				var/mob/living/carbon/human/H = C
				H.vessel.remove_reagent("blood",560)
		return(OXYLOSS|BRUTELOSS)
	else
		return ..()

/obj/item/pipe_meter
	name = "meter"
	desc = "A meter that can be laid on pipes"
	icon = 'icons/obj/atmospherics/pipes/pipe_item.dmi'
	icon_state = "meter"
	item_state = "buildpipe"
	w_class = 4

/obj/item/pipe_meter/attackby(obj/item/weapon/W, mob/user, params)
	..()

	if (!istype(W, /obj/item/weapon/wrench))
		return ..()
	if(!locate(/obj/machinery/atmospherics/pipe, src.loc))
		user << "You need to fasten it to a pipe!"
		return 1
	new/obj/machinery/meter( src.loc )
	playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
	user << "You fasten the meter to the pipe."
	qdel(src)


code:
/obj/machinery/pipedispenser
	name = "pipe dispenser"
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "pipe_d"
	density = 1
	anchored = 1
	var/wait = 0

/obj/machinery/pipedispenser/attack_paw(mob/user)
	return src.attack_hand(user)

/obj/machinery/pipedispenser/attack_hand(mob/user)
	if(..())
		return 1
	var/dat = {"
Regular pipes:

Pipe

Bent Pipe

Manifold

4-Way Manifold

Manual Valve

Digital Valve

Devices:

Connector

Vent

Gas Pump

Passive Gate

Volume Pump

Scrubber

Meter

Gas Filter

Gas Mixer

Heat exchange:

Pipe

Bent Pipe

Manifold

4-Way Manifold

Junction

Heat Exchanger

"}

	user << browse("<TITLE>[src]</TITLE><TT>[dat]</TT>", "window=pipedispenser")
	onclose(user, "pipedispenser")
	return

/obj/machinery/pipedispenser/Topic(href, href_list)
	if(..())
		return 1
	if(!anchored|| !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
		usr << browse(null, "window=pipedispenser")
		return 1
	usr.set_machine(src)
	src.add_fingerprint(usr)
	if(href_list["make"])
		if(!wait)
			var/p_type = text2path(href_list["make"])
			var/p_dir = text2num(href_list["dir"])
			var/obj/item/pipe/P = new (src.loc, pipe_type=p_type, dir=p_dir)
			P.add_fingerprint(usr)
			wait = 1
			spawn(10)
				wait = 0
	if(href_list["makemeter"])
		if(!wait)
			new /obj/item/pipe_meter(src.loc)
			wait = 1
			spawn(15)
				wait = 0
	return

/obj/machinery/pipedispenser/attackby(obj/item/W, mob/user, params)
	add_fingerprint(user)
	if (istype(W, /obj/item/pipe) || istype(W, /obj/item/pipe_meter))
		usr << "You put [W] back into [src]."
		if(!user.drop_item())
			return
		qdel(W)
		return
	else if (istype(W, /obj/item/weapon/wrench))
		if (!anchored && !isinspace())
			playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
			user << "You begin to fasten \the [src] to the floor..."
			if (do_after(user, 40/W.toolspeed, target = src))
				add_fingerprint(user)
				user.visible_message( \
					"[user] fastens \the [src].", \
					"You fasten \the [src]. Now it can dispense pipes.", \
					"You hear ratchet.")
				anchored = 1
				stat &= MAINT
				if (usr.machine==src)
					usr << browse(null, "window=pipedispenser")
		else if(anchored)
			playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
			user << "You begin to unfasten \the [src] from the floor..."
			if (do_after(user, 20/W.toolspeed, target = src))
				add_fingerprint(user)
				user.visible_message( \
					"[user] unfastens \the [src].", \
					"You unfasten \the [src]. Now it can be pulled somewhere else.", \
					"You hear ratchet.")
				anchored = 0
				stat |= ~MAINT
				power_change()
	else
		return ..()

/obj/machinery/pipedispenser/disposal
	name = "disposal pipe dispenser"
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "pipe_d"
	density = 1
	anchored = 1

/*
//Allow you to push disposal pipes into it (for those with density 1)
/obj/machinery/pipedispenser/disposal/Crossed(var/obj/structure/disposalconstruct/pipe as obj)
	if(istype(pipe) && !pipe.anchored)
		qdel(pipe)

Nah
*/

//Allow you to drag-drop disposal pipes and transit tubes into it
/obj/machinery/pipedispenser/disposal/MouseDrop_T(obj/structure/pipe, mob/usr)
	if(!usr.canmove || usr.stat || usr.restrained())
		return

	if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod))
		return

	if (get_dist(usr, src) > 1 || get_dist(src,pipe) > 1 )
		return

	if (pipe.anchored)
		return

	qdel(pipe)

/obj/machinery/pipedispenser/disposal/attack_hand(mob/user)
	if(..())
		return 1

	var/dat = {"Disposal Pipes

Pipe

Bent Pipe

Junction

Y-Junction

Trunk

Bin

Outlet

Chute

Sort Junction

"}

	user << browse("<TITLE>[src]</TITLE><TT>[dat]</TT>", "window=pipedispenser")
	return

/obj/machinery/pipedispenser/disposal/Topic(href, href_list)
	if(..())
		return 1
	usr.set_machine(src)
	src.add_fingerprint(usr)
	if(href_list["dmake"])
		if(!wait)
			var/p_type = text2num(href_list["dmake"])
			var/obj/structure/disposalconstruct/C = new (src.loc,p_type)

			if(!C.can_place())
				usr << "There's not enough room to build that here!"
				qdel(C)
				return

			C.add_fingerprint(usr)
			C.update()
			wait = 1
			spawn(15)
				wait = 0
	return

//transit tube dispenser
//inherit disposal for the dragging proc
/obj/machinery/pipedispenser/disposal/transit_tube
	name = "transit tube dispenser"
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "pipe_d"
	density = 1
	anchored = 1

/obj/machinery/pipedispenser/disposal/transit_tube/attack_hand(mob/user)
	if(..())
		return 1

	var/dat = {"Transit Tubes:

Straight Tube

Straight Tube with Crossing

Curved Tube

Diagonal Tube

Junction

Station Equipment:

Through Tube Station

Terminus Tube Station

Tube Blocker

Transit Tube Pod

"}

	user << browse("<TITLE>[src]</TITLE><TT>[dat]</TT>", "window=pipedispenser")
	return

/obj/machinery/pipedispenser/disposal/transit_tube/Topic(href, href_list)
	if(..())
		return 1
	usr.set_machine(src)
	src.add_fingerprint(usr)
	if(!wait)
		if(href_list["tube"])
			var/tube_type = text2num(href_list["tube"])
			if(tube_type <= 4)
				var/obj/structure/c_transit_tube/C = new/obj/structure/c_transit_tube(src.loc)
				switch(tube_type)
					if(0)
						C.icon_state = "E-W"
					if(1)
						C.icon_state = "E-W-Pass"
					if(2)
						C.icon_state = "S-NE"
					if(3)
						C.icon_state = "NE-SW"
					if(4)
						C.icon_state = "W-NE-SE"
				C.add_fingerprint(usr)
			else
				switch(tube_type)
					if(5)
						var/obj/structure/c_transit_tube/station/C = new/obj/structure/c_transit_tube/station(src.loc)
						C.add_fingerprint(usr)
					if(6)
						var/obj/structure/c_transit_tube/station/reverse/C = new/obj/structure/c_transit_tube/station/reverse(src.loc)
						C.add_fingerprint(usr)
					if(7)
						var/obj/structure/c_transit_tube/station/block/C = new/obj/structure/c_transit_tube/station/block(src.loc)
						C.add_fingerprint(usr)
					if(8)
						var/obj/structure/c_transit_tube_pod/C = new/obj/structure/c_transit_tube_pod(src.loc)
						C.add_fingerprint(usr)
			wait = 1
			spawn(15)
				wait = 0
	return