code:
#define CHARS_PER_LINE 5
#define FONT_SIZE "5pt"
#define FONT_COLOR "#09f"
#define FONT_STYLE "Arial Black"
#define MAX_TIMER 9000

#define PRESET_SHORT 1200
#define PRESET_MEDIUM 3000
#define PRESET_LONG 6000

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

///////////////////////////////////////////////////////////////////////////////////////////////
// Brig Door control displays.
//  Description: This is a controls the timer for the brig doors, displays the timer on itself and
//               has a popup window when used, allowing to set the timer.
//  Code Notes: Combination of old brigdoor.dm code from rev4407 and the status_display.dm code
//  Date: 01/September/2010
//  Programmer: Veryinky
/////////////////////////////////////////////////////////////////////////////////////////////////
/obj/machinery/door_timer
	name = "door timer"
	icon = 'icons/obj/status_display.dmi'
	icon_state = "frame"
	desc = "A remote control for a door."
	req_access = list(access_brig)
	anchored = 1
	density = 0
	var/id = null // id of linked machinery/lockers

	var/activation_time = 0
	var/timer_duration = 0

	var/timing = FALSE		// boolean, true/1 timer is on, false/0 means it's not timing
	var/list/obj/machinery/targets = list()
	var/obj/item/device/radio/Radio //needed to send messages to sec radio

	maptext_height = 26
	maptext_width = 32

/obj/machinery/door_timer/New()
	..()

	Radio = new/obj/item/device/radio(src)
	Radio.listening = 0

/obj/machinery/door_timer/initialize()
	for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
		if (M.id == id)
			targets += M

	for(var/obj/machinery/flasher/F in urange(20, src))
		if(F.id == id)
			targets += F

	for(var/obj/structure/closet/secure_closet/brig/C in urange(20, src))
		if(C.id == id)
			targets += C

	if(!targets.len)
		stat |= BROKEN
	update_icon()

//Main door timer loop, if it's timing and time is >0 reduce time by 1.
// if it's less than 0, open door, reset timer
// update the door_timer window and the icon
/obj/machinery/door_timer/process()
	if(stat & (NOPOWER|BROKEN))
		return

	if(timing)
		if(world.time - activation_time >= timer_duration)
			timer_end() // open doors, reset timer, clear status screen
		update_icon()

// has the door power sitatuation changed, if so update icon.
/obj/machinery/door_timer/power_change()
	..()
	update_icon()

// open/closedoor checks if door_timer has power, if so it checks if the
// linked door is open/closed (by density) then opens it/closes it.
/obj/machinery/door_timer/proc/timer_start()
	if(stat & (NOPOWER|BROKEN))
		return 0

	activation_time = world.time
	timing = TRUE

	for(var/obj/machinery/door/window/brigdoor/door in targets)
		if(door.density)
			continue
		spawn(0)
			door.close()

	for(var/obj/structure/closet/secure_closet/brig/C in targets)
		if(C.broken)
			continue
		if(C.opened && !C.close())
			continue
		C.locked = 1
		C.update_icon()
	return 1

/obj/machinery/door_timer/proc/timer_end(forced = FALSE)

	if(stat & (NOPOWER|BROKEN))
		return 0

	if(!forced)
		Radio.set_frequency(SEC_FREQ)
		Radio.talk_into(src, "Timer has expired. Releasing prisoner.", SEC_FREQ)

	timing = FALSE
	activation_time = null
	set_timer(0)
	update_icon()

	for(var/obj/machinery/door/window/brigdoor/door in targets)
		if(!door.density)
			continue
		spawn(0)
			door.open()

	for(var/obj/structure/closet/secure_closet/brig/C in targets)
		if(C.broken)
			continue
		if(C.opened)
			continue
		C.locked = 0
		C.update_icon()

	return 1

/obj/machinery/door_timer/proc/time_left(seconds = FALSE)
	. = max(0,timer_duration - (activation_time ? world.time - activation_time : 0))
	if(seconds)
		. /= 10

/obj/machinery/door_timer/proc/set_timer(value)
	var/new_time = Clamp(value,0,MAX_TIMER)
	. = new_time == timer_duration //return 1 on no change
	timer_duration = new_time

/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
										datum/tgui/master_ui = null, datum/ui_state/state = default_state)
	ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
	if(!ui)
		ui = new(user, src, ui_key, "brig_timer", name, 300, 200, master_ui, state)
		ui.open()

//icon update function
// if NOPOWER, display blank
// if BROKEN, display blue screen of death icon AI uses
// if timing=true, run update display function
/obj/machinery/door_timer/update_icon()
	if(stat & (NOPOWER))
		icon_state = "frame"
		return

	if(stat & (BROKEN))
		set_picture("ai_bsod")
		return

	if(timing)
		var/disp1 = id
		var/time_left = time_left(seconds = TRUE)
		var/disp2 = "[add_zero(num2text((time_left / 60) % 60),2)]~[add_zero(num2text(time_left % 60), 2)]"
		if(length(disp2) > CHARS_PER_LINE)
			disp2 = "Error"
		update_display(disp1, disp2)
	else
		if(maptext)
			maptext = ""
	return

// Adds an icon in case the screen is broken/off, stolen from status_display.dm
/obj/machinery/door_timer/proc/set_picture(state)
	if(maptext)
		maptext = ""
	overlays.Cut()
	overlays += image('icons/obj/status_display.dmi', icon_state=state)

//Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display
// Stolen from status_display
/obj/machinery/door_timer/proc/update_display(line1, line2)
	var/new_text = {"
[line1]
[line2]
"}
	if(maptext != new_text)
		maptext = new_text

/obj/machinery/door_timer/ui_data()
	var/list/data = list()
	var/time_left = time_left(seconds = TRUE)
	data["seconds"] = round(time_left % 60)
	data["minutes"] = round((time_left - data["seconds"]) / 60)
	data["timing"] = timing
	data["flash_charging"] = FALSE
	for(var/obj/machinery/flasher/F in targets)
		if(F.last_flash && (F.last_flash + 150) > world.time)
			data["flash_charging"] = TRUE
			break
	return data

/obj/machinery/door_timer/ui_act(action, params)
	if(..())
		return
	. = TRUE
	switch(action)
		if("time")
			var/value = text2num(params["adjust"])
			if(value)
				. = set_timer(time_left()+value)
		if("start")
			timer_start()
		if("stop")
			timer_end(forced = TRUE)
		if("flash")
			for(var/obj/machinery/flasher/F in targets)
				F.flash()
		if("preset")
			var/preset = params["preset"]
			var/preset_time = time_left()
			switch(preset)
				if("short")
					preset_time = PRESET_SHORT
				if("medium")
					preset_time = PRESET_MEDIUM
				if("long")
					preset_time = PRESET_LONG
			. = set_timer(preset_time)
			if(timing)
				activation_time = world.time
		else
			. = FALSE

#undef PRESET_SHORT
#undef PRESET_MEDIUM
#undef PRESET_LONG

#undef MAX_TIMER
#undef FONT_SIZE
#undef FONT_COLOR
#undef FONT_STYLE
#undef CHARS_PER_LINE


code:
/obj/machinery/door/proc/checkForMultipleDoors()
	if(!src.loc)
		return 0
	for(var/obj/machinery/door/D in src.loc)
		if(!istype(D, /obj/machinery/door/window) && D.density && D != src)
			return 0
	return 1

/turf/closed/wall/proc/checkForMultipleDoors()
	if(!src.loc)
		return 0
	for(var/obj/machinery/door/D in locate(src.x,src.y,src.z))
		if(!istype(D, /obj/machinery/door/window) && D.density)
			return 0
	//There are no false wall checks because that would be fucking retarded
	return 1

license: mit


code:
/obj/machinery/door
	name = "door"
	desc = "It opens and closes."
	icon = 'icons/obj/doors/Doorint.dmi'
	icon_state = "door1"
	anchored = 1
	opacity = 1
	density = 1
	layer = 2.7
	power_channel = ENVIRON

	var/secondsElectrified = 0
	var/visible = 1
	var/p_open = 0
	var/operating = 0
	var/glass = 0
	var/normalspeed = 1
	var/heat_proof = 0 // For rglass-windowed airlocks and firedoors
	var/emergency = 0 // Emergency access override
	var/sub_door = 0 // 1 if it's meant to go under another door.
	var/closingLayer = 3.1

/obj/machinery/door/New()
	..()
	if(density)
		layer = 3.1 //Above most items if closed
	else
		layer = 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
	update_freelook_sight()
	air_update_turf(1)
	airlocks += src
	return

/obj/machinery/door/Destroy()
	density = 0
	air_update_turf(1)
	update_freelook_sight()
	airlocks -= src
	return ..()

//process()
	//return

/obj/machinery/door/Bumped(atom/AM)
	if(operating || emagged) return
	if(isliving(AM))
		var/mob/living/M = AM
		if(world.time - M.last_bumped <= 10) return	//Can bump-open one airlock per second. This is to prevent shock spam.
		M.last_bumped = world.time
		if(!M.restrained())
			bumpopen(M)
		return

	if(istype(AM, /obj/mecha))
		var/obj/mecha/mecha = AM
		if(density)
			if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access) || emergency == 1))
				open()
			else
				do_animate("deny")
		return
	return

/obj/machinery/door/Move()
	var/turf/T = loc
	..()
	move_update_air(T)

/obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return !opacity
	return !density

/obj/machinery/door/CanAtmosPass()
	return !density

/obj/machinery/door/proc/CheckForMobs()
	if(locate(/mob/living) in get_turf(src))
		sleep(1)
		open()

/obj/machinery/door/proc/bumpopen(mob/user)
	if(operating)
		return
	src.add_fingerprint(user)
	if(!src.requiresID())
		user = null

	if(density && !emagged)
		if(allowed(user) || src.emergency == 1)
			open()
		else
			do_animate("deny")
	return

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

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

/obj/machinery/door/attack_hand(mob/user)
	return src.attackby(user, user)

/obj/machinery/door/attack_tk(mob/user)
	if(requiresID() && !allowed(null))
		return
	..()

/obj/machinery/door/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/device/detective_scanner))
		return
	if(isrobot(user))
		return //borgs can't attack doors open because it conflicts with their AI-like interaction with them.
	src.add_fingerprint(user)
	if(operating || emagged)
		return
	if(!Adjacent(user))
		user = null
	if(!src.requiresID())
		user = null
	if(src.allowed(user) || src.emergency == 1)
		if(src.density)
			open()
		else
			close()
		return
	if(src.density)
		do_animate("deny")
	return

/obj/machinery/door/blob_act()
	if(prob(40))
		qdel(src)
	return

/obj/machinery/door/emp_act(severity)
	if(prob(20/severity) && (istype(src,/obj/machinery/door/airlock) || istype(src,/obj/machinery/door/window)) )
		open()
	if(prob(40/severity))
		if(secondsElectrified == 0)
			secondsElectrified = -1
			spawn(300)
				secondsElectrified = 0
	..()

/obj/machinery/door/ex_act(severity, target)
	if(severity == 3)
		if(prob(80))
			var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
			s.set_up(2, 1, src)
			s.start()
		return
	..()

/obj/machinery/door/update_icon()
	if(density)
		icon_state = "door1"
	else
		icon_state = "door0"
	return

/obj/machinery/door/proc/do_animate(animation)
	switch(animation)
		if("opening")
			if(p_open)
				flick("o_doorc0", src)
			else
				flick("doorc0", src)
		if("closing")
			if(p_open)
				flick("o_doorc1", src)
			else
				flick("doorc1", src)
		if("deny")
			flick("door_deny", src)
	return

/obj/machinery/door/proc/open()
	if(!density)
		return 1
	if(operating)
		return
	if(!ticker || !ticker.mode)
		return 0
	operating = 1

	do_animate("opening")
	icon_state = "door0"
	src.SetOpacity(0)
	sleep(5)
	src.density = 0
	sleep(5)
	src.layer = 2.7
	update_icon()
	SetOpacity(0)
	operating = 0
	air_update_turf(1)
	update_freelook_sight()
	return 1

/obj/machinery/door/proc/close()
	if(density)
		return 1
	if(operating)
		return
	operating = 1

	do_animate("closing")
	src.layer = closingLayer
	sleep(5)
	src.density = 1
	sleep(5)
	update_icon()
	if(visible && !glass)
		SetOpacity(1)
	CheckForMobs()
	operating = 0
	air_update_turf(1)
	update_freelook_sight()
	return

/obj/machinery/door/proc/crush()
	for(var/mob/living/L in get_turf(src))
		if(isalien(L))  //For xenos
			L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans.
			L.emote("roar")
		else if(ishuman(L)) //For humans
			L.adjustBruteLoss(DOOR_CRUSH_DAMAGE)
			L.emote("scream")
			L.Weaken(5)
		else if(ismonkey(L)) //For monkeys
			L.adjustBruteLoss(DOOR_CRUSH_DAMAGE)
			L.Weaken(5)
		else //for simple_animals & borgs
			L.adjustBruteLoss(DOOR_CRUSH_DAMAGE)
		var/turf/location = get_turf(src)
		//add_blood doesn't work for borgs/xenos, but add_blood_floor does.
		location.add_blood_floor(L)
	for(var/obj/mecha/M in get_turf(src))
		M.take_damage(DOOR_CRUSH_DAMAGE)

/obj/machinery/door/proc/requiresID()
	return 1

/obj/machinery/door/proc/hasPower()
	return !(stat & NOPOWER)

/obj/machinery/door/proc/update_freelook_sight()
	if(!glass && cameranet)
		cameranet.updateVisibility(src, 0)

/obj/machinery/door/BlockSuperconductivity() // All non-glass airlocks block heat, this is intended.
	if(opacity || heat_proof)
		return 1
	return 0

/obj/machinery/door/morgue
	icon = 'icons/obj/doors/doormorgue.dmi'

/obj/machinery/door/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
	return 0

/obj/machinery/door/proc/lock()
	return

/obj/machinery/door/proc/unlock()
	return


code:
#define CONSTRUCTION_COMPLETE 0 //No construction done - functioning as normal
#define CONSTRUCTION_PANEL_OPEN 1 //Maintenance panel is open, still functioning
#define CONSTRUCTION_WIRES_EXPOSED 2 //Cover plate is removed, wires are available
#define CONSTRUCTION_GUTTED 3 //Wires are removed, circuit ready to remove
#define CONSTRUCTION_NOCIRCUIT 4 //Circuit board removed, can safely weld apart

/var/const/OPEN = 1
/var/const/CLOSED = 2

/obj/machinery/door/firedoor
	name = "firelock"
	desc = "Apply crowbar."
	icon = 'icons/obj/doors/Doorfireglass.dmi'
	icon_state = "door_open"
	opacity = 0
	density = 0
	heat_proof = 1
	glass = 1
	var/blocked = 0
	var/nextstate = null
	sub_door = 1
	closingLayer = 3.11

/obj/machinery/door/firedoor/Bumped(atom/AM)
	if(p_open || operating)
		return
	if(!density)
		return ..()
	return 0

/obj/machinery/door/firedoor/power_change()
	if(powered(power_channel))
		stat &= ~NOPOWER
		latetoggle()
	else
		stat |= NOPOWER
	return

/obj/machinery/door/firedoor/attackby(obj/item/weapon/C, mob/user, params)
	add_fingerprint(user)
	if(operating)
		return//Already doing something.

	if(istype(C, /obj/item/weapon/weldingtool))
		var/obj/item/weapon/weldingtool/W = C
		if(W.remove_fuel(0, user))
			blocked = !blocked
			user << text("You [blocked?"welded":"unwelded"] \the [src]")
			update_icon()
			return

	if(istype(C, /obj/item/weapon/wrench) && panel_open)
		playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1)
		user.visible_message("[user] starts undoing [src]'s bolts...", \
							 "You start unfastening [src]'s floor bolts...")
		if(!do_after(user, 50/C.toolspeed, target = src))
			return
		playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
		user.visible_message("[user] unfastens [src]'s bolts.", \
							 "You undo [src]'s floor bolts.")
		var/obj/structure/firelock_frame/F = new(get_turf(src))
		if(istype(src, /obj/machinery/door/firedoor/heavy))
			F.reinforced = 1
		F.constructionStep = CONSTRUCTION_PANEL_OPEN
		F.update_icon()
		qdel(src)
		return

	if(istype(C, /obj/item/weapon/crowbar) || (istype(C,/obj/item/weapon/twohanded/fireaxe) && C:wielded == 1))
		if(blocked || operating)
			return
		if(density)
			open()
			return
		else	//close it up again	//fucking 10/10 commenting here einstein
			close()
			return

	if(istype(C, /obj/item/weapon/screwdriver))
		default_deconstruction_screwdriver(user, icon_state, icon_state, C)
		return

	return

/obj/machinery/door/firedoor/attack_ai(mob/user)
	add_fingerprint(user)
	if(blocked || operating || stat & NOPOWER)
		return
	if(density)
		open()
	else
		close()
	return

/obj/machinery/door/firedoor/attack_alien(mob/user)
	add_fingerprint(user)
	if(blocked)
		user << "[src] refuses to budge!"
		return
	open()

/obj/machinery/door/firedoor/do_animate(animation)
	switch(animation)
		if("opening")
			flick("door_opening", src)
		if("closing")
			flick("door_closing", src)
	return

/obj/machinery/door/firedoor/update_icon()
	overlays.Cut()
	if(density)
		icon_state = "door_closed"
		if(blocked)
			overlays += "welded"
	else
		icon_state = "door_open"
		if(blocked)
			overlays += "welded_open"
	return

/obj/machinery/door/firedoor/open()
	..()
	latetoggle()
	return

/obj/machinery/door/firedoor/close()
	..()
	if(locate(/mob/living) in get_turf(src))
		open()
		return
	latetoggle()
	return

/obj/machinery/door/firedoor/proc/latetoggle()
	if(operating || stat & NOPOWER || !nextstate)
		return
	switch(nextstate)
		if(OPEN)
			nextstate = null
			open()
		if(CLOSED)
			nextstate = null
			close()
	return

/obj/machinery/door/firedoor/border_only
	icon = 'icons/obj/doors/edge_Doorfire.dmi'
	flags = ON_BORDER

/obj/machinery/door/firedoor/border_only/CanPass(atom/movable/mover, turf/target, height=0)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	if(get_dir(loc, target) == dir) //Make sure looking at appropriate border
		return !density
	else
		return 1

/obj/machinery/door/firedoor/border_only/CheckExit(atom/movable/mover as mob|obj, turf/target)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	if(get_dir(loc, target) == dir)
		return !density
	else
		return 1

/obj/machinery/door/firedoor/border_only/CanAtmosPass(turf/T)
	if(get_dir(loc, T) == dir)
		return !density
	else
		return 1

/obj/machinery/door/firedoor/heavy
	name = "heavy firelock"
	icon = 'icons/obj/doors/Doorfire.dmi'
	glass = 0

/obj/item/weapon/electronics/firelock
	name = "firelock circuitry"
	desc = "A circuit board used in construction of firelocks."
	icon_state = "mainboard"

/obj/structure/firelock_frame
	name = "firelock frame"
	desc = "A partially completed firelock."
	icon = 'icons/obj/doors/Doorfire.dmi'
	icon_state = "frame1"
	anchored = 0
	density = 1
	var/constructionStep = CONSTRUCTION_NOCIRCUIT
	var/reinforced = 0

/obj/structure/firelock_frame/examine(mob/user)
	..()
	switch(constructionStep)
		if(CONSTRUCTION_PANEL_OPEN)
			user << "There is a small metal plate covering the wires."
		if(CONSTRUCTION_WIRES_EXPOSED)
			user << "Wires are trailing from the maintenance panel."
		if(CONSTRUCTION_GUTTED)
			user << "The circuit board is visible."
		if(CONSTRUCTION_NOCIRCUIT)
			user << "There are no electronics in the frame."

/obj/structure/firelock_frame/update_icon()
	..()
	icon_state = "frame[constructionStep]"

/obj/structure/firelock_frame/attackby(obj/item/weapon/C, mob/user)
	switch(constructionStep)
		if(CONSTRUCTION_PANEL_OPEN)
			if(istype(C, /obj/item/weapon/crowbar))
				playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
				user.visible_message("[user] starts prying something out from [src]...", \
									 "You begin prying out the wire cover...")
				if(!do_after(user, 50/C.toolspeed, target = src)) return
				if(constructionStep != CONSTRUCTION_PANEL_OPEN) return
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				user.visible_message("[user] pries out a metal plate from [src], exposing the wires.", \
									 "You remove the cover plate from [src], exposing the wires.")
				constructionStep = CONSTRUCTION_WIRES_EXPOSED
				update_icon()
				return
			if(istype(C, /obj/item/weapon/wrench))
				playsound(get_turf(src), 'sound/items/Ratchet.ogg', 50, 1)
				user.visible_message("[user] starts bolting down [src]...", \
									 "You begin bolting [src]...")
				if(!do_after(user, 30/C.toolspeed, target = src)) return
				user.visible_message("[user] finishes the firelock.", \
									 "You finish the firelock.")
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				if(reinforced)
					new /obj/machinery/door/firedoor/heavy(get_turf(src))
				else
					new /obj/machinery/door/firedoor(get_turf(src))
				qdel(src)
				return
		if(CONSTRUCTION_WIRES_EXPOSED)
			if(istype(C, /obj/item/weapon/wirecutters))
				playsound(get_turf(src), 'sound/items/Wirecutter.ogg', 50, 1)
				user.visible_message("[user] starts cutting the wires from [src]...", \
									 "You begin removing [src]'s wires...")
				if(!do_after(user, 60/C.toolspeed, target = src)) return
				if(constructionStep != CONSTRUCTION_WIRES_EXPOSED) return
				user.visible_message("[user] removes the wires from [src].", \
									 "You remove the wiring from [src], exposing the circuit board.")
				var/obj/item/stack/cable_coil/B = new(get_turf(src))
				B.amount = 5
				constructionStep = CONSTRUCTION_GUTTED
				update_icon()
				return
			if(istype(C, /obj/item/weapon/weldingtool))
				var/obj/item/weapon/weldingtool/W = C
				if(W.remove_fuel(1, user))
					playsound(get_turf(src), 'sound/items/Welder.ogg', 50, 1)
					user.visible_message("[user] starts welding a metal plate into [src]...", \
										 "You begin welding the cover plate back onto [src]...")
					if(!do_after(user, 80/C.toolspeed, target = src)) return
					if(constructionStep != CONSTRUCTION_WIRES_EXPOSED) return
					playsound(get_turf(src), 'sound/items/Welder2.ogg', 50, 1)
					user.visible_message("[user] welds the metal plate into [src].", \
										 "You weld [src]'s cover plate into place, hiding the wires.")
				constructionStep = CONSTRUCTION_PANEL_OPEN
				update_icon()
				return
		if(CONSTRUCTION_GUTTED)
			if(istype(C, /obj/item/weapon/crowbar))
				user.visible_message("[user] begins removing the circuit board from [src]...", \
									 "You begin prying out the circuit board from [src]...")
				playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
				if(!do_after(user, 50/C.toolspeed, target = src)) return
				if(constructionStep != CONSTRUCTION_GUTTED) return
				user.visible_message("[user] removes [src]'s circuit board.", \
									 "You remove the circuit board from [src].")
				new /obj/item/weapon/electronics/firelock(get_turf(src))
				playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
				constructionStep = CONSTRUCTION_NOCIRCUIT
				update_icon()
				return
			if(istype(C, /obj/item/stack/cable_coil))
				var/obj/item/stack/cable_coil/B = C
				if(B.amount < 5)
					user << "You need more wires to add wiring to [src]."
					return
				user.visible_message("[user] begins wiring [src]...", \
									 "You begin adding wires to [src]...")
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				if(!do_after(user, 60, target = src)) return
				if(constructionStep != CONSTRUCTION_GUTTED) return
				user.visible_message("[user] adds wires to [src].", \
									 "You wire [src].")
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				B.use(5)
				constructionStep = CONSTRUCTION_WIRES_EXPOSED
				update_icon()
				return
		if(CONSTRUCTION_NOCIRCUIT)
			if(istype(C, /obj/item/weapon/weldingtool))
				var/obj/item/weapon/weldingtool/W = C
				if(W.remove_fuel(1,user))
					playsound(get_turf(src), 'sound/items/Welder.ogg', 50, 1)
					user.visible_message("[user] begins cutting apart [src]'s frame...", \
										 "You begin slicing [src] apart...")
					if(!do_after(user, 80/C.toolspeed, target = src)) return
					if(constructionStep != CONSTRUCTION_NOCIRCUIT) return
					user.visible_message("[user] cuts apart [src]!", \
										 "You cut [src] into metal.")
					playsound(get_turf(src), 'sound/items/Welder2.ogg', 50, 1)
					var/obj/item/stack/sheet/metal/M = new(get_turf(src))
					M.amount = 3
					qdel(src)
				return
			if(istype(C, /obj/item/weapon/electronics/firelock))
				user.visible_message("[user] starts adding [C] to [src]...", \
									 "You begin adding a circuit board to [src]...")
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				if(!do_after(user, 40, target = src)) return
				if(constructionStep != CONSTRUCTION_NOCIRCUIT) return
				user.drop_item()
				qdel(C)
				user.visible_message("[user] adds a circuit to [src].", \
									 "You insert and secure [C].")
				playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1)
				constructionStep = CONSTRUCTION_GUTTED
				update_icon()
				return


code:
/obj/machinery/door/poddoor
	name = "blast door"
	desc = "A heavy duty blast door that opens mechanically."
	icon = 'icons/obj/doors/blastdoor.dmi'
	icon_state = "closed"
	var/id = 1
	var/auto_close = 0 // Time in seconds to automatically close when opened, 0 if it doesn't.
	sub_door = 1
	explosion_block = 3
	heat_proof = 1

/obj/machinery/door/poddoor/preopen
	icon_state = "open"
	density = 0
	opacity = 0

/obj/machinery/door/poddoor/ert
	desc = "A heavy duty blast door that only opens for dire emergencies."

/obj/machinery/door/poddoor/shuttledock //special poddoors that open when emergency shuttle docks at centcom
	var/checkdir = 4	//door won't open if turf in this dir is space

/obj/machinery/door/poddoor/Bumped(atom/AM)
	if(density)
		return 0
	else
		return ..()

/obj/machinery/door/poddoor/attackby(obj/item/I, mob/user, params)
	add_fingerprint(user)

	if(istype(I, /obj/item/weapon/twohanded/fireaxe))
		var/obj/item/weapon/twohanded/fireaxe/F = I
		if(!F.wielded)
			return
	else if(!istype(I, /obj/item/weapon/crowbar))
		return

	if(stat & NOPOWER)
		open(1)	//ignore the usual power requirement.

/obj/machinery/door/poddoor/open(ignorepower = 0)
	if(operating)
		return
	if(!density)
		return
	if(!ignorepower && (stat & NOPOWER))
		return

	operating = 1
	flick("opening", src)
	icon_state = "open"
	SetOpacity(0)
	sleep(5)
	density = 0
	sleep(5)
	air_update_turf(1)
	update_freelook_sight()
	operating = 0

	if(auto_close)
		spawn(auto_close)
			// Checks for being able to close are in close().
			close()

	return 1

/obj/machinery/door/poddoor/close(ignorepower = 0)
	if(operating)
		return
	if(density)
		return
	if(!ignorepower && (stat & NOPOWER))
		return

	operating = 1
	flick("closing", src)
	icon_state = "closed"
	SetOpacity(1)
	sleep(5)
	density = 1
	sleep(5)
	air_update_turf(1)
	update_freelook_sight()
	sleep(5)
	crush()
	sleep(5)
	operating = 0

//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS.
/obj/machinery/door/poddoor/ex_act(severity, target)
	if(target == src)
		qdel(src)
		return
	switch(severity)
		if(1)
			if(prob(80))
				qdel(src)
			else
				var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
				s.set_up(2, 1, src)
				s.start()
		if(2)
			if(prob(20))
				qdel(src)
			else
				var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
				s.set_up(2, 1, src)
				s.start()

		if(3)
			if(prob(80))
				var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
				s.set_up(2, 1, src)
				s.start()

/obj/machinery/door/poddoor/update_icon()
	if(density)
		icon_state = "closed"
	else
		icon_state = "open"


code:
/obj/machinery/door/poddoor/shutters
	gender = PLURAL
	name = "shutters"
	desc = "Heavy duty metal shutters that opens mechanically."
	icon = 'icons/obj/doors/shutters.dmi'
	layer = 3.1

/obj/machinery/door/poddoor/shutters/preopen
	icon_state = "open"
	density = 0
	opacity = 0

//shutters look like ass with things on top of them.

/obj/machinery/door/poddoor/shutters/New()
	..()
	layer = 3.1	//to handle /obj/machinery/door/New() resetting the layer.

/obj/machinery/door/poddoor/shutters/open(ignorepower = 0)
	..()
	layer = 3.1

/obj/machinery/door/poddoor/shutters/close(ignorepower = 0)
	..()
	layer = 3.1


code:
/obj/machinery/door/unpowered
	var/locked = 0

/obj/machinery/door/unpowered/Bumped(atom/AM)
	if(src.locked)
		return
	..()
	return

/obj/machinery/door/unpowered/attackby(obj/item/I, mob/user, params)
	if(src.locked)
		return
	..()
	return

/obj/machinery/door/unpowered/emag_act()
	return

/obj/machinery/door/unpowered/shuttle
	icon = 'icons/turf/shuttle.dmi'
	name = "door"
	icon_state = "door1"
	opacity = 1
	density = 1
	explosion_block = 1


code:
/obj/machinery/door/window
	name = "interior door"
	desc = "A strong door."
	icon = 'icons/obj/doors/windoor.dmi'
	icon_state = "left"
	var/base_state = "left"
	var/health = 150 //If you change this, consider changing ../door/window/brigdoor/ health at the bottom of this .dm file
	visible = 0
	flags = ON_BORDER
	opacity = 0
	var/obj/item/weapon/electronics/airlock/electronics = null
	var/reinf = 0

/obj/machinery/door/window/New()
	..()

	if (src.req_access && src.req_access.len)
		src.icon_state = "[src.icon_state]"
		src.base_state = src.icon_state
	return

/obj/machinery/door/window/Destroy()
	density = 0
	if(health == 0)
		playsound(src, "shatter", 70, 1)
	electronics = null
	return ..()

/obj/machinery/door/window/update_icon()
	if(density)
		icon_state = base_state
	else
		icon_state = "[src.base_state]open"

/obj/machinery/door/window/proc/open_and_close()
	open()
	if(src.check_access(null))
		sleep(50)
	else //secure doors close faster
		sleep(20)
	close()

/obj/machinery/door/window/Bumped(atom/movable/AM as mob|obj)
	if( operating || !src.density )
		return
	if (!( ismob(AM) ))
		if(istype(AM, /obj/mecha))
			var/obj/mecha/mecha = AM
			if(mecha.occupant && src.allowed(mecha.occupant))
				open_and_close()
			else
				flick("[src.base_state]deny", src)
		return
	if (!( ticker ))
		return
	var/mob/M = AM
	if(!M.restrained())
		bumpopen(M)
	return

/obj/machinery/door/window/bumpopen(mob/user)
	if( operating || !src.density )
		return
	src.add_fingerprint(user)
	if(!src.requiresID())
		user = null

	if(allowed(user))
		open_and_close()
	else
		flick("[src.base_state]deny", src)
	return

/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	if(get_dir(loc, target) == dir) //Make sure looking at appropriate border
		return !density
	else
		return 1

/obj/machinery/door/window/CanAtmosPass(turf/T)
	if(get_dir(loc, T) == dir)
		return !density
	else
		return 1

//used in the AStar algorithm to determinate if the turf the door is on is passable
/obj/machinery/door/window/CanAStarPass(obj/item/weapon/card/id/ID, to_dir)
	return !density || (dir != to_dir) || (check_access(ID) && hasPower())

/obj/machinery/door/window/CheckExit(atom/movable/mover as mob|obj, turf/target)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	if(get_dir(loc, target) == dir)
		return !density
	else
		return 1

/obj/machinery/door/window/open(forced=0)
	if (src.operating == 1) //doors can still open when emag-disabled
		return 0
	if(!ticker || !ticker.mode)
		return 0
	if(!forced)
		if(!hasPower())
			return 0
	if(forced < 2)
		if(emagged)
			return 0
	if(!src.operating) //in case of emag
		src.operating = 1
	flick("[src.base_state]opening", src)
	playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
	src.icon_state ="[src.base_state]open"
	sleep(10)

	src.density = 0
//	src.sd_SetOpacity(0)	//TODO: why is this here? Opaque windoors? ~Carn
	air_update_turf(1)
	update_freelook_sight()

	if(operating == 1) //emag again
		src.operating = 0
	return 1

/obj/machinery/door/window/close(forced=0)
	if (src.operating)
		return 0
	if(!forced)
		if(!hasPower())
			return 0
	if(forced < 2)
		if(emagged)
			return 0
	src.operating = 1
	flick("[src.base_state]closing", src)
	playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
	src.icon_state = src.base_state

	src.density = 1
//	if(src.visible)
//		SetOpacity(1)	//TODO: why is this here? Opaque windoors? ~Carn
	air_update_turf(1)
	update_freelook_sight()
	sleep(10)

	src.operating = 0
	return 1

/obj/machinery/door/window/proc/take_damage(damage)
	src.health = max(0, src.health - damage)
	if (src.health <= 0)
		if(!(flags&NODECONSTRUCT))
			var/debris = list(
				new /obj/item/weapon/shard(src.loc),
				new /obj/item/weapon/shard(src.loc),
				new /obj/item/stack/rods(src.loc, 2),
				new /obj/item/stack/cable_coil(src.loc, 2)
				)
			for(var/obj/fragment in debris)
				transfer_fingerprints_to(fragment)
		src.density = 0
		qdel(src)
		return

/obj/machinery/door/window/ex_act(severity, target)
	switch(severity)
		if(1)
			qdel(src)
		if(2)
			if(prob(25))
				qdel(src)
			else
				take_damage(120)
		if(3)
			take_damage(60)

/obj/machinery/door/window/narsie_act()
	color = "#7D1919"

/obj/machinery/door/window/bullet_act(obj/item/projectile/Proj)
	if(Proj.damage)
		if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
			take_damage(round(Proj.damage / 2))
	..()

/obj/machinery/door/window/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
	if(exposed_temperature > T0C + (reinf ? 1600 : 800))
		take_damage(round(exposed_volume / 200))
	..()

//When an object is thrown at the window
/obj/machinery/door/window/hitby(AM as mob|obj)

	..()
	var/tforce = 0
	if(ismob(AM))
		tforce = 40
	else
		tforce = AM:throwforce
	playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1)
	take_damage(tforce)
	//..() //Does this really need to be here twice? The parent proc doesn't even do anything yet. - Nodrak
	return

/obj/machinery/door/window/mech_melee_attack(obj/mecha/M)
	if(M.damtype == "brute")
		playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
		visible_message("[M.name] has hit [src].")
		take_damage(M.force)
	return

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

/obj/machinery/door/window/proc/attack_generic(mob/user, damage = 0)
	if(src.operating)
		return
	user.changeNext_move(CLICK_CD_MELEE)
	playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
	user.visible_message("[user] smashes against the [src.name]!", \
				"You smash against the [src.name]!")
	take_damage(damage)

/obj/machinery/door/window/attack_alien(mob/living/user)
	user.do_attack_animation(src)
	if(islarva(user))
		return
	attack_generic(user, 25)

/obj/machinery/door/window/attack_animal(mob/living/user)
	if(!isanimal(user))
		return
	var/mob/living/simple_animal/M = user
	M.do_attack_animation(src)
	if(M.melee_damage_upper > 0 && (M.melee_damage_type == BRUTE || M.melee_damage_type == BURN))
		attack_generic(M, M.melee_damage_upper)

/obj/machinery/door/window/attack_slime(mob/living/simple_animal/slime/user)
	user.do_attack_animation(src)
	if(!user.is_adult)
		return
	attack_generic(user, 25)

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

/obj/machinery/door/window/attack_hand(mob/user)
	return src.attackby(user, user)

/obj/machinery/door/window/emag_act(mob/user)
	if(!operating && density && !emagged)
		operating = 1
		flick("[src.base_state]spark", src)
		sleep(6)
		operating = 0
		desc += "
Its access panel is smoking slightly."
		open()
		emagged = 1

/obj/machinery/door/window/attackby(obj/item/weapon/I, mob/living/user, params)

	//If it's in the process of opening/closing, ignore the click
	if (src.operating)
		return

	if(istype(I, /obj/item/weapon/card/emag))
		return

	add_fingerprint(user)

	if(!(flags&NODECONSTRUCT))
		if(istype(I, /obj/item/weapon/screwdriver))
			if(src.density || src.operating)
				user << "You need to open the door to access the maintenance panel!"
				return
			playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
			src.p_open = !( src.p_open )
			user << "You [p_open ? "open":"close"] the maintenance panel of the [src.name]."
			return

		if(istype(I, /obj/item/weapon/crowbar))
			if(p_open && !src.density && !src.operating)
				playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
				user.visible_message("[user] removes the electronics from the [src.name].", \
									 "You start to remove electronics from the [src.name]...")
				if(do_after(user,40/I.toolspeed, target = src))
					if(src.p_open && !src.density && !src.operating && src.loc)
						var/obj/structure/windoor_assembly/WA = new /obj/structure/windoor_assembly(src.loc)
						switch(base_state)
							if("left")
								WA.facing = "l"
							if("right")
								WA.facing = "r"
							if("leftsecure")
								WA.facing = "l"
								WA.secure = 1
							if("rightsecure")
								WA.facing = "r"
								WA.secure = 1
						WA.anchored = 1
						WA.state= "02"
						WA.dir = src.dir
						WA.ini_dir = src.dir
						WA.update_icon()
						WA.created_name = src.name

						if(emagged)
							user << "You discard the damaged electronics."
							qdel(src)
							return

						user << "You remove the airlock electronics."

						var/obj/item/weapon/electronics/airlock/ae
						if(!electronics)
							ae = new/obj/item/weapon/electronics/airlock( src.loc )
							if(req_one_access)
								ae.one_access = 1
								ae.accesses = src.req_one_access
							else
								ae.accesses = src.req_access
						else
							ae = electronics
							electronics = null
							ae.loc = src.loc

						qdel(src)
				return

	//If windoor is unpowered, crowbar, fireaxe and armblade can force it.
	if(istype(I, /obj/item/weapon/crowbar) || istype(I, /obj/item/weapon/twohanded/fireaxe) || istype(I, /obj/item/weapon/melee/arm_blade) )
		if(!hasPower())
			if(src.density)
				open(2)
			else
				close(2)
			return

	//If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway)
	if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card) )
		user.changeNext_move(CLICK_CD_MELEE)
		user.do_attack_animation(src)
		if( (I.flags&NOBLUDGEON) || !I.force )
			return
		var/aforce = I.force
		playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
		visible_message("[user] has hit \the [src] with [I].")
		if(I.damtype == BURN || I.damtype == BRUTE)
			take_damage(aforce)
		return

	if (!src.requiresID())
		//don't care who they are or what they have, act as if they're NOTHING
		user = null

	if (src.allowed(user))
		if (src.density)
			open()
		else
			close()

	else if (src.density)
		flick("[src.base_state]deny", src)

	return

/obj/machinery/door/window/attack_hulk(mob/user)
	..(user, 1)
	user.visible_message("[user] smashes through the windoor!", \
						"You tear through the windoor!")
	user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
	playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
	take_damage(health)

/obj/machinery/door/window/brigdoor
	name = "secure door"
	icon = 'icons/obj/doors/windoor.dmi'
	icon_state = "leftsecure"
	base_state = "leftsecure"
	var/id = null
	health = 300 //Stronger doors for prison (regular window door health is 200)
	reinf = 1
	explosion_block = 1

/obj/machinery/door/window/northleft
	dir = NORTH

/obj/machinery/door/window/eastleft
	dir = EAST

/obj/machinery/door/window/westleft
	dir = WEST

/obj/machinery/door/window/southleft
	dir = SOUTH

/obj/machinery/door/window/northright
	dir = NORTH
	icon_state = "right"
	base_state = "right"

/obj/machinery/door/window/eastright
	dir = EAST
	icon_state = "right"
	base_state = "right"

/obj/machinery/door/window/westright
	dir = WEST
	icon_state = "right"
	base_state = "right"

/obj/machinery/door/window/southright
	dir = SOUTH
	icon_state = "right"
	base_state = "right"

/obj/machinery/door/window/brigdoor/northleft
	dir = NORTH

/obj/machinery/door/window/brigdoor/eastleft
	dir = EAST

/obj/machinery/door/window/brigdoor/westleft
	dir = WEST

/obj/machinery/door/window/brigdoor/southleft
	dir = SOUTH

/obj/machinery/door/window/brigdoor/northright
	dir = NORTH
	icon_state = "rightsecure"
	base_state = "rightsecure"

/obj/machinery/door/window/brigdoor/eastright
	dir = EAST
	icon_state = "rightsecure"
	base_state = "rightsecure"

/obj/machinery/door/window/brigdoor/westright
	dir = WEST
	icon_state = "rightsecure"
	base_state = "rightsecure"

/obj/machinery/door/window/brigdoor/southright
	dir = SOUTH
	icon_state = "rightsecure"
	base_state = "rightsecure"


code:
var/list/doppler_arrays = list()

/obj/machinery/doppler_array
	name = "tachyon-doppler array"
	desc = "A highly precise directional sensor array which measures the release of quants from decaying tachyons. The doppler shifting of the mirror-image formed by these quants can reveal the size, location and temporal affects of energetic disturbances within a large radius ahead of the array.\nAlt-click to rotate it clockwise."
	icon = 'icons/obj/machines/research.dmi'
	icon_state = "tdoppler"
	density = 1
	anchored = 1
	var/integrated = 0
	var/max_dist = 100
	verb_say = "states coldly"

/obj/machinery/doppler_array/New()
	..()
	doppler_arrays += src

/obj/machinery/doppler_array/Destroy()
	doppler_arrays -= src
	return ..()

/obj/machinery/doppler_array/process()
	return PROCESS_KILL

/obj/machinery/doppler_array/attackby(obj/item/O, mob/user, params)
	if(istype(O, /obj/item/weapon/wrench))
		if(!anchored && !isinspace())
			anchored = 1
			power_change()
			user << "You fasten [src]."
		else if(anchored)
			anchored = 0
			power_change()
			user << "You unfasten [src]."
		playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
	else
		..()

/obj/machinery/doppler_array/verb/rotate()
	set name = "Rotate Tachyon-doppler Dish"
	set category = "Object"
	set src in oview(1)

	if(!usr || !isturf(usr.loc))
		return
	if(usr.stat || usr.restrained() || !usr.canmove)
		return
	src.dir = turn(src.dir, 90)
	return

/obj/machinery/doppler_array/AltClick(mob/living/user)
	if(!istype(user) || user.incapacitated())
		user << "You can't do that right now!"
		return
	if(!in_range(src, user))
		return
	else
		rotate()

/obj/machinery/doppler_array/proc/sense_explosion(turf/epicenter,devastation_range,heavy_impact_range,light_impact_range,
												  took,orig_dev_range,orig_heavy_range,orig_light_range)
	if(stat & NOPOWER)
		return
	var/turf/zone = get_turf(src)

	if(zone.z != epicenter.z)
		return

	var/distance = get_dist(epicenter, zone)
	var/direct = get_dir(zone, epicenter)

	if(distance > max_dist)
		return
	if(!(direct & dir) && !integrated)
		return

	var/list/messages = list("Explosive disturbance detected.", \
							 "Epicenter at: grid ([epicenter.x],[epicenter.y]). Temporal displacement of tachyons: [took] seconds.", \
							 "Factual: Epicenter radius: [devastation_range]. Outer radius: [heavy_impact_range]. Shockwave radius: [light_impact_range].")

	// If the bomb was capped, say it's theoretical size.
	if(devastation_range < orig_dev_range || heavy_impact_range < orig_heavy_range || light_impact_range < orig_light_range)
		messages += "Theoretical: Epicenter radius: [orig_dev_range]. Outer radius: [orig_heavy_range]. Shockwave radius: [orig_light_range]."

	if(integrated)
		var/obj/item/clothing/head/helmet/space/hardsuit/helm = loc
		if(!helm || !istype(helm, /obj/item/clothing/head/helmet/space/hardsuit))
			return
		helm.display_visor_message("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]")
	else
		for(var/message in messages)
			say(message)

/obj/machinery/doppler_array/power_change()
	if(stat & BROKEN)
		icon_state = "[initial(icon_state)]-broken"
	else
		if(powered() && anchored)
			icon_state = initial(icon_state)
			stat &= ~NOPOWER
		else
			icon_state = "[initial(icon_state)]-off"
			stat |= NOPOWER

//Portable version, built into EOD equipment. It simply provides an explosion's three damage levels.
/obj/machinery/doppler_array/integrated
	name = "integrated tachyon-doppler module"
	integrated = 1
	max_dist = 21 //Should detect most explosions in hearing range.
	use_power = 0


code:
/obj/machinery/droneDispenser //Most customizable machine 2015
	name = "drone shell dispenser"
	desc = "A hefty machine that, when supplied with metal and glass, will periodically create a drone shell. Does not need to be manually operated."
	icon = 'icons/obj/machines/droneDispenser.dmi'
	icon_state = "on"
	anchored = 1
	density = 1

	var/health = 100 //The health of the drone dispenser. It will break if it goes below 0
	var/max_health = 100

	var/icon_off = "off" //These variables allow for different icons when creating custom dispensers
	var/icon_on = "on"
	var/icon_recharging = "recharge"
	var/icon_creating = "make"

	var/metal = 0
	var/glass = 0
	var/metal_cost = 1000
	var/glass_cost = 1000
	var/power_used = 1000

	var/droneMadeRecently = 0
	var/cooldownTime = 1800 //3 minutes
	var/dispense_type = /obj/item/drone_shell //The item the dispenser will create

	var/work_sound = 'sound/items/rped.ogg'
	var/create_sound = 'sound/items/Deconstruct.ogg'
	var/recharge_sound = 'sound/machines/ping.ogg'

	var/begin_create_message = "whirs to life!"
	var/end_create_message = "dispenses a drone shell."
	var/recharge_message = "pings."
	var/recharging_text = "It is whirring and clicking. It seems to be recharging."

	var/break_message = "lets out a tinny alarm before falling dark."
	var/break_sound = 'sound/machines/warning-buzzer.ogg'

/obj/machinery/droneDispenser/New()
	..()
	health = max_health
	SSmachine.processing |= src

/obj/machinery/droneDispenser/Destroy()
	SSmachine.processing -= src
	return ..()

/obj/machinery/droneDispenser/preloaded
	metal = 5000
	glass = 5000

/obj/machinery/droneDispenser/syndrone //Please forgive me
	name = "syndrone shell dispenser"
	desc = "A suspicious machine that will create Syndicate exterminator drones when supplied with metal and glass. Disgusting."
	metal = 25000
	glass = 25000
	dispense_type = /obj/item/drone_shell/syndrone
	cooldownTime = 100 //If we're gonna be a jackass, go the full mile - 10 second recharge timer
	end_create_message = "dispenses a suspicious drone shell."

/obj/machinery/droneDispenser/syndrone/badass //Please forgive me
	name = "badass syndrone shell dispenser"
	desc = "A suspicious machine that will create Syndicate exterminator drones when supplied with metal and glass. Disgusting. This one seems ominous."
	dispense_type = /obj/item/drone_shell/syndrone/badass
	end_create_message = "dispenses a ominous suspicious drone shell."

/obj/machinery/droneDispenser/hivebot //An example of a custom drone dispenser. This one requires no materials and creates basic hivebots
	name = "hivebot fabricator"
	desc = "A large, bulky machine that whirs with activity, steam hissing from vents in its sides."
	icon = 'icons/obj/objects.dmi'
	icon_state = "hivebot_fab"
	icon_off = "hivebot_fab"
	icon_on = "hivebot_fab"
	icon_recharging = "hivebot_fab"
	icon_creating = "hivebot_fab_on"
	metal_cost = 0
	glass_cost = 0
	power_used = 0
	cooldownTime = 10 //Only 1 second - hivebots are extremely weak
	dispense_type = /mob/living/simple_animal/hostile/hivebot
	begin_create_message = "closes and begins fabricating something within."
	end_create_message = "slams open, revealing out a hivebot!"
	recharge_sound = null
	recharge_message = null

/obj/machinery/droneDispenser/swarmer
	name = "swarmer fabricator"
	desc = "An alien machine of unknown origin. It whirs and hums with green-blue light, the air above it shimmering."
	icon = 'icons/obj/machines/gateway.dmi'
	icon_state = "toffcenter"
	icon_off = "toffcenter"
	icon_on = "toffcenter"
	icon_recharging = "toffcenter"
	icon_creating = "offcenter"
	metal_cost = 0
	glass_cost = 0
	cooldownTime = 300 //30 seconds
	dispense_type = /obj/item/unactivated_swarmer
	begin_create_message = "hums softly as an interface appears above it, scrolling by at unreadable speed."
	end_create_message = "materializes a strange shell, which drops to the ground."
	recharging_text = "Its lights are slowly increasing in brightness."
	work_sound = 'sound/effects/EMPulse.ogg'
	create_sound = 'sound/effects/phasein.ogg'
	break_sound = 'sound/effects/EMPulse.ogg'
	break_message = "slowly falls dark, lights stuttering."

/obj/machinery/droneDispenser/examine(mob/user)
	..()
	if(droneMadeRecently && !stat && recharging_text)
		user << "[recharging_text]"
	if(stat & BROKEN)
		user << "[src] is smoking and steadily buzzing. It seems to be broken."
	if(metal_cost)
		user << "It has [metal] units of metal stored."
	if(glass_cost)
		user << "It has [glass] units of glass stored."

/obj/machinery/droneDispenser/power_change()
	..()
	if(stat & BROKEN)
		return
	else
		if(powered())
			stat &= ~NOPOWER
		else
			icon_state = "off"
			stat |= NOPOWER

/obj/machinery/droneDispenser/process()
	..()
	if(stat & (NOPOWER|BROKEN) || !anchored)
		return
	if((metal_cost && glass_cost) && (metal < metal_cost || glass < glass_cost))
		return
	if(droneMadeRecently)
		icon_state = icon_recharging
		return
	droneMadeRecently = 1
	if(begin_create_message)
		visible_message("[src] [begin_create_message]")
	if(work_sound)
		playsound(src, work_sound, 50, 1)
	icon_state = icon_creating
	sleep(30)
	icon_state = icon_on
	metal -= metal_cost
	glass -= glass_cost
	if(metal < 0)
		metal = 0
	if(glass < 0)
		glass = 0
	if(power_used)
		use_power(power_used)
	new dispense_type(loc)
	if(create_sound)
		playsound(src, create_sound, 50, 1)
	if(end_create_message)
		visible_message("[src] [end_create_message]")
	icon_state = icon_recharging
	sleep(cooldownTime)
	if(stat != BROKEN)
		icon_state = icon_on
	else
		icon_state = icon_off
	droneMadeRecently = 0
	if(recharge_sound)
		playsound(src, recharge_sound, 50, 1)
	if(recharge_message)
		visible_message("[src] [recharge_message]")

/obj/machinery/droneDispenser/attackby(obj/item/O, mob/living/user)
	if(istype(O, /obj/item/stack))
		if(!O.materials[MAT_METAL] && !O.materials[MAT_GLASS])
			return ..()
		if(!metal_cost && !glass_cost)
			user << "There isn't a place to insert [O]!"
			return
		var/stack = 1
		var/obj/item/stack/sheets
		sheets = O
		stack = (input(user, "How many sheets do you want to add?.", "Drone Dispenser", "[stack]") as num)
		if(stack <= 0)
			return
		if(!user.canUseTopic(src))
			return
		stack = Clamp(stack, 0, sheets.max_amount)
		sheets.use(stack)
		if(!stack)
			if(!user.unEquip(O))
				user << "[O] is stuck to your hand, you can't get it off!"
				return
			user.drop_item()
			O.loc = src
		metal += O.materials[MAT_METAL] * stack
		glass += O.materials[MAT_GLASS] * stack
		user << "You insert [stack] sheet[stack > 1 ? "s" : ""] to [src]."
		if((O && O.loc == src) || !stack)
			qdel(O)
		return
	if(istype(O, /obj/item/weapon/weldingtool) && (stat & BROKEN))
		var/obj/item/weapon/weldingtool/WT = O
		if(!WT.isOn())
			return
		if(WT.get_fuel() < 1)
			user << "You need more fuel to complete this task!"
			return
		playsound(src, 'sound/items/Welder.ogg', 50, 1)
		user.visible_message("[user] begins patching up [src] with [WT].", \
							 "You begin restoring the damage to [src]...")
		if(!do_after(user, 40/O.toolspeed, target = src))
			return
		if(!src || !WT.remove_fuel(1, user)) return
		user.visible_message("[user] fixes [src]!", \
							 "You restore [src] to operation.")
		stat -= BROKEN
		icon_state = icon_on
		return
	if(O.force && stat != BROKEN)
		user.visible_message("[user] hits [src] with [O]!", \
							 "You hit [src] with [O]!")
		playsound(src, O.hitsound, 50, 1)
		health = Clamp(health - O.force, 0, max_health)
		if(health <= 0)
			if(break_message)
				audible_message("[src] [break_message]")
			if(break_sound)
				playsound(src, break_sound, 50, 1)
			stat = BROKEN
			icon_state = icon_off
		return
	..()


code:
#define CLOSING			1
#define OPENING			2
#define CYCLE			3
#define CYCLE_EXTERIOR	4
#define CYCLE_INTERIOR	5

/obj/machinery/doorButtons
	power_channel = ENVIRON
	anchored = 1
	use_power = 1
	idle_power_usage = 2
	active_power_usage = 4
	var/idSelf

/obj/machinery/doorButtons/attackby(obj/O, mob/user)
	attack_hand(user)

/obj/machinery/doorButtons/proc/findObjsByTag()
	return

/obj/machinery/doorButtons/initialize()
	findObjsByTag()

/obj/machinery/doorButtons/emag_act(mob/user)
	if(!emagged)
		emagged = 1
		req_access = list()
		req_one_access = list()
		playsound(src.loc, "sparks", 100, 1)
		user << "You short out the access controller."

/obj/machinery/doorButtons/proc/removeMe()

/obj/machinery/doorButtons/access_button
	icon = 'icons/obj/airlock_machines.dmi'
	icon_state = "access_button_standby"
	name = "access button"
	var/idDoor
	var/obj/machinery/door/airlock/door
	var/obj/machinery/doorButtons/airlock_controller/controller
	var/busy

/obj/machinery/doorButtons/access_button/findObjsByTag()
	for(var/obj/machinery/doorButtons/airlock_controller/A in machines)
		if(A.idSelf == idSelf)
			controller = A
			break
	for(var/obj/machinery/door/airlock/I in machines)
		if(I.id_tag == idDoor)
			door = I
			break

/obj/machinery/doorButtons/access_button/attack_hand(mob/user)
	if(..())
		return
	if(busy)
		return
	if(!allowed(user))
		user << "Access denied."
		return
	if(controller && !controller.busy && door)
		if(controller.stat & NOPOWER)
			return
		busy = 1
		update_icon()
		if(door.density)
			if(!controller.exteriorAirlock || !controller.interiorAirlock)
				controller.onlyOpen(door)
			else
				if(controller.exteriorAirlock.density && controller.interiorAirlock.density)
					controller.onlyOpen(door)
				else
					controller.cycleClose(door)
		else
			controller.onlyClose(door)
		sleep(20)
		busy = 0
		update_icon()

/obj/machinery/doorButtons/access_button/update_icon()
	if(stat & NOPOWER)
		icon_state = "access_button_off"
	else
		if(busy)
			icon_state = "access_button_cycle"
		else
			icon_state = "access_button_standby"

/obj/machinery/doorButtons/access_button/power_change()
	..()
	update_icon()

/obj/machinery/doorButtons/access_button/removeMe(obj/O)
	if(O == door)
		door = null

/obj/machinery/doorButtons/airlock_controller
	icon = 'icons/obj/airlock_machines.dmi'
	icon_state = "access_control_standby"
	name = "access console"
	var/obj/machinery/door/airlock/interiorAirlock
	var/obj/machinery/door/airlock/exteriorAirlock
	var/idInterior
	var/idExterior
	var/busy
	var/lostPower

/obj/machinery/doorButtons/airlock_controller/removeMe(obj/O)
	if(O == interiorAirlock)
		interiorAirlock = null
	else if(O == exteriorAirlock)
		exteriorAirlock = null

/obj/machinery/doorButtons/airlock_controller/Destroy()
	for(var/obj/machinery/doorButtons/access_button/A in machines)
		if(A.controller == src)
			A.controller = null
	return ..()

/obj/machinery/doorButtons/airlock_controller/Topic(href, href_list)
	if(..())
		return
	if(busy)
		return
	if(!allowed(usr))
		usr << "Access denied."
		return
	switch(href_list["command"])
		if("close_exterior")
			onlyClose(exteriorAirlock)
		if("close_interior")
			onlyClose(interiorAirlock)
		if("cycle_exterior")
			cycleClose(exteriorAirlock)
		if("cycle_interior")
			cycleClose(interiorAirlock)
		if("open_exterior")
			onlyOpen(exteriorAirlock)
		if("open_interior")
			onlyOpen(interiorAirlock)

/obj/machinery/doorButtons/airlock_controller/proc/onlyOpen(obj/machinery/door/airlock/A)
	if(A)
		busy = CLOSING
		update_icon()
		openDoor(A)

/obj/machinery/doorButtons/airlock_controller/proc/onlyClose(obj/machinery/door/airlock/A)
	if(A)
		busy = CLOSING
		closeDoor(A)

/obj/machinery/doorButtons/airlock_controller/proc/closeDoor(obj/machinery/door/airlock/A)
	if(A.density)
		goIdle()
		return 0
	update_icon()
	A.unbolt()
	spawn()
		if(A && A.close())
			if(stat & NOPOWER || lostPower || !A || qdeleted(A))
				goIdle(1)
				return
			A.bolt()
			if(busy == CLOSING)
				goIdle(1)
		else
			goIdle(1)
	return 1

/obj/machinery/doorButtons/airlock_controller/proc/cycleClose(obj/machinery/door/airlock/A)
	if(!A || !exteriorAirlock || !interiorAirlock)
		return
	if(exteriorAirlock.density == interiorAirlock.density || !A.density)
		return
	busy = CYCLE
	update_icon()
	if(A == interiorAirlock)
		if(closeDoor(exteriorAirlock))
			busy = CYCLE_INTERIOR
	else
		if(closeDoor(interiorAirlock))
			busy = CYCLE_EXTERIOR

/obj/machinery/doorButtons/airlock_controller/proc/cycleOpen(obj/machinery/door/airlock/A)
	if(!A)
		goIdle(1)
	if(A == exteriorAirlock)
		if(interiorAirlock)
			if(!interiorAirlock.density || !interiorAirlock.locked)
				return
	else
		if(exteriorAirlock)
			if(!exteriorAirlock.density || !exteriorAirlock.locked)
				return
	if(busy != OPENING)
		busy = OPENING
		openDoor(A)

/obj/machinery/doorButtons/airlock_controller/proc/openDoor(obj/machinery/door/airlock/A)
	if(exteriorAirlock && interiorAirlock && (!exteriorAirlock.density || !interiorAirlock.density))
		goIdle(1)
		return
	A.unbolt()
	spawn()
		if(A && A.open())
			if(stat | (NOPOWER) && !lostPower && A && !qdeleted(A))
				A.bolt()
		goIdle(1)

/obj/machinery/doorButtons/airlock_controller/proc/goIdle(update)
	lostPower = 0
	busy = 0
	if(update)
		update_icon()
	updateUsrDialog()

/obj/machinery/doorButtons/airlock_controller/process()
	if(stat & NOPOWER)
		return
	if(busy == CYCLE_EXTERIOR)
		cycleOpen(exteriorAirlock)
	else if(busy == CYCLE_INTERIOR)
		cycleOpen(interiorAirlock)

/obj/machinery/doorButtons/airlock_controller/power_change()
	..()
	if(stat & NOPOWER)
		lostPower = 1
	else
		if(!busy)
			lostPower = 0
	update_icon()

/obj/machinery/doorButtons/airlock_controller/findObjsByTag()
	for(var/obj/machinery/door/airlock/A in machines)
		if(A.id_tag == idInterior)
			interiorAirlock = A
		else if(A.id_tag == idExterior)
			exteriorAirlock = A

/obj/machinery/doorButtons/airlock_controller/update_icon()
	if(stat & NOPOWER)
		icon_state = "access_control_off"
		return
	if(busy || lostPower)
		icon_state = "access_control_process"
	else
		icon_state = "access_control_standby"

/obj/machinery/doorButtons/airlock_controller/attack_hand(mob/user)
	if(..())
		return
	var/datum/browser/popup = new(user, "computer", name)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.set_content(returnText())
	popup.open()

/obj/machinery/doorButtons/airlock_controller/proc/returnText()
	var/output
	if(!exteriorAirlock && !interiorAirlock)
		return "ERROR ERROR ERROR ERROR"
	if(lostPower)
		output = "Initializing..."
	else
		if(!exteriorAirlock || !interiorAirlock)
			if(!exteriorAirlock)
				if(interiorAirlock.density)
					output = "Open Interior Airlock
"
				else
					output = "Close Interior Airlock
"
			else
				if(exteriorAirlock.density)
					output = "Open Exterior Airlock
"
				else
					output = "Close Exterior Airlock
"
		else
			if(exteriorAirlock.density)
				if(interiorAirlock.density)
					output = {"Open Exterior Airlock

					Open Interior Airlock
"}
				else
					output = {"Cycle to Exterior Airlock

					Close Interior Airlock
"}
			else
				if(interiorAirlock.density)
					output = {"Close Exterior Airlock

					Cycle to Interior Airlock
"}
				else
					output = {"Close Exterior Airlock

					Close Interior Airlock
"}

	output = {"Access Control Console

				[output]
"}
	if(exteriorAirlock)
		output += "Exterior Door:  [exteriorAirlock.density ? "closed" : "open"]
"
	if(interiorAirlock)
		output += "Interior Door:  [interiorAirlock.density ? "closed" : "open"]
"

	return output

#undef CLOSING
#undef OPENING
#undef CYCLE
#undef CYCLE_EXTERIOR
#undef CYCLE_INTERIOR


code:
//States for airlock_control
#define AIRLOCK_STATE_INOPEN		-2
#define AIRLOCK_STATE_PRESSURIZE	-1
#define AIRLOCK_STATE_CLOSED		0
#define AIRLOCK_STATE_DEPRESSURIZE	1
#define AIRLOCK_STATE_OUTOPEN		2

/datum/computer/file/embedded_program/airlock_controller
	var/id_tag
	var/exterior_door_tag
	var/interior_door_tag
	var/airpump_tag
	var/sensor_tag
	var/sanitize_external

	state = AIRLOCK_STATE_CLOSED
	var/target_state = AIRLOCK_STATE_CLOSED
	var/sensor_pressure = null

/datum/computer/file/embedded_program/airlock_controller/receive_signal(datum/signal/signal, receive_method, receive_param)
	var/receive_tag = signal.data["tag"]
	if(!receive_tag) return

	if(receive_tag==sensor_tag)
		if(signal.data["pressure"])
			sensor_pressure = text2num(signal.data["pressure"])

	else if(receive_tag==exterior_door_tag)
		memory["exterior_status"] = signal.data["door_status"]

	else if(receive_tag==interior_door_tag)
		memory["interior_status"] = signal.data["door_status"]

	else if(receive_tag==airpump_tag)
		if(signal.data["power"])
			memory["pump_status"] = signal.data["direction"]
		else
			memory["pump_status"] = "off"

	else if(receive_tag==id_tag)
		switch(signal.data["command"])
			if("cycle")
				if(state < AIRLOCK_STATE_CLOSED)
					target_state = AIRLOCK_STATE_OUTOPEN
				else
					target_state = AIRLOCK_STATE_INOPEN

/datum/computer/file/embedded_program/airlock_controller/receive_user_command(command)
	switch(command)
		if("cycle_closed")
			target_state = AIRLOCK_STATE_CLOSED
		if("cycle_exterior")
			target_state = AIRLOCK_STATE_OUTOPEN
		if("cycle_interior")
			target_state = AIRLOCK_STATE_INOPEN
		if("abort")
			target_state = AIRLOCK_STATE_CLOSED

/datum/computer/file/embedded_program/airlock_controller/process()
	var/process_again = 1
	while(process_again)
		process_again = 0
		switch(state)
			if(AIRLOCK_STATE_INOPEN) // state -2
				if(target_state > state)
					if(memory["interior_status"] == "closed")
						state = AIRLOCK_STATE_CLOSED
						process_again = 1
					else
						var/datum/signal/signal = new
						signal.data["tag"] = interior_door_tag
						signal.data["command"] = "secure_close"
						post_signal(signal)
				else
					if(memory["pump_status"] != "off")
						var/datum/signal/signal = new
						signal.data = list(
							"tag" = airpump_tag,
							"power" = 0,
							"sigtype"="command"
						)
						post_signal(signal)

			if(AIRLOCK_STATE_PRESSURIZE)
				if(target_state < state)
					if(sensor_pressure >= ONE_ATMOSPHERE*0.95)
						if(memory["interior_status"] == "open")
							state = AIRLOCK_STATE_INOPEN
							process_again = 1
						else
							var/datum/signal/signal = new
							signal.data["tag"] = interior_door_tag
							signal.data["command"] = "secure_open"
							post_signal(signal)
					else
						var/datum/signal/signal = new
						signal.data = list(
							"tag" = airpump_tag,
							"sigtype"="command"
						)
						if(memory["pump_status"] == "siphon")
							signal.data["stabalize"] = 1
						else if(memory["pump_status"] != "release")
							signal.data["power"] = 1
						post_signal(signal)
				else if(target_state > state)
					state = AIRLOCK_STATE_CLOSED
					process_again = 1

			if(AIRLOCK_STATE_CLOSED)
				if(target_state > state)
					if(memory["interior_status"] == "closed")
						state = AIRLOCK_STATE_DEPRESSURIZE
						process_again = 1
					else
						var/datum/signal/signal = new
						signal.data["tag"] = interior_door_tag
						signal.data["command"] = "secure_close"
						post_signal(signal)
				else if(target_state < state)
					if(memory["exterior_status"] == "closed")
						state = AIRLOCK_STATE_PRESSURIZE
						process_again = 1
					else
						var/datum/signal/signal = new
						signal.data["tag"] = exterior_door_tag
						signal.data["command"] = "secure_close"
						post_signal(signal)

				else
					if(memory["pump_status"] != "off")
						var/datum/signal/signal = new
						signal.data = list(
							"tag" = airpump_tag,
							"power" = 0,
							"sigtype"="command"
						)
						post_signal(signal)

			if(AIRLOCK_STATE_DEPRESSURIZE)
				var/target_pressure = ONE_ATMOSPHERE*0.05
				if(sanitize_external)
					target_pressure = ONE_ATMOSPHERE*0.01

				if(sensor_pressure <= target_pressure)
					if(target_state > state)
						if(memory["exterior_status"] == "open")
							state = AIRLOCK_STATE_OUTOPEN
						else
							var/datum/signal/signal = new
							signal.data["tag"] = exterior_door_tag
							signal.data["command"] = "secure_open"
							post_signal(signal)
					else if(target_state < state)
						state = AIRLOCK_STATE_CLOSED
						process_again = 1
				else if((target_state < state) && !sanitize_external)
					state = AIRLOCK_STATE_CLOSED
					process_again = 1
				else
					var/datum/signal/signal = new
					signal.transmission_method = 1 //radio signal
					signal.data = list(
						"tag" = airpump_tag,
						"sigtype"="command"
					)
					if(memory["pump_status"] == "release")
						signal.data["purge"] = 1
					else if(memory["pump_status"] != "siphon")
						signal.data["power"] = 1
					post_signal(signal)

			if(AIRLOCK_STATE_OUTOPEN) //state 2
				if(target_state < state)
					if(memory["exterior_status"] == "closed")
						if(sanitize_external)
							state = AIRLOCK_STATE_DEPRESSURIZE
							process_again = 1
						else
							state = AIRLOCK_STATE_CLOSED
							process_again = 1
					else
						var/datum/signal/signal = new
						signal.data["tag"] = exterior_door_tag
						signal.data["command"] = "secure_close"
						post_signal(signal)
				else
					if(memory["pump_status"] != "off")
						var/datum/signal/signal = new
						signal.data = list(
							"tag" = airpump_tag,
							"power" = 0,
							"sigtype"="command"
						)
						post_signal(signal)

	memory["sensor_pressure"] = sensor_pressure
	memory["processing"] = state != target_state
	//sensor_pressure = null //not sure if we can comment this out. Uncomment in case of problems -rastaf0

	return 1

/obj/machinery/embedded_controller/radio/airlock_controller
	icon = 'icons/obj/airlock_machines.dmi'
	icon_state = "airlock_control_standby"

	name = "airlock console"
	density = 0

	frequency = 1449
	power_channel = ENVIRON

	// Setup parameters only
	var/id_tag
	var/exterior_door_tag
	var/interior_door_tag
	var/airpump_tag
	var/sensor_tag
	var/sanitize_external

/obj/machinery/embedded_controller/radio/airlock_controller/initialize()
	..()

	var/datum/computer/file/embedded_program/airlock_controller/new_prog = new

	new_prog.id_tag = id_tag
	new_prog.exterior_door_tag = exterior_door_tag
	new_prog.interior_door_tag = interior_door_tag
	new_prog.airpump_tag = airpump_tag
	new_prog.sensor_tag = sensor_tag
	new_prog.sanitize_external = sanitize_external

	new_prog.master = src
	program = new_prog

/obj/machinery/embedded_controller/radio/airlock_controller/update_icon()
	if(on && program)
		if(program.memory["processing"])
			icon_state = "airlock_control_process"
		else
			icon_state = "airlock_control_standby"
	else
		icon_state = "airlock_control_off"

/obj/machinery/embedded_controller/radio/airlock_controller/return_text()
	var/state_options = null

	var/state = 0
	var/sensor_pressure = "----"
	var/exterior_status = "----"
	var/interior_status = "----"
	var/pump_status = "----"
	var/current_status = "Inactive
 "
	if(program)
		state = program.state
		sensor_pressure = program.memory["sensor_pressure"] ? program.memory["sensor_pressure"] : "----"
		exterior_status = program.memory["exterior_status"] ? program.memory["exterior_status"] : "----"
		interior_status = program.memory["interior_status"] ? program.memory["interior_status"] : "----"
		pump_status = program.memory["pump_status"] ? program.memory["pump_status"] : "----"

	switch(state)
		if(AIRLOCK_STATE_INOPEN)
			state_options = {"Close Interior Airlock

Cycle to Exterior Airlock
"}
			current_status = "Interior Airlock Open
Chamber Pressurized"
		if(AIRLOCK_STATE_PRESSURIZE)
			state_options = "Abort Cycling
"
			current_status = "Cycling to Interior Airlock
Chamber Pressurizing"
		if(AIRLOCK_STATE_CLOSED)
			state_options = {"Open Interior Airlock

Open Exterior Airlock
"}
		if(AIRLOCK_STATE_DEPRESSURIZE)
			state_options = "Abort Cycling
"
			current_status = "Cycling to Exterior Airlock
Chamber Depressurizing"
		if(AIRLOCK_STATE_OUTOPEN)
			state_options = {"Cycle to Interior Airlock

Close Exterior Airlock
"}
			current_status = "Exterior Airlock Open
Chamber Depressurized"

	var/output = {"
Airlock Status

Current Status:

[current_status]

\> Chamber Pressure:

[sensor_pressure] kPa

\> Control Pump:

[pump_status]

\> Interior Door:

[interior_status]

\> Exterior Door:

[exterior_status]

[state_options]"}

	return output


code:
/datum/computer/file/embedded_program
	var/list/memory = list()
	var/state
	var/obj/machinery/embedded_controller/master

/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
	if(master)
		master.post_signal(signal, comm_line)
	else
		qdel(signal)

/datum/computer/file/embedded_program/proc/receive_user_command(command)

/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
	return null

/datum/computer/file/embedded_program/process()
	return 0

/obj/machinery/embedded_controller
	var/datum/computer/file/embedded_program/program

	name = "embedded controller"
	density = 0
	anchored = 1

	var/on = 1

/obj/machinery/embedded_controller/interact(mob/user)
	//user << browse(return_text(), "window=computer")
	//onclose(user, "computer")
	user.set_machine(src)
	var/datum/browser/popup = new(user, "computer", name) // Set up the popup browser window
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.set_content(return_text())
	popup.open()

/obj/machinery/embedded_controller/attack_hand(mob/user)
	interact(user)

/obj/machinery/embedded_controller/update_icon()

/obj/machinery/embedded_controller/proc/return_text()

/obj/machinery/embedded_controller/proc/post_signal(datum/signal/signal, comm_line)
	return 0

/obj/machinery/embedded_controller/receive_signal(datum/signal/signal, receive_method, receive_param)
	if(!signal || signal.encryption) return

	if(program)
		program.receive_signal(signal, receive_method, receive_param)
		//spawn(5) program.process() //no, program.process sends some signals and machines respond and we here again and we lag -rastaf0

/obj/machinery/embedded_controller/Topic(href, href_list)
	if(..())
		return 0

	if(program)
		program.receive_user_command(href_list["command"])
		spawn(5) program.process()

	usr.set_machine(src)
	spawn(5) src.updateDialog()

/obj/machinery/embedded_controller/process()
	if(program)
		program.process()

	update_icon()
	src.updateDialog()

/obj/machinery/embedded_controller/radio
	var/frequency
	var/datum/radio_frequency/radio_connection

/obj/machinery/embedded_controller/radio/Destroy()
	if(SSradio)
		SSradio.remove_object(src,frequency)
	return ..()

/obj/machinery/embedded_controller/radio/initialize()
	set_frequency(frequency)

/obj/machinery/embedded_controller/radio/post_signal(datum/signal/signal)
	signal.transmission_method = TRANSMISSION_RADIO
	if(radio_connection)
		return radio_connection.post_signal(src, signal)
	else
		signal = null

/obj/machinery/embedded_controller/radio/proc/set_frequency(new_frequency)
	SSradio.remove_object(src, frequency)
	frequency = new_frequency
	radio_connection = SSradio.add_object(src, frequency)


code:
/datum/computer/file/embedded_program/simple_vent_controller

	var/airpump_tag

/datum/computer/file/embedded_program/simple_vent_controller/receive_user_command(command)
	switch(command)
		if("vent_inactive")
			var/datum/signal/signal = new
			signal.data = list(
				"tag" = airpump_tag,
				"sigtype"="command"
			)
			signal.data["power"] = 0
			post_signal(signal)

		if("vent_pump")
			var/datum/signal/signal = new
			signal.data = list(
				"tag" = airpump_tag,
				"sigtype"="command"
			)
			signal.data["stabalize"] = 1
			signal.data["power"] = 1
			post_signal(signal)

		if("vent_clear")
			var/datum/signal/signal = new
			signal.transmission_method = 1 //radio signal
			signal.data = list(
				"tag" = airpump_tag,
				"sigtype"="command"
			)
			signal.data["purge"] = 1
			signal.data["power"] = 1
			post_signal(signal)

/datum/computer/file/embedded_program/simple_vent_controller/process()
	return 0

/obj/machinery/embedded_controller/radio/simple_vent_controller
	icon = 'icons/obj/airlock_machines.dmi'
	icon_state = "airlock_control_standby"

	name = "vent controller"
	density = 0

	frequency = 1229
	power_channel = ENVIRON

	// Setup parameters only
	var/airpump_tag

/obj/machinery/embedded_controller/radio/simple_vent_controller/initialize()
	..()

	var/datum/computer/file/embedded_program/simple_vent_controller/new_prog = new

	new_prog.airpump_tag = airpump_tag
	new_prog.master = src
	program = new_prog

/obj/machinery/embedded_controller/radio/simple_vent_controller/update_icon()
	if(on && program)
		icon_state = "airlock_control_standby"
	else
		icon_state = "airlock_control_off"

/obj/machinery/embedded_controller/radio/simple_vent_controller/return_text()
	var/state_options = null
	state_options = {"Deactivate Vent

Activate Vent / Pump

Activate Vent / Clear
"}
	var/output = {"Vent Control Console

[state_options]
"}

	return output


code:
/obj/item/weapon/electronics/firealarm
	name = "fire alarm electronics"
	desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\""

/obj/item/wallframe/firealarm
	name = "fire alarm frame"
	desc = "Used for building Fire Alarms"
	icon = 'icons/obj/monitors.dmi'
	icon_state = "fire_bitem"
	result_path = /obj/machinery/firealarm

/obj/machinery/firealarm
	name = "fire alarm"
	desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever."
	icon = 'icons/obj/monitors.dmi'
	icon_state = "fire0"
	anchored = 1
	use_power = 1
	idle_power_usage = 2
	active_power_usage = 6
	power_channel = ENVIRON
	var/detecting = 1
	var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone

/obj/machinery/firealarm/New(loc, dir, building)
	..()
	if(dir)
		src.dir = dir
	if(building)
		buildstage = 0
		panel_open = 1
		pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
		pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
	update_icon()

/obj/machinery/firealarm/power_change()
	..()
	update_icon()

/obj/machinery/firealarm/update_icon()
	src.overlays = list()

	var/area/A = src.loc
	A = A.loc

	if(panel_open)
		icon_state = "fire_b[buildstage]"
		return
	else
		icon_state = "fire0"

		if(stat & NOPOWER)
			return
		if(stat & BROKEN)
			icon_state = "firex"
			return

		overlays += "overlay_[security_level]"
		if(detecting)
			overlays += "overlay_[A.fire ? "fire" : "clear"]"
		else
			overlays += "overlay_fire"

/obj/machinery/firealarm/bullet_act(BLAH)
	if(prob(50))
		alarm()

/obj/machinery/firealarm/emp_act(severity)
	if(prob(50 / severity))
		alarm()

/obj/machinery/firealarm/emag_act(mob/user)
	if(!emagged)
		emagged = 1
		if(user)
			user.visible_message("Sparks fly out of the [src]!",
								"You emag the [src], disabling its thermal sensors.")
		playsound(src.loc, 'sound/effects/sparks4.ogg', 50, 1)

/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
	if(!emagged && detecting && temperature > T0C + 200)
		alarm()

/obj/machinery/firealarm/proc/alarm()
	if(!is_operational())
		return
	var/area/A = get_area(src)
	A.firealert(src)
	playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0)

/obj/machinery/firealarm/proc/alarm_in(time)
	addtimer(src, "alarm", time, FALSE)

/obj/machinery/firealarm/proc/reset()
	if(!is_operational())
		return
	var/area/A = get_area(src)
	A.firereset(src)

/obj/machinery/firealarm/proc/reset_in(time)
	addtimer(src, "reset", time, FALSE)

/obj/machinery/firealarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
									datum/tgui/master_ui = null, datum/ui_state/state = default_state)
	ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
	if(!ui)
		ui = new(user, src, ui_key, "firealarm", name, 300, 150, master_ui, state)
		ui.open()

/obj/machinery/firealarm/ui_data(mob/user)
	var/list/data = list()
	data["emagged"] = emagged
	data["seclevel"] = get_security_level()

	var/area/A = get_area(src)
	data["alarm"] = A.fire

	return data

/obj/machinery/firealarm/ui_act(action, params)
	if(..() || buildstage != 2)
		return
	switch(action)
		if("reset")
			reset()
			. = TRUE
		if("alarm")
			alarm()
			. = TRUE

/obj/machinery/firealarm/attackby(obj/item/W, mob/user, params)
	add_fingerprint(user)

	if(istype(W, /obj/item/weapon/screwdriver) && buildstage == 2)
		playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
		panel_open = !panel_open
		user << "The wires have been [panel_open ? "exposed" : "unexposed"]."
		update_icon()
		return

	if(panel_open)
		switch(buildstage)
			if(2)
				if(istype(W, /obj/item/device/multitool))
					detecting = !detecting
					if (src.detecting)
						user.visible_message("[user] has reconnected [src]'s detecting unit!", "You reconnect [src]'s detecting unit.")
					else
						user.visible_message("[user] has disconnected [src]'s detecting unit!", "You disconnect [src]'s detecting unit.")
					return

				else if (istype(W, /obj/item/weapon/wirecutters))
					buildstage = 1
					playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1)
					var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil()
					coil.amount = 5
					coil.loc = user.loc
					user << "You cut the wires from \the [src]."
					update_icon()
					return
			if(1)
				if(istype(W, /obj/item/stack/cable_coil))
					var/obj/item/stack/cable_coil/coil = W
					if(coil.get_amount() < 5)
						user << "You need more cable for this!"
					else
						coil.use(5)
						buildstage = 2
						user << "You wire \the [src]."
						update_icon()
					return

				else if(istype(W, /obj/item/weapon/crowbar))
					playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
					user.visible_message("[user.name] removes the electronics from [src.name].", \
										"You start prying out the circuit...")
					if(do_after(user, 20/W.toolspeed, target = src))
						if(buildstage == 1)
							if(stat & BROKEN)
								user << "You remove the destroyed circuit."
							else
								user << "You pry out the circuit."
								new /obj/item/weapon/electronics/firealarm(user.loc)
							buildstage = 0
							update_icon()
					return
			if(0)
				if(istype(W, /obj/item/weapon/electronics/firealarm))
					user << "You insert the circuit."
					qdel(W)
					buildstage = 1
					update_icon()
					return

				else if(istype(W, /obj/item/weapon/wrench))
					user.visible_message("[user] removes the fire alarm assembly from the wall.", \
										 "You remove the fire alarm assembly from the wall.")
					var/obj/item/wallframe/firealarm/frame = new /obj/item/wallframe/firealarm()
					frame.loc = user.loc
					playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
					qdel(src)
					return
	return ..()


code:
// It is a gizmo that flashes a small area

/obj/machinery/flasher
	name = "mounted flash"
	desc = "A wall-mounted flashbulb device."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "mflash1"
	var/obj/item/device/assembly/flash/handheld/bulb = null
	var/id = null
	var/range = 2 //this is roughly the size of brig cell
	var/last_flash = 0 //Don't want it getting spammed like regular flashes
	var/strength = 5 //How weakened targets are when flashed.
	var/base_state = "mflash"
	anchored = 1

/obj/machinery/flasher/portable //Portable version of the flasher. Only flashes when anchored
	name = "portable flasher"
	desc = "A portable flashing device. Wrench to activate and deactivate. Cannot detect slow movements."
	icon_state = "pflash1-p"
	strength = 4
	anchored = 0
	base_state = "pflash"
	density = 1

/obj/machinery/flasher/New(loc, ndir = 0, built = 0)
	..() // ..() is EXTREMELY IMPORTANT, never forget to add it
	if(built)
		dir = ndir
		pixel_x = (dir & 3)? 0 : (dir == 4 ? -28 : 28)
		pixel_y = (dir & 3)? (dir ==1 ? -28 : 28) : 0
	else
		bulb = new /obj/item/device/assembly/flash/handheld(src)

/obj/machinery/flasher/Move()
	remove_from_proximity_list(src, range)
	..()

/obj/machinery/flasher/power_change()
	if (powered() && anchored && bulb)
		stat &= ~NOPOWER
		if(bulb.crit_fail)
			icon_state = "[base_state]1-p"
		else
			icon_state = "[base_state]1"
	else
		stat |= ~NOPOWER
		icon_state = "[base_state]1-p"

//Don't want to render prison breaks impossible
/obj/machinery/flasher/attackby(obj/item/weapon/W, mob/user, params)
	if (istype(W, /obj/item/weapon/wirecutters))
		if (bulb)
			user.visible_message("[user] begins to disconnect [src]'s flashbulb.", "You begin to disconnect [src]'s flashbulb...")
			playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
			if(do_after(user, 30/W.toolspeed, target = src) && bulb)
				user.visible_message("[user] has disconnected [src]'s flashbulb!", "You disconnect [src]'s flashbulb.")
				bulb.loc = src.loc
				bulb = null
				power_change()

	else if (istype(W, /obj/item/device/assembly/flash/handheld))
		if (!bulb)
			if(!user.drop_item())
				return
			user.visible_message("[user] installs [W] into [src].", "You install [W] into [src].")
			W.loc = src
			bulb = W
			power_change()
		else
			user << "A flashbulb is already installed in [src]!"

	else if (istype(W, /obj/item/weapon/wrench))
		if(!bulb)
			user << "You start unsecuring the flasher frame..."
			playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
			if(do_after(user, 40/W.toolspeed, target = src))
				user << "You unsecure the flasher frame."
				var/obj/item/wallframe/flasher/F = new(get_turf(src))
				transfer_fingerprints_to(F)
				F.id = id
				playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1)
				qdel(src)
		else
			user << "Remove a flashbulb from [src] first!"

	add_fingerprint(user)

//Let the AI trigger them directly.
/obj/machinery/flasher/attack_ai()
	if (anchored)
		return flash()
	else
		return

/obj/machinery/flasher/proc/flash()
	if (!powered() || !bulb)
		return

	if (bulb.crit_fail || (last_flash && world.time < src.last_flash + 150))
		return

	if(!bulb.flash_recharge(30)) //Bulb can burn out if it's used too often too fast
		power_change()
		return
	bulb.times_used ++

	playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
	flick("[base_state]_flash", src)
	last_flash = world.time
	use_power(1000)

	for (var/mob/living/L in viewers(src, null))
		if (get_dist(src, L) > range)
			continue

		if(L.flash_eyes(affect_silicon = 1))
			L.Weaken(strength)
			if(L.weakeyes)
				L.Weaken(strength * 1.5)
				L.visible_message("[L] gasps and shields their eyes!")

	return 1

/obj/machinery/flasher/emp_act(severity)
	if(stat & (BROKEN|NOPOWER))
		..(severity)
		return
	if(bulb && prob(75/severity))
		flash()
		bulb.burn_out()
		power_change()
	..(severity)

/obj/machinery/flasher/portable/HasProximity(atom/movable/AM)
	if (last_flash && world.time < last_flash + 150)
		return

	if(istype(AM, /mob/living/carbon))
		var/mob/living/carbon/M = AM
		if (M.m_intent != "walk" && anchored)
			flash()

/obj/machinery/flasher/portable/attackby(obj/item/weapon/W, mob/user, params)
	if (istype(W, /obj/item/weapon/wrench))
		playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)

		if (!anchored && !isinspace())
			user << "[src] is now secured."
			overlays += "[base_state]-s"
			anchored = 1
			power_change()
			add_to_proximity_list(src, range)
		else
			user << "[src] can now be moved."
			overlays.Cut()
			anchored = 0
			power_change()
			remove_from_proximity_list(src, range)

	else
		..()

/obj/item/wallframe/flasher
	name = "mounted flash frame"
	desc = "Used for building wall-mounted flashers."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "mflash_frame"
	result_path = /obj/machinery/flasher
	var/id = null

/obj/item/wallframe/flasher/examine(mob/user)
	..()
	user << "Its channel ID is '[id]'."

/obj/item/wallframe/flasher/after_attach(var/obj/O)
	..()
	var/obj/machinery/flasher/F = O
	F.id = id


code:
/* Holograms!
 * Contains:
 *		Holopad
 *		Hologram
 *		Other stuff
 */

/*
Revised. Original based on space ninja hologram code. Which is also mine. /N
How it works:
AI clicks on holopad in camera view. View centers on holopad.
AI clicks again on the holopad to display a hologram. Hologram stays as long as AI is looking at the pad and it (the hologram) is in range of the pad.
AI can use the directional keys to move the hologram around, provided the above conditions are met and the AI in question is the holopad's master.
Any number of AIs can use a holopad. /Lo6
AI may cancel the hologram at any time by clicking on the holopad once more.

Possible to do for anyone motivated enough:
	Give an AI variable for different hologram icons.
	Itegrate EMP effect to disable the unit.
*/

/*
 * Holopad
 */

#define HOLOPAD_PASSIVE_POWER_USAGE 1
#define HOLOGRAM_POWER_USAGE 2
#define RANGE_BASED 4
#define AREA_BASED 6

var/const/HOLOPAD_MODE = RANGE_BASED

/obj/machinery/hologram/holopad
	name = "\improper AI holopad"
	desc = "It's a floor-mounted device for projecting holographic images. It is activated remotely."
	icon_state = "holopad0"
	layer = 2.1
	flags = HEAR
	languages = ROBOT | HUMAN
	var/list/masters = list()//List of AIs that use the holopad
	var/last_request = 0 //to prevent request spam. ~Carn
	var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
	var/temp = ""

/obj/machinery/hologram/holopad/New()
	..()
	component_parts = list()
	component_parts += new /obj/item/weapon/circuitboard/holopad(null)
	component_parts += new /obj/item/weapon/stock_parts/capacitor(null)
	RefreshParts()

/obj/machinery/hologram/holopad/RefreshParts()
	var/holograph_range = 4
	for(var/obj/item/weapon/stock_parts/capacitor/B in component_parts)
		holograph_range += 1 * B.rating
	holo_range = holograph_range

/obj/machinery/hologram/holopad/attackby(obj/item/P, mob/user, params)
	if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
		return

	if(exchange_parts(user, P))
		return

	if(default_pry_open(P))
		return

	if(default_unfasten_wrench(user, P))
		return

	default_deconstruction_crowbar(P)

/obj/machinery/hologram/holopad/AltClick(mob/living/carbon/human/user)
	interact(user)

/obj/machinery/hologram/holopad/interact(mob/living/carbon/human/user) //Carn: Hologram requests.
	if(!istype(user))
		return
	if(user.stat || stat & (NOPOWER|BROKEN))
		return
	user.set_machine(src)
	var/dat
	if(temp)
		dat = temp
	else
		dat = "request an AI's presence."

	var/datum/browser/popup = new(user, "holopad", name, 300, 130)
	popup.set_content(dat)
	popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
	popup.open()

/obj/machinery/hologram/holopad/Topic(href, href_list)
	if(..())
		return
	if (href_list["AIrequest"])
		if(last_request + 200 < world.time)
			last_request = world.time
			temp = "You requested an AI's presence.
"
			temp += "Main Menu"
			var/area/area = get_area(src)
			for(var/mob/living/silicon/ai/AI in living_mob_list)
				if(!AI.client)
					continue
				AI << "Your presence is requested at \the [area]."
		else
			temp = "A request for AI presence was already sent recently.
"
			temp += "Main Menu"

	else if(href_list["mainmenu"])
		temp = ""

	updateDialog()
	add_fingerprint(usr)

/obj/machinery/hologram/holopad/attack_ai(mob/living/silicon/ai/user)
	if (!istype(user))
		return
	/*There are pretty much only three ways to interact here.
	I don't need to check for client since they're clicking on an object.
	This may change in the future but for now will suffice.*/
	if(user.eyeobj.loc != src.loc)//Set client eye on the object if it's not already.
		user.eyeobj.setLoc(get_turf(src))
	else if(!masters[user])//If there is no hologram, possibly make one.
		activate_holo(user)
	else//If there is a hologram, remove it.
		clear_holo(user)
	return

/obj/machinery/hologram/holopad/proc/activate_holo(mob/living/silicon/ai/user)
	if(!(stat & NOPOWER) && user.eyeobj.loc == src.loc)//If the projector has power and client eye is on it
		if (istype(user.current, /obj/machinery/hologram/holopad))
			user << "ERROR: \black Image feed in progress."
			return
		create_holo(user)//Create one.
		src.visible_message("A holographic image of [user] flicks to life right before your eyes!")
	else
		user << "ERROR: \black Unable to project hologram."
	return

/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/hologram/holopad/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
	if(speaker && masters.len && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
		for(var/mob/living/silicon/ai/master in masters)
			if(masters[master] && speaker != master)
				master.relay_speech(message, speaker, message_langs, raw_message, radio_freq, spans)

/obj/machinery/hologram/holopad/proc/create_holo(mob/living/silicon/ai/A, turf/T = loc)
	var/obj/effect/overlay/holo_pad_hologram/h = new(T)//Spawn a blank effect at the location.
	h.icon = A.holo_icon
	h.mouse_opacity = 0//So you can't click on it.
	h.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
	h.anchored = 1//So space wind cannot drag it.
	h.name = "[A.name] (Hologram)"//If someone decides to right click.
	h.SetLuminosity(2)	//hologram lighting
	masters[A] = h
	SetLuminosity(2)			//pad lighting
	icon_state = "holopad1"
	A.current = src
	use_power += HOLOGRAM_POWER_USAGE
	return 1

/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/silicon/ai/user)
	if(user.current == src)
		user.current = null
	qdel(masters[user])//Get rid of user's hologram
	masters -= user //Discard AI from the list of those who use holopad
	use_power = max(HOLOPAD_PASSIVE_POWER_USAGE, use_power - HOLOGRAM_POWER_USAGE)//Reduce power usage
	if (!masters.len)//If no users left
		SetLuminosity(0)			//pad lighting (hologram lighting will be handled automatically since its owner was deleted)
		icon_state = "holopad0"
		use_power = HOLOPAD_PASSIVE_POWER_USAGE
	return 1

/obj/machinery/hologram/holopad/process()
	if(masters.len)//If there is a hologram.
		for (var/mob/living/silicon/ai/master in masters)
			if(master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
				if(!(stat & NOPOWER))//If the  machine has power.
					if((HOLOPAD_MODE == RANGE_BASED && (get_dist(master.eyeobj, src) <= holo_range)))
						return 1

					else if (HOLOPAD_MODE == AREA_BASED)

						var/area/holo_area = get_area(src)
						var/area/eye_area = get_area(master.eyeobj)

						if(eye_area in holo_area.master.related)
							return 1

			clear_holo(master)//If not, we want to get rid of the hologram.
	return 1

/obj/machinery/hologram/holopad/proc/move_hologram(mob/living/silicon/ai/user)
	if(masters[user])
		step_to(masters[user], user.eyeobj) // So it turns.
		var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
		H.loc = get_turf(user.eyeobj)
		masters[user] = H
	return 1

/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0)
	return 1

/*
 * Hologram
 */

/obj/machinery/hologram
	anchored = 1
	use_power = 1
	idle_power_usage = 5
	active_power_usage = 100

/obj/machinery/hologram/power_change()
	if (powered())
		stat &= ~NOPOWER
	else
		stat |= ~NOPOWER

//Destruction procs.
/obj/machinery/hologram/ex_act(severity, target)
	switch(severity)
		if(1)
			qdel(src)
		if(2)
			if (prob(50))
				qdel(src)
		if(3)
			if (prob(5))
				qdel(src)
	return

/obj/machinery/hologram/holopad/Destroy()
	for (var/mob/living/silicon/ai/master in masters)
		clear_holo(master)
	return ..()

#undef RANGE_BASED
#undef AREA_BASED
#undef HOLOPAD_PASSIVE_POWER_USAGE
#undef HOLOGRAM_POWER_USAGE


code:
/obj/machinery/igniter
	name = "igniter"
	desc = "It's useful for igniting plasma."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "igniter1"
	var/id = null
	var/on = 1
	anchored = 1
	use_power = 1
	idle_power_usage = 2
	active_power_usage = 4

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

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

/obj/machinery/igniter/attack_hand(mob/user)
	if(..())
		return
	add_fingerprint(user)

	use_power(50)
	src.on = !( src.on )
	src.icon_state = text("igniter[]", src.on)
	return

/obj/machinery/igniter/process()	//ugh why is this even in process()?
	if (src.on && !(stat & NOPOWER) )
		var/turf/location = src.loc
		if (isturf(location))
			location.hotspot_expose(1000,500,1)
	return 1

/obj/machinery/igniter/New()
	..()
	icon_state = "igniter[on]"

/obj/machinery/igniter/power_change()
	if(!( stat & NOPOWER) )
		icon_state = "igniter[src.on]"
	else
		icon_state = "igniter0"

// Wall mounted remote-control igniter.

/obj/machinery/sparker
	name = "mounted igniter"
	desc = "A wall-mounted ignition device."
	icon = 'icons/obj/stationobjs.dmi'
	icon_state = "migniter"
	var/id = null
	var/disable = 0
	var/last_spark = 0
	var/base_state = "migniter"
	var/datum/effect_system/spark_spread/spark_system
	anchored = 1

/obj/machinery/sparker/New()
	..()
	spark_system = new /datum/effect_system/spark_spread
	spark_system.set_up(2, 1, src)
	spark_system.attach(src)

/obj/machinery/sparker/Destroy()
	qdel(spark_system)
	spark_system = null
	return ..()

/obj/machinery/sparker/power_change()
	if ( powered() && disable == 0 )
		stat &= ~NOPOWER
		icon_state = "[base_state]"
//		src.sd_SetLuminosity(2)
	else
		stat |= ~NOPOWER
		icon_state = "[base_state]-p"
//		src.sd_SetLuminosity(0)

/obj/machinery/sparker/attackby(obj/item/weapon/W, mob/user, params)
	if(istype(W, /obj/item/device/detective_scanner))
		return
	if (istype(W, /obj/item/weapon/screwdriver))
		add_fingerprint(user)
		src.disable = !src.disable
		if (src.disable)
			user.visible_message("[user] has disabled \the [src]!", "You disable the connection to \the [src].")
			icon_state = "[base_state]-d"
		if (!src.disable)
			user.visible_message("[user] has reconnected \the [src]!", "You fix the connection to \the [src].")
			if(src.powered())
				icon_state = "[base_state]"
			else
				icon_state = "[base_state]-p"

/obj/machinery/sparker/attack_ai()
	if (anchored)
		return src.ignite()
	else
		return

/obj/machinery/sparker/proc/ignite()
	if (!(powered()))
		return

	if ((src.disable) || (src.last_spark && world.time < src.last_spark + 50))
		return

	flick("[base_state]-spark", src)
	spark_system.start()
	last_spark = world.time
	use_power(1000)
	var/turf/location = src.loc
	if (isturf(location))
		location.hotspot_expose(1000,500,1)
	return 1

/obj/machinery/sparker/emp_act(severity)
	if(stat & (BROKEN|NOPOWER))
		..(severity)
		return
	ignite()
	..(severity)


code:
/obj/machinery/iv_drip
	name = "\improper IV drip"
	icon = 'icons/obj/iv_drip.dmi'
	icon_state = "iv_drip"
	anchored = 0
	density = 1
	var/mob/living/carbon/human/attached = null
	var/mode = 1 // 1 is injecting, 0 is taking blood.
	var/obj/item/weapon/reagent_containers/beaker = null

/obj/machinery/iv_drip/New()
	..()
	update_icon()

/obj/machinery/iv_drip/update_icon()
	if(attached)
		if(mode)
			icon_state = "injecting"
		else
			icon_state = "donating"
	else
		if(mode)
			icon_state = "injectidle"
		else
			icon_state = "donateidle"

	overlays = null

	if(beaker)
		if(attached)
			overlays += "beakeractive"
		else
			overlays += "beakeridle"
		if(beaker.reagents.total_volume)
			var/image/filling = image('icons/obj/iv_drip.dmi', src, "reagent")

			var/percent = round((beaker.reagents.total_volume / beaker.volume) * 100)
			switch(percent)
				if(0 to 9)
					filling.icon_state = "reagent0"
				if(10 to 24)
					filling.icon_state = "reagent10"
				if(25 to 49)
					filling.icon_state = "reagent25"
				if(50 to 74)
					filling.icon_state = "reagent50"
				if(75 to 79)
					filling.icon_state = "reagent75"
				if(80 to 90)
					filling.icon_state = "reagent80"
				if(91 to INFINITY)
					filling.icon_state = "reagent100"

			filling.icon += mix_color_from_reagents(beaker.reagents.reagent_list)
			overlays += filling

/obj/machinery/iv_drip/MouseDrop(mob/living/target)
	if(!ishuman(usr) || !usr.canUseTopic(src,BE_CLOSE))
		return

	if(attached)
		visible_message("[attached] is detached from \the [src].")
		attached = null
		update_icon()
		return

	if(!ishuman(target))
		usr << "The drip beeps: Warning, human patients only!"
		return

	if(Adjacent(target) && usr.Adjacent(target))
		if(beaker)
			usr.visible_message("[usr] attaches \the [src] to \the [target].", "You attach \the [src] to \the [target].")
			attached = target
			SSmachine.processing.Add(src)
			update_icon()
		else
			usr << "There's nothing attached to the IV drip!"

/obj/machinery/iv_drip/attackby(obj/item/weapon/W, mob/user, params)
	if (istype(W, /obj/item/weapon/reagent_containers))
		if(!isnull(beaker))
			user << "There is already a reagent container loaded!"
			return
		if(!user.drop_item())
			return

		W.loc = src
		beaker = W
		user << "You attach \the [W] to \the [src]."
		update_icon()
		return
	else
		return ..()

/obj/machinery/iv_drip/process()
	if(!attached)
		return PROCESS_KILL

	if(!(get_dist(src, attached) <= 1 && isturf(attached.loc)))
		attached << "The IV drip needle is ripped out of you!"
		attached.apply_damage(3, BRUTE, pick("r_arm", "l_arm"))
		attached = null
		update_icon()
		return PROCESS_KILL

	if(beaker)
		// Give blood
		if(mode)
			if(beaker.volume > 0)
				var/transfer_amount = 5
				if(istype(beaker, /obj/item/weapon/reagent_containers/blood))
					// speed up transfer on blood packs
					transfer_amount = 10
				var/fraction = min(transfer_amount/beaker.volume, 1) //the fraction that is transfered of the total volume
				beaker.reagents.reaction(attached, INJECT, fraction,0) //make reagents reacts, but don't spam messages
				beaker.reagents.trans_to(attached, transfer_amount)
				update_icon()

		// Take blood
		else
			var/amount = beaker.reagents.maximum_volume - beaker.reagents.total_volume
			amount = min(amount, 4)
			// If the beaker is full, ping
			if(amount == 0)
				if(prob(5)) visible_message("\The [src] pings.")
				return

			var/mob/living/carbon/human/T = attached

			if(!istype(T))
				return

			if(T.disabilities & NOCLONE)
				return

			if((NOBLOOD in T.dna.species.specflags) && !T.dna.species.exotic_blood)
				return

			if(T.dna.species.exotic_blood)
				T.reagents.trans_to(beaker, amount)
				update_icon()
			else
				// If the human is losing too much blood, beep.
				if(T.vessel.get_reagent_amount("blood") < BLOOD_VOLUME_SAFE && prob(5))
					visible_message("\The [src] beeps loudly.")
					playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
				var/datum/reagent/B = T.take_blood(beaker,amount)

				if (B)
					beaker.reagents.reagent_list |= B
					beaker.reagents.update_total()
					beaker.on_reagent_change()
					beaker.reagents.handle_reactions()
					update_icon()

/obj/machinery/iv_drip/attack_hand(mob/user)
	if (!ishuman(user))
		return
	if(attached)
		visible_message("[attached] is detached from \the [src]")
		attached = null
		update_icon()
		return
	else if(beaker)
		eject_beaker(user)
	else
		toggle_mode()

/obj/machinery/iv_drip/verb/eject_beaker(mob/user)
	set category = "Object"
	set name = "Remove IV Container"
	set src in view(1)

	if(!istype(usr, /mob/living))
		usr << "You can't do that!"
		return

	if(usr.stat)
		return

	if(beaker)
		beaker.loc = get_turf(src)
		beaker = null
		update_icon()

/obj/machinery/iv_drip/verb/toggle_mode()
	set category = "Object"
	set name = "Toggle Mode"
	set src in view(1)

	if(!istype(usr, /mob/living))
		usr << "You can't do that!"
		return

	if(usr.stat)
		return

	mode = !mode
	usr << "The IV drip is now [mode ? "injecting" : "taking blood"]."
	update_icon()

/obj/machinery/iv_drip/examine()
	set src in view()
	..()
	if (!(usr in view(2)) && usr!=loc) return

	usr << "The IV drip is [mode ? "injecting" : "taking blood"]."

	if(beaker)
		if(beaker.reagents && beaker.reagents.reagent_list.len)
			usr << "Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid."
		else
			usr << "Attached is an empty [beaker]."
	else
		usr << "No chemicals are attached."

	usr << "[attached ? attached : "No one"] is attached."