code:
// Basic transit tubes. Straight pieces, curved sections,
//  and basic splits/joins (no routing logic).
// Mappers: you can use "Generate Instances from Icon-states"
//  to get the different pieces.
/obj/structure/transit_tube
	icon = 'icons/obj/pipes/transit_tube.dmi'
	icon_state = "E-W"
	density = 1
	layer = 3.1
	anchored = 1.0
	var/tube_construction = /obj/structure/c_transit_tube
	var/list/tube_dirs = null
	var/exit_delay = 1
	var/enter_delay = 0

	// alldirs in global.dm is the same list of directions, but since
	//  the specific order matters to get a usable icon_state, it is
	//  copied here so that, in the unlikely case that alldirs is changed,
	//  this continues to work.
	var/global/list/tube_dir_list = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)

/obj/structure/transit_tube/CanPass(atom/movable/mover, turf/target)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	return !density

// When destroyed by explosions, properly handle contents.
obj/structure/transit_tube/ex_act(severity, target)
	if(3 - severity >= 0)
		var/oldloc = loc
		..(severity + 1)
		for(var/atom/movable/AM in contents)
			AM.loc = oldloc

/obj/structure/transit_tube/New(loc)
	..(loc)

	if(tube_dirs == null)
		init_dirs()

/obj/structure/transit_tube/attackby(obj/item/W, mob/user, params)
	if(istype(W, /obj/item/weapon/wrench))
		if(copytext(icon_state, 1, 3) != "D-") //decorative diagonals cannot be unwrenched directly
			for(var/obj/structure/transit_tube_pod/pod in src.loc)
				user << "Remove the pod first."
				return
			user.visible_message("[user] starts to deattach \the [src]!", "You start deattaching the [name]...")
			playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
			if(do_after(user, 35))
				user << "You deattach the [name]!"
				var/obj/structure/R = new tube_construction(src.loc)
				R.icon_state = src.icon_state
				src.transfer_fingerprints_to(R)
				R.add_fingerprint(user)
				src.destroy_diagonals()
				qdel(src)
	if(istype(W, /obj/item/weapon/crowbar))
		for(var/obj/structure/transit_tube_pod/pod in src.loc)
			pod.attackby(W, user)

//destroys disconnected decorative diagonals
/obj/structure/transit_tube/proc/destroy_diagonals()
	for(var/obj/structure/transit_tube/D in orange(1, src))
		if(copytext(D.icon_state, 1, 3) == "D-") //is diagonal
			var/my_dir = text2dir_extended(copytext(D.icon_state, 3, 5))
			var/is_connecting = 0
			for(var/obj/structure/transit_tube/N in orange(1,D))
				if( (( get_dir(D,N) == turn(my_dir, -45) && D.has_exit(turn(my_dir, 90)) ) || \
					( get_dir(D,N) == turn(my_dir, 45) && D.has_exit(turn(my_dir, -90))) ) && \
					D != src )
					is_connecting = 1
					break
			if(!is_connecting)
				qdel(D)

// Called to check if a pod should stop upon entering this tube.
/obj/structure/transit_tube/proc/should_stop_pod(pod, from_dir)
	return 0

// Called when a pod stops in this tube section.
/obj/structure/transit_tube/proc/pod_stopped(pod, from_dir)
	return

// Returns a /list of directions this tube section can connect to.
//  Tubes that have some sort of logic or changing direction might
//  override it with additional logic.
/obj/structure/transit_tube/proc/directions()
	return tube_dirs

/obj/structure/transit_tube/proc/has_entrance(from_dir)
	from_dir = turn(from_dir, 180)

	for(var/direction in directions())
		if(direction == from_dir)
			return 1

	return 0

/obj/structure/transit_tube/proc/has_exit(in_dir)
	for(var/direction in directions())
		if(direction == in_dir)
			return 1

	return 0

// Searches for an exit direction within 45 degrees of the
//  specified dir. Returns that direction, or 0 if none match.
/obj/structure/transit_tube/proc/get_exit(in_dir)
	var/near_dir = 0
	var/in_dir_cw = turn(in_dir, -45)
	var/in_dir_ccw = turn(in_dir, 45)

	for(var/direction in directions())
		if(direction == in_dir)
			return direction

		else if(direction == in_dir_cw)
			near_dir = direction

		else if(direction == in_dir_ccw)
			near_dir = direction

	return near_dir

// Return how many BYOND ticks to wait before entering/exiting
//  the tube section. Default action is to return the value of
//  a var, which wouldn't need a proc, but it makes it possible
//  for later tube types to interact in more interesting ways
//  such as being very fast in one direction, but slow in others
/obj/structure/transit_tube/proc/exit_delay(pod, to_dir)
	return exit_delay

/obj/structure/transit_tube/proc/enter_delay(pod, to_dir)
	return enter_delay

// Parse the icon_state into a list of directions.
// This means that mappers can use Dream Maker's built in
//  "Generate Instances from Icon-states" option to get all
//  variations. Additionally, as a separate proc, sub-types
//  can handle it more intelligently.
/obj/structure/transit_tube/proc/init_dirs()
	if(icon_state == "auto")
		// Additional delay, for map loading.
		spawn(1)
			init_dirs_automatic()

	else
		tube_dirs = parse_dirs(icon_state)

		if(copytext(icon_state, 1, 3) == "D-" || findtextEx(icon_state, "Pass"))
			density = 0

// Initialize dirs by searching for tubes that do/might connect
//  on nearby turfs. Create corner pieces if nessecary.
// Pick two directions, preferring tubes that already connect
//  to loc, or other auto tubes if there aren't enough connections.
/obj/structure/transit_tube/proc/init_dirs_automatic()
	var/list/connected = list()
	var/list/connected_auto = list()

	for(var/direction in tube_dir_list)
		var/location = get_step(loc, direction)
		for(var/obj/structure/transit_tube/tube in location)
			if(tube.directions() == null && tube.icon_state == "auto")
				connected_auto += direction
				break

			else if(turn(direction, 180) in tube.directions())
				connected += direction
				break

	connected += connected_auto

	tube_dirs = select_automatic_dirs(connected)

	if(length(tube_dirs) == 2 && tube_dir_list.Find(tube_dirs[1]) > tube_dir_list.Find(tube_dirs[2]))
		tube_dirs.Swap(1, 2)

	generate_automatic_corners(tube_dirs)
	select_automatic_icon_state(tube_dirs)

// Given a list of directions, look a pair that forms a 180 or
//  135 degree angle, and return a list containing the pair.
//  If none exist, return list(connected[1], turn(connected[1], 180)
/obj/structure/transit_tube/proc/select_automatic_dirs(connected)
	if(length(connected) < 1)
		return list()

	for(var/i = 1, i <= length(connected), i++)
		for(var/j = i + 1, j <= length(connected), j++)
			var/d1 = connected[i]
			var/d2 = connected[j]

			if(d1 == turn(d2, 135) || d1 == turn(d2, 180) || d1 == turn(d2, 225))
				return list(d1, d2)

	return list(connected[1], turn(connected[1], 180))

/obj/structure/transit_tube/proc/select_automatic_icon_state(directions)
	if(length(directions) == 2)
		icon_state = "[dir2text_short(directions[1])]-[dir2text_short(directions[2])]"

// Look for diagonal directions, generate the decorative corners in each.
/obj/structure/transit_tube/proc/generate_automatic_corners(directions)
	for(var/direction in directions)
		if(direction == 5 || direction == 6 || direction == 9 || direction == 10)
			if(direction & NORTH)
				create_automatic_decorative_corner(get_step(loc, NORTH), direction ^ 3)

			else
				create_automatic_decorative_corner(get_step(loc, SOUTH), direction ^ 3)

			if(direction & EAST)
				create_automatic_decorative_corner(get_step(loc, EAST), direction ^ 12)

			else
				create_automatic_decorative_corner(get_step(loc, WEST), direction ^ 12)

// Generate a corner, if one doesn't exist for the direction on the turf.
/obj/structure/transit_tube/proc/create_automatic_decorative_corner(location, direction)
	var/state = "D-[dir2text_short(direction)]"

	for(var/obj/structure/transit_tube/tube in location)
		if(tube.icon_state == state)
			return

	var/obj/structure/transit_tube/tube = new(location)
	tube.icon_state = state
	tube.init_dirs()

// Uses a list() to cache return values. Since they should
//  never be edited directly, all tubes with a certain
//  icon_state can just reference the same list. In theory,
//  reduces memory usage, and improves CPU cache usage.
//  In reality, I don't know if that is quite how BYOND works,
//  but it is probably safer to assume the existence of, and
//  rely on, a sufficiently smart compiler/optimizer.
/obj/structure/transit_tube/proc/parse_dirs(text)
	var/global/list/direction_table = list()

	if(text in direction_table)
		return direction_table[text]

	var/list/split_text = text2list(text, "-")

	// If the first token is D, the icon_state represents
	//  a purely decorative tube, and doesn't actually
	//  connect to anything.
	if(split_text[1] == "D")
		direction_table[text] = list()
		return null

	var/list/directions = list()

	for(var/text_part in split_text)
		var/direction = text2dir_extended(text_part)

		if(direction > 0)
			directions += direction

	direction_table[text] = directions
	return directions


code:
// transit tube construction

// normal transit tubes
/obj/structure/c_transit_tube
	name = "unattached transit tube"
	icon = 'icons/obj/pipes/transit_tube.dmi'
	icon_state = "E-W" //icon_state decides which tube will be built
	density = 0
	layer = 3.1 //same as the built tube
	anchored = 0.0

//wrapper for turn that changes the transit tube formatted icon_state instead of the dir
/obj/structure/c_transit_tube/proc/tube_turn(var/angle)
	var/list/badtubes = list("W-E", "W-E-Pass", "S-N", "S-N-Pass", "SW-NE", "SE-NW")
	var/list/split_text = text2list(icon_state, "-")
	for(var/i=1; i<=split_text.len; i++)
		var/curdir = text2dir_extended(split_text[i]) //0 if not a valid direction (e.g. Pass, Block)
		if(curdir)
			split_text[i] = dir2text_short(turn(curdir, angle))
	var/newdir = list2text(split_text, "-")
	if(badtubes.Find(newdir))
		split_text.Swap(1,2)
		newdir = list2text(split_text, "-")
	icon_state = newdir

/obj/structure/c_transit_tube/proc/tube_flip()
	var/list/split_text = text2list(icon_state, "-")
	//skip straight pipes
	if(length(split_text[2]) < 2)
		return
	//for junctions, just swap the diagonals with each other
	if(split_text.len == 3 && split_text[3] != "Pass")
		split_text.Swap(2,3)
	//for curves, swap the diagonal direction that is not in the same axis as the cardinal direction
	else
		if(split_text[1] == "N" || split_text[1] == "S")
			split_text[2] = copytext(split_text[2],1,2) + ((copytext(split_text[2],2,3) == "E") ? "W" : "E")
		else
			split_text[2] = ((copytext(split_text[2],1,2) == "N") ? "S" : "N") + copytext(split_text[2],2,3)
	icon_state = list2text(split_text, "-")

// disposals-style flip and rotate verbs
/obj/structure/c_transit_tube/verb/rotate()
	set name = "Rotate Tube CW"
	set category = "Object"
	set src in view(1)

	if(!usr.canUseTopic(src))
		return

	tube_turn(-90)

/obj/structure/c_transit_tube/verb/rotate_ccw()
	set name = "Rotate Tube CCW"
	set category = "Object"
	set src in view(1)

	if(!usr.canUseTopic(src))
		return

	tube_turn(90)

/obj/structure/c_transit_tube/verb/flip()
	set name = "Flip"
	set category = "Object"
	set src in view(1)

	if(!usr.canUseTopic(src))
		return

	tube_flip()

/obj/structure/c_transit_tube/proc/buildtube()
	var/obj/structure/transit_tube/R = new/obj/structure/transit_tube(src.loc)
	R.icon_state = src.icon_state
	R.init_dirs()
	R.generate_automatic_corners(R.tube_dirs)
	return R

/obj/structure/c_transit_tube/attackby(var/obj/item/I, var/mob/user, params)
	if(istype(I, /obj/item/weapon/wrench))
		user << "You start attaching the [name]..."
		src.add_fingerprint(user)
		if(do_after(user, 40))
			if(!src) return
			user << "You attach the [name]!"
			var/obj/structure/transit_tube/R = src.buildtube()
			src.transfer_fingerprints_to(R)
			qdel(src)
			return

// transit tube station
/obj/structure/c_transit_tube/station
	name = "unattached through station"
	icon = 'icons/obj/pipes/transit_tube_station.dmi'
	icon_state = "closed"

/obj/structure/c_transit_tube/station/tube_turn(var/angle)
	src.dir = turn(src.dir, angle)

/obj/structure/c_transit_tube/station/tube_flip()
	src.tube_turn(180)

/obj/structure/c_transit_tube/station/buildtube()
	var/obj/structure/transit_tube/station/R = new/obj/structure/transit_tube/station(src.loc)
	R.dir = src.dir
	R.init_dirs()
	return R

// reverser station, used for the terminus
/obj/structure/c_transit_tube/station/reverse
	name = "unattached terminus station"

/obj/structure/c_transit_tube/station/reverse/buildtube()
	var/obj/structure/transit_tube/station/reverse/R = new/obj/structure/transit_tube/station/reverse(src.loc)
	R.dir = src.dir
	R.init_dirs()
	return R

// block, used after the terminus of a transit tube station, decorative only
// code-wise they're normal tubes but they're ~speshul~ because they care about the dir instead of the icon_state
// in that sense they're the same as stations and can reuse their flip and rotate verbs
/obj/structure/c_transit_tube/station/block
	name = "unattached tube blocker"
	icon = 'icons/obj/pipes/transit_tube.dmi'
	icon_state = "Block"

/obj/structure/c_transit_tube/station/block/buildtube()
	var/obj/structure/transit_tube/R = new/obj/structure/transit_tube(src.loc)
	R.icon_state = src.icon_state
	R.dir = src.dir
	R.init_dirs()
	return R

//transit tube pod
//see station.dm for the logic
/obj/structure/c_transit_tube_pod
	name = "unattached transit tube pod"
	icon = 'icons/obj/pipes/transit_tube_pod.dmi'
	icon_state = "pod"
	anchored = 0.0
	density = 0

license: mit


code:
/obj/structure/transit_tube_pod
	icon = 'icons/obj/pipes/transit_tube_pod.dmi'
	icon_state = "pod"
	animate_movement = FORWARD_STEPS
	anchored = 1.0
	density = 1
	var/moving = 0
	var/datum/gas_mixture/air_contents = new()

/obj/structure/transit_tube_pod/New(loc)
	..(loc)

	air_contents.oxygen = MOLES_O2STANDARD * 2
	air_contents.nitrogen = MOLES_N2STANDARD
	air_contents.temperature = T20C

	// Give auto tubes time to align before trying to start moving
	spawn(5)
		follow_tube()

/obj/structure/transit_tube_pod/Destroy()
	for(var/atom/movable/AM in contents)
		AM.loc = loc

	..()

/obj/structure/transit_tube_pod/attackby(var/obj/item/I, var/mob/user, params)
	if(istype(I, /obj/item/weapon/crowbar))
		if(!moving)
			for(var/obj/structure/transit_tube/station/T in loc)
				return
			if(src.contents.len)
				user.visible_message("[user] empties \the [src].", "You empty \the [src].")
				src.empty()
				return
			else
				user << "You free \the [src]."
				var/obj/structure/c_transit_tube_pod/R = new/obj/structure/c_transit_tube_pod(src.loc)
				src.transfer_fingerprints_to(R)
				R.add_fingerprint(user)
				qdel(src)

/obj/structure/transit_tube_pod/container_resist()
	var/mob/living/user = usr
	if(!moving)
		user.changeNext_move(CLICK_CD_BREAKOUT)
		user.last_special = world.time + CLICK_CD_BREAKOUT
		user << "You start trying to escape from the pod."
		if(do_after(user, 600))
			user << "You manage to open the pod."
			src.empty()

/obj/structure/transit_tube_pod/proc/empty()
	for(var/atom/movable/M in src.contents)
		M.loc = src.loc

/obj/structure/transit_tube_pod/Process_Spacemove()
	if(moving) //No drifting while moving in the tubes
		return 1
	else return ..()

/obj/structure/transit_tube_pod/proc/follow_tube(var/reverse_launch)
	if(moving)
		return

	moving = 1

	spawn()
		var/obj/structure/transit_tube/current_tube = null
		var/next_dir
		var/next_loc
		var/last_delay = 0
		var/exit_delay

		if(reverse_launch)
			dir = turn(dir, 180) // Back it up

		for(var/obj/structure/transit_tube/tube in loc)
			if(tube.has_exit(dir))
				current_tube = tube
				break

		while(current_tube)
			next_dir = current_tube.get_exit(dir)

			if(!next_dir)
				break

			exit_delay = current_tube.exit_delay(src, dir)
			last_delay += exit_delay

			sleep(exit_delay)

			next_loc = get_step(loc, next_dir)

			current_tube = null
			for(var/obj/structure/transit_tube/tube in next_loc)
				if(tube.has_entrance(next_dir))
					current_tube = tube
					break

			if(current_tube == null)
				dir = next_dir
				Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes.
				break

			last_delay = current_tube.enter_delay(src, next_dir)
			sleep(last_delay)
			dir = next_dir
			loc = next_loc // When moving from one tube to another, skip collision and such.
			density = current_tube.density

			if(current_tube && current_tube.should_stop_pod(src, next_dir))
				current_tube.pod_stopped(src, dir)
				break

		density = 1
		moving = 0

// Should I return a copy here? If the caller edits or del()s the returned
//  datum, there might be problems if I don't...
/obj/structure/transit_tube_pod/return_air()
	var/datum/gas_mixture/GM = new()
	GM.oxygen			= air_contents.oxygen
	GM.carbon_dioxide	= air_contents.carbon_dioxide
	GM.nitrogen			= air_contents.nitrogen
	GM.toxins			= air_contents.toxins
	GM.temperature		= air_contents.temperature
	return GM

// For now, copying what I found in an unused FEA file (and almost identical in a
//  used ZAS file). Means that assume_air and remove_air don't actually alter the
//  air contents.
/obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver)
	return air_contents.merge(giver)

/obj/structure/transit_tube_pod/remove_air(amount)
	return air_contents.remove(amount)

// Called when a pod arrives at, and before a pod departs from a station,
//  giving it a chance to mix its internal air supply with the turf it is
//  currently on.
/obj/structure/transit_tube_pod/proc/mix_air()
	var/datum/gas_mixture/environment = loc.return_air()
	var/env_pressure = environment.return_pressure()
	var/int_pressure = air_contents.return_pressure()
	var/total_pressure = env_pressure + int_pressure

	if(total_pressure == 0)
		return

	// Math here: Completely made up, not based on realistic equasions.
	//  Goal is to balance towards equal pressure, but ensure some gas
	//  transfer in both directions regardless.
	// Feel free to rip this out and replace it with something better,
	//  I don't really know muhch about how gas transfer rates work in
	//  SS13.
	var/transfer_in = max(0.1, 0.5 * (env_pressure - int_pressure) / total_pressure)
	var/transfer_out = max(0.1, 0.3 * (int_pressure - env_pressure) / total_pressure)

	var/datum/gas_mixture/from_env = loc.remove_air(environment.total_moles() * transfer_in)
	var/datum/gas_mixture/from_int = air_contents.remove(air_contents.total_moles() * transfer_out)

	loc.assume_air(from_int)
	air_contents.merge(from_env)

// When the player moves, check if the pos is currently stopped at a station.
//  if it is, check the direction. If the direction matches the direction of
//  the station, try to exit. If the direction matches one of the station's
//  tube directions, launch the pod in that direction.
/obj/structure/transit_tube_pod/relaymove(mob/mob, direction)
	if(istype(mob, /mob) && mob.client)
		// If the pod is not in a tube at all, you can get out at any time.
		if(!(locate(/obj/structure/transit_tube) in loc))
			mob.loc = loc
			mob.client.Move(get_step(loc, direction), direction)
			mob.reset_view(null)

			//if(moving && istype(loc, /turf/space))
				// Todo: If you get out of a moving pod in space, you should move as well.
				//  Same direction as pod? Direcion you moved? Halfway between?

		if(!moving)
			for(var/obj/structure/transit_tube/station/station in loc)
				if(dir in station.directions())
					if(!station.pod_moving)
						if(direction == station.dir)
							if(station.icon_state == "open")
								mob.loc = loc
								mob.client.Move(get_step(loc, direction), direction)
								mob.reset_view(null)

							else
								station.open_animation()

						else if(direction in station.directions())
							dir = direction
							station.launch_pod()
					return

			for(var/obj/structure/transit_tube/tube in loc)
				if(dir in tube.directions())
					if(tube.has_exit(direction))
						dir = direction
						return


code:
/obj/structure/toilet
	name = "toilet"
	desc = "The HT-451, a torque rotation-based, waste disposal unit for small matter. This one seems remarkably clean."
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "toilet00"
	density = 0
	anchored = 1
	var/open = 0			//if the lid is up
	var/cistern = 0			//if the cistern bit is open
	var/w_items = 0			//the combined w_class of all the items in the cistern
	var/mob/living/swirlie = null	//the mob being given a swirlie

/obj/structure/toilet/New()
	open = round(rand(0, 1))
	update_icon()

/obj/structure/toilet/attack_hand(mob/living/user)
	if(swirlie)
		user.changeNext_move(CLICK_CD_MELEE)
		playsound(src.loc, "swing_hit", 25, 1)
		swirlie.visible_message("[user] slams the toilet seat onto [swirlie]'s head!", "[user] slams the toilet seat onto [swirlie]'s head!", "You hear reverberating porcelain.")
		swirlie.adjustBruteLoss(5)
		return

	if(cistern && !open)
		if(!contents.len)
			user << "The cistern is empty."
			return
		else
			var/obj/item/I = pick(contents)
			if(ishuman(user))
				user.put_in_hands(I)
			else
				I.loc = get_turf(src)
			user << "You find [I] in the cistern."
			w_items -= I.w_class
			return

	open = !open
	update_icon()

/obj/structure/toilet/update_icon()
	icon_state = "toilet[open][cistern]"

/obj/structure/toilet/attackby(obj/item/I, mob/living/user, params)
	if(istype(I, /obj/item/weapon/crowbar))
		user << "You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]."
		playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, 1)
		if(do_after(user, 30))
			user.visible_message("[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!", "You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!", "You hear grinding porcelain.")
			cistern = !cistern
			update_icon()
			return

	if(istype(I, /obj/item/weapon/grab))
		user.changeNext_move(CLICK_CD_MELEE)
		var/obj/item/weapon/grab/G = I
		if(!G.confirm())
			return
		if(isliving(G.affecting))
			var/mob/living/GM = G.affecting
			if(G.state >= GRAB_AGGRESSIVE)
				if(GM.loc != get_turf(src))
					user << "[GM] needs to be on [src]."
					return
				if(!swirlie)
					if(open)
						GM.visible_message("[user] starts to give [GM] a swirlie!", "[user] starts to give [GM] a swirlie!")
						swirlie = GM
						if(do_after(user, 30, 5, 0))
							GM.visible_message("[user] gives [GM] a swirlie!", "[user] gives [GM] a swirlie!", "You hear a toilet flushing.")
							if(iscarbon(GM))
								var/mob/living/carbon/C = GM
								if(!C.internal)
									C.adjustOxyLoss(5)
							else
								GM.adjustOxyLoss(5)
						swirlie = null
					else
						playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
						GM.visible_message("[user] slams [GM.name] into [src]!", "[user] slams [GM.name] into [src]!")
						GM.adjustBruteLoss(5)
			else
				user << "You need a tighter grip."

	if(cistern)
		if(I.w_class > 3)
			user << "[I] does not fit."
			return
		if(w_items + I.w_class > 5)
			user << "The cistern is full."
			return
		if(!user.drop_item())
			user << "\The [I] is stuck to your hand, you cannot put it in the cistern!"
			return
		I.loc = src
		w_items += I.w_class
		user << "You carefully place [I] into the cistern."
		return

/obj/structure/urinal
	name = "urinal"
	desc = "The HU-452, an experimental urinal."
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "urinal"
	density = 0
	anchored = 1

/obj/structure/urinal/attackby(obj/item/I, mob/user, params)
	if(istype(I, /obj/item/weapon/grab))
		var/obj/item/weapon/grab/G = I
		if(!G.confirm())
			return
		if(isliving(G.affecting))
			var/mob/living/GM = G.affecting
			if(G.state >= GRAB_AGGRESSIVE)
				if(GM.loc != get_turf(src))
					user << "[GM.name] needs to on [src]."
					return
				user.visible_message("[user] slams [GM] into [src]!", "You slam [GM] into [src]!")
				GM.adjustBruteLoss(8)
			else
				user << "You need a tighter grip."

/obj/machinery/shower
	name = "shower"
	desc = "The HS-451. Installed in the 2550s by the Nanotrasen Hygiene Division."
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "shower"
	density = 0
	anchored = 1
	use_power = 0
	var/on = 0
	var/obj/effect/mist/mymist = null
	var/ismist = 0				//needs a var so we can make it linger~
	var/watertemp = "normal"	//freezing, normal, or boiling
	var/mobpresent = 0		//true if there is a mob on the shower's loc, this is to ease process()

/obj/effect/mist
	name = "mist"
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "mist"
	layer = MOB_LAYER + 1
	anchored = 1
	mouse_opacity = 0

/obj/machinery/shower/attack_hand(mob/M)
	on = !on
	update_icon()
	add_fingerprint(M)
	if(on)
		for (var/atom/movable/G in loc)
			wash(G)
	else
		if(istype(loc, /turf/simulated))
			var/turf/simulated/tile = loc
			tile.MakeSlippery()

/obj/machinery/shower/attackby(obj/item/I, mob/user, params)
	if(I.type == /obj/item/device/analyzer)
		user << "The water temperature seems to be [watertemp]."
	if(istype(I, /obj/item/weapon/wrench))
		user << "You begin to adjust the temperature valve with \the [I]."
		if(do_after(user, 50))
			switch(watertemp)
				if("normal")
					watertemp = "freezing"
				if("freezing")
					watertemp = "boiling"
				if("boiling")
					watertemp = "normal"
			user.visible_message("[user] adjusts the shower with \the [I].", "You adjust the shower with \the [I] to [watertemp] temperature.")
			log_game("[key_name(user)] has wrenched a shower to [watertemp] at ([x],[y],[z])")
			add_hiddenprint(user)

/obj/machinery/shower/update_icon()	//this is terribly unreadable, but basically it makes the shower mist up
	overlays.Cut()					//once it's been on for a while, in addition to handling the water overlay.
	if(mymist)
		qdel(mymist)

	if(on)
		overlays += image('icons/obj/watercloset.dmi', src, "water", MOB_LAYER + 1, dir)
		if(watertemp == "freezing")
			return
		if(!ismist)
			spawn(50)
				if(src && on)
					ismist = 1
					mymist = new /obj/effect/mist(loc)
		else
			ismist = 1
			mymist = new /obj/effect/mist(loc)
	else if(ismist)
		ismist = 1
		mymist = new /obj/effect/mist(loc)
		spawn(250)
			if(src && !on && mymist)
				qdel(mymist)
				ismist = 0

/obj/machinery/shower/Crossed(atom/movable/O)
	..()
	wash(O)
	if(iscarbon(O) && on)
		var/mob/living/carbon/M=O
		M.slip(4,2,null,NO_SLIP_WHEN_WALKING)

/obj/machinery/shower/Uncrossed(atom/movable/O)
	if(ismob(O))
		mobpresent -= 1
	..()

//Yes, showers are super powerful as far as washing goes.
/obj/machinery/shower/proc/wash(atom/movable/O)
	if(!on) return
	if(ismob(O))
		mobpresent += 1
		check_heat(O)
	if(isliving(O))
		var/mob/living/L = O
		L.ExtinguishMob()
		L.fire_stacks = -20 //Douse ourselves with water to avoid fire more easily
		L << "You've been drenched in water!"
		if(iscarbon(O))
			var/mob/living/carbon/M = O
			if(M.r_hand)
				M.r_hand.clean_blood()
			if(M.l_hand)
				M.l_hand.clean_blood()
			if(M.back)
				if(M.back.clean_blood())
					M.update_inv_back(0)
			if(ishuman(M))
				var/mob/living/carbon/human/H = M
				var/washgloves = 1
				var/washshoes = 1
				var/washmask = 1
				var/washears = 1
				var/washglasses = 1

				if(H.wear_suit)
					washgloves = !(H.wear_suit.flags_inv & HIDEGLOVES)
					washshoes = !(H.wear_suit.flags_inv & HIDESHOES)

				if(H.head)
					washmask = !(H.head.flags_inv & HIDEMASK)
					washglasses = !(H.head.flags_inv & HIDEEYES)
					washears = !(H.head.flags_inv & HIDEEARS)

				if(H.wear_mask)
					if (washears)
						washears = !(H.wear_mask.flags_inv & HIDEEARS)
					if (washglasses)
						washglasses = !(H.wear_mask.flags_inv & HIDEEYES)

				if(H.head)
					if(H.head.clean_blood())
						H.update_inv_head(0)
				if(H.wear_suit)
					if(H.wear_suit.clean_blood())
						H.update_inv_wear_suit(0)
				else if(H.w_uniform)
					if(H.w_uniform.clean_blood())
						H.update_inv_w_uniform(0)
				if(H.gloves && washgloves)
					if(H.gloves.clean_blood())
						H.update_inv_gloves(0)
				if(H.shoes && washshoes)
					if(H.shoes.clean_blood())
						H.update_inv_shoes(0)
				if(H.wear_mask && washmask)
					if(H.wear_mask.clean_blood())
						H.update_inv_wear_mask(0)
				if(H.glasses && washglasses)
					if(H.glasses.clean_blood())
						H.update_inv_glasses(0)
				if(H.ears && washears)
					if(H.ears.clean_blood())
						H.update_inv_ears(0)
				if(H.belt)
					if(H.belt.clean_blood())
						H.update_inv_belt(0)
			else
				if(M.wear_mask)						//if the mob is not human, it cleans the mask without asking for bitflags
					if(M.wear_mask.clean_blood())
						M.update_inv_wear_mask(0)
		else
			O.clean_blood()

	if(isturf(loc))
		var/turf/tile = loc
		loc.clean_blood()
		for(var/obj/effect/E in tile)
			if(istype(E,/obj/effect/rune) || istype(E,/obj/effect/decal/cleanable) || istype(E,/obj/effect/overlay))
				qdel(E)

/obj/machinery/shower/process()
	if(!on || !mobpresent) return
	for(var/mob/living/carbon/C in loc)
		check_heat(C)

/obj/machinery/shower/proc/check_heat(mob/M)
	if(!on || watertemp == "normal") return
	if(iscarbon(M))
		var/mob/living/carbon/C = M

		if(watertemp == "freezing")
			C.bodytemperature = max(80, C.bodytemperature - 80)
			C << "The water is freezing!"
			return
		if(watertemp == "boiling")
			C.bodytemperature = min(500, C.bodytemperature + 35)
			C.adjustFireLoss(5)
			C << "The water is searing!"
			return

/obj/item/weapon/bikehorn/rubberducky
	name = "rubber ducky"
	desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~"	//thanks doohl
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "rubberducky"
	item_state = "rubberducky"

/obj/structure/sink
	name = "sink"
	icon = 'icons/obj/watercloset.dmi'
	icon_state = "sink"
	desc = "A sink used for washing one's hands and face."
	anchored = 1
	var/busy = 0 	//Something's being washed at the moment

/obj/structure/sink/attack_hand(mob/user)
	if(isrobot(user) || isAI(user))
		return
	if(!Adjacent(user))
		return

	if(busy)
		user << "Someone's already washing here."
		return

	user << "You start washing your hands."

	busy = 1
	sleep(40)
	busy = 0

	if(!Adjacent(user)) return		//Person has moved away from the sink

	user.clean_blood()
	user.visible_message("[user] washes their hands in [src].")

/obj/structure/sink/attackby(obj/item/O, mob/user, params)
	if(busy)
		user << "Someone's already washing here."
		return

	if(istype(O, /obj/item/weapon/reagent_containers))
		var/obj/item/weapon/reagent_containers/RG = O
		RG.reagents.add_reagent("water", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
		user << "You fill [RG] from [src]."
		return

	else if(istype(O, /obj/item/weapon/melee/baton))
		var/obj/item/weapon/melee/baton/B = O
		if(B.bcell)
			if(B.bcell.charge > 0 && B.status == 1)
				flick("baton_active", src)
				user.Stun(10)
				user.stuttering = 10
				user.Weaken(10)
				if(isrobot(user))
					var/mob/living/silicon/robot/R = user
					R.cell.charge -= 20
				else
					B.deductcharge(B.hitcost)
				user.visible_message( \
					"[user] was stunned by \his wet [O]!", \
					"[user] was stunned by \his wet [O]!")
				return

	var/turf/location = user.loc
	if(!isturf(location)) return

	var/obj/item/I = O
	if(!I || !istype(I,/obj/item)) return

	usr << "You start washing [I]."

	busy = 1
	sleep(40)
	busy = 0

	if(user.loc != location) return				//User has moved
	if(!I) return 								//Item's been destroyed while washing
	if(user.get_active_hand() != I) return		//Person has switched hands or the item in their hands

	O.clean_blood()
	user.visible_message( \
		"[user] washes [I] using [src].", \
		"You wash [I] using [src].")

/obj/structure/sink/kitchen
	name = "kitchen sink"
	icon_state = "sink_alt"

/obj/structure/sink/puddle	//splishy splashy ^_^
	name = "puddle"
	icon_state = "puddle"

/obj/structure/sink/puddle/attack_hand(mob/M as mob)
	icon_state = "puddle-splash"
	..()
	icon_state = "puddle"

/obj/structure/sink/puddle/attackby(obj/item/O as obj, mob/user as mob, params)
	icon_state = "puddle-splash"
	..()
	icon_state = "puddle"


code:
/* Windoor (window door) assembly -Nodrak
 * Step 1: Create a windoor out of rglass
 * Step 2: Add r-glass to the assembly to make a secure windoor (Optional)
 * Step 3: Rotate or Flip the assembly to face and open the way you want
 * Step 4: Wrench the assembly in place
 * Step 5: Add cables to the assembly
 * Step 6: Set access for the door.
 * Step 7: Screwdriver the door to complete
 */

/obj/structure/windoor_assembly
	icon = 'icons/obj/doors/windoor.dmi'

	name = "windoor Assembly"
	icon_state = "l_windoor_assembly01"
	anchored = 0
	density = 0
	dir = NORTH

	var/ini_dir
	var/obj/item/weapon/airlock_electronics/electronics = null
	var/created_name = null

	//Vars to help with the icon's name
	var/facing = "l"	//Does the windoor open to the left or right?
	var/secure = 0		//Whether or not this creates a secure windoor
	var/state = "01"	//How far the door assembly has progressed

/obj/structure/windoor_assembly/New(dir=NORTH)
	..()
	src.ini_dir = src.dir
	air_update_turf(1)

/obj/structure/windoor_assembly/Destroy()
	density = 0
	air_update_turf(1)
	..()

/obj/structure/windoor_assembly/Move()
	var/turf/T = loc
	..()
	move_update_air(T)

/obj/structure/windoor_assembly/update_icon()
	icon_state = "[facing]_[secure ? "secure_" : ""]windoor_assembly[state]"

/obj/structure/windoor_assembly/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/structure/windoor_assembly/CanAtmosPass(var/turf/T)
	if(get_dir(loc, T) == dir)
		return !density
	else
		return 1

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

/obj/structure/windoor_assembly/attackby(obj/item/W as obj, mob/user as mob, params)
	//I really should have spread this out across more states but thin little windoors are hard to sprite.
	add_fingerprint(user)
	switch(state)
		if("01")
			if(istype(W, /obj/item/weapon/weldingtool) && !anchored )
				var/obj/item/weapon/weldingtool/WT = W
				if (WT.remove_fuel(0,user))
					user.visible_message("[user] dissassembles the windoor assembly.", "You start to dissassemble the windoor assembly.")
					playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)

					if(do_after(user, 20))
						if(!src || !WT.isOn()) return
						user << "You dissasembled the windoor assembly!"
						var/obj/item/stack/sheet/rglass/RG = new (get_turf(src), 5)
						RG.add_fingerprint(user)
						if(secure)
							var/obj/item/stack/rods/R = new (get_turf(src), 4)
							R.add_fingerprint(user)
						qdel(src)
				else
					return

			//Wrenching an unsecure assembly anchors it in place. Step 4 complete
			if(istype(W, /obj/item/weapon/wrench) && !anchored)
				for(var/obj/machinery/door/window/WD in src.loc)
					if(WD.dir == src.dir)
						user << "There is already a windoor in that location."
						return
				playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
				user.visible_message("[user] secures the windoor assembly to the floor.", "You start to secure the windoor assembly to the floor.")

				if(do_after(user, 20))
					if(!src || src.anchored)
						return
					for(var/obj/machinery/door/window/WD in src.loc)
						if(WD.dir == src.dir)
							user << "There is already a windoor in that location."
							return
					user << "You've secured the windoor assembly!"
					src.anchored = 1
					if(src.secure)
						src.name = "secure anchored windoor assembly"
					else
						src.name = "anchored windoor assembly"

			//Unwrenching an unsecure assembly un-anchors it. Step 4 undone
			else if(istype(W, /obj/item/weapon/wrench) && anchored)
				playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
				user.visible_message("[user] unsecures the windoor assembly to the floor.", "You start to unsecure the windoor assembly to the floor.")

				if(do_after(user, 20))
					if(!src || !src.anchored)
						return
					user << "You've unsecured the windoor assembly!"
					src.anchored = 0
					if(src.secure)
						src.name = "secure windoor assembly"
					else
						src.name = "windoor assembly"

			//Adding plasteel makes the assembly a secure windoor assembly. Step 2 (optional) complete.
			else if(istype(W, /obj/item/stack/sheet/plasteel) && !secure)
				var/obj/item/stack/sheet/plasteel/P = W
				if(P.amount < 2)
					user << "You need more plasteel to do this."
					return
				user << "You start to reinforce the windoor with plasteel."

				if(do_after(user,20))
					if(!src || secure)
						return

					P.use(2)
					user << "You reinforce the windoor."
					src.secure = 1
					if(src.anchored)
						src.name = "secure anchored windoor assembly"
					else
						src.name = "secure windoor assembly"

			//Adding cable to the assembly. Step 5 complete.
			else if(istype(W, /obj/item/stack/cable_coil) && anchored)
				user.visible_message("[user] wires the windoor assembly.", "You start to wire the windoor assembly.")

				if(do_after(user, 20))
					if(!src || !src.anchored || src.state != "01")
						return
					var/obj/item/stack/cable_coil/CC = W
					CC.use(1)
					user << "You wire the windoor!"
					src.state = "02"
					if(src.secure)
						src.name = "secure wired windoor assembly"
					else
						src.name = "wired windoor assembly"
			else
				..()

		if("02")

			//Removing wire from the assembly. Step 5 undone.
			if(istype(W, /obj/item/weapon/wirecutters))
				playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
				user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly.")

				if(do_after(user, 20))
					if(!src || src.state != "02")
						return

					user << "You cut the windoor wires!"
					new/obj/item/stack/cable_coil(get_turf(user), 1)
					src.state = "01"
					if(src.secure)
						src.name = "secure anchored windoor assembly"
					else
						src.name = "anchored windoor assembly"

			//Adding airlock electronics for access. Step 6 complete.
			else if(istype(W, /obj/item/weapon/airlock_electronics))
				playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
				user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly.")
				user.drop_item()
				W.loc = src

				if(do_after(user, 20))
					if(!src || src.electronics)
						W.loc = src.loc
						return
					user << "You've installed the airlock electronics!"
					src.name = "near finished windoor assembly"
					src.electronics = W
				else
					W.loc = src.loc

			//Screwdriver to remove airlock electronics. Step 6 undone.
			else if(istype(W, /obj/item/weapon/screwdriver))
				if(!electronics)
					return

				playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
				user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to uninstall electronics from the airlock assembly.")

				if(do_after(user, 20))
					if(!src || !electronics)
						return
					user << "You've removed the airlock electronics!"
					src.name = "wired windoor assembly"
					var/obj/item/weapon/airlock_electronics/ae
					ae = electronics
					electronics = null
					ae.loc = src.loc

			else if(istype(W, /obj/item/weapon/pen))
				var/t = stripped_input(user, "Enter the name for the door.", src.name, src.created_name,MAX_NAME_LEN)
				if(!t)
					return
				if(!in_range(src, usr) && src.loc != usr)
					return
				created_name = t
				return

			//Crowbar to complete the assembly, Step 7 complete.
			else if(istype(W, /obj/item/weapon/crowbar))
				if(!src.electronics)
					usr << "The assembly is missing electronics."
					return
				usr << browse(null, "window=windoor_access")
				playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
				user.visible_message("[user] pries the windoor into the frame.", "You start prying the windoor into the frame.")

				if(do_after(user, 20))

					if(src.loc && src.electronics)

						density = 1 //Shouldn't matter but just incase
						user << "You finish the windoor!"

						if(secure)
							var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(src.loc)
							if(src.facing == "l")
								windoor.icon_state = "leftsecureopen"
								windoor.base_state = "leftsecure"
							else
								windoor.icon_state = "rightsecureopen"
								windoor.base_state = "rightsecure"
							windoor.dir = src.dir
							windoor.density = 0

							if(src.electronics.use_one_access)
								windoor.req_one_access = src.electronics.conf_access
							else
								windoor.req_access = src.electronics.conf_access
							windoor.electronics = src.electronics
							src.electronics.loc = windoor
							if(created_name)
								windoor.name = created_name
							qdel(src)
							windoor.close()

						else
							var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(src.loc)
							if(src.facing == "l")
								windoor.icon_state = "leftopen"
								windoor.base_state = "left"
							else
								windoor.icon_state = "rightopen"
								windoor.base_state = "right"
							windoor.dir = src.dir
							windoor.density = 0

							windoor.req_access = src.electronics.conf_access
							windoor.electronics = src.electronics
							src.electronics.loc = windoor
							if(created_name)
								windoor.name = created_name
							qdel(src)
							windoor.close()

			else
				..()

	//Update to reflect changes(if applicable)
	update_icon()

//Rotates the windoor assembly clockwise
/obj/structure/windoor_assembly/verb/revrotate()
	set name = "Rotate Windoor Assembly"
	set category = "Object"
	set src in oview(1)
	if(usr.stat || !usr.canmove || usr.restrained())
		return
	if (src.anchored)
		usr << "It is fastened to the floor; therefore, you can't rotate it!"
		return 0
	//if(src.state != "01")
		//update_nearby_tiles(need_rebuild=1) //Compel updates before

	src.dir = turn(src.dir, 270)

	//if(src.state != "01")
		//update_nearby_tiles(need_rebuild=1)

	src.ini_dir = src.dir
	update_icon()
	return

//Flips the windoor assembly, determines whather the door opens to the left or the right
/obj/structure/windoor_assembly/verb/flip()
	set name = "Flip Windoor Assembly"
	set category = "Object"
	set src in oview(1)
	if(usr.stat || !usr.canmove || usr.restrained())
		return

	if(src.facing == "l")
		usr << "The windoor will now slide to the right."
		src.facing = "r"
	else
		src.facing = "l"
		usr << "The windoor will now slide to the left."

	update_icon()
	return


code:
/obj/structure/window
	name = "window"
	desc = "A window."
	icon = 'icons/obj/structures.dmi'
	icon_state = "window"
	density = 1
	layer = 3.2//Just above doors
	pressure_resistance = 4*ONE_ATMOSPHERE
	anchored = 1.0
	flags = ON_BORDER
	var/maxhealth = 25
	var/health = 0
	var/ini_dir = null
	var/state = 0
	var/reinf = 0
	var/disassembled = 0
	var/wtype = "glass"
	var/fulltile = 0
	var/obj/item/stack/rods/storedrods
	var/obj/item/weapon/shard/storedshard
//	var/silicate = 0 // number of units of silicate
//	var/icon/silicateIcon = null // the silicated icon

/obj/structure/window/New(Loc,re=0)
	..()
	health = maxhealth
	if(re)	reinf = re
	storedshard = new/obj/item/weapon/shard(src)
	ini_dir = dir
	if(reinf)
		state = 2*anchored
		storedrods = new/obj/item/stack/rods(src)

	air_update_turf(1)
	update_nearby_icons()

	return

/obj/structure/window/bullet_act(var/obj/item/projectile/Proj)
	if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
		health -= Proj.damage
		update_nearby_icons()
	..()
	if(health <= 0)
		spawnfragments()
	return

/obj/structure/window/ex_act(severity, target)
	switch(severity)
		if(1.0)
			qdel(src)
			return
		if(2.0)
			spawnfragments()
			return
		if(3.0)
			if(prob(50))
				spawnfragments()
				return

/obj/structure/window/blob_act()
	spawnfragments()

/obj/structure/window/singularity_pull(S, current_size)
	if(current_size >= STAGE_FIVE)
		spawnfragments()

/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0)
	if(istype(mover) && mover.checkpass(PASSGLASS))
		return 1
	if(dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST)
		return 0	//full tile window, you can't move into it!
	if(get_dir(loc, target) == dir)
		return !density
	else
		return 1

/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
	if(istype(O) && O.checkpass(PASSGLASS))
		return 1
	if(get_dir(O.loc, target) == dir)
		return 0
	return 1

/obj/structure/window/hitby(AM as mob|obj)
	..()
	visible_message("[src] was hit by [AM].")
	var/tforce = 0
	if(ismob(AM))
		tforce = 40

	else if(isobj(AM))
		var/obj/item/I = AM
		tforce = I.throwforce

	if(reinf)
		tforce *= 0.25

	playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
	health = max(0, health - tforce)
	if(health <= 7 && !reinf)
		anchored = 0
		update_nearby_icons()
		step(src, get_dir(AM, src))

	if(health <= 0)
		spawnfragments()
	update_nearby_icons()

/obj/structure/window/attack_tk(mob/user as mob)
	user.changeNext_move(CLICK_CD_MELEE)
	user.visible_message("Something knocks on [src].")
	add_fingerprint(user)
	playsound(loc, 'sound/effects/Glassknock.ogg', 50, 1)

/obj/structure/window/attack_hulk(mob/living/carbon/human/user)
	if(!can_be_reached(user))
		return
	..(user, 1)
	user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
	user.visible_message("[user] smashes through [src]!")
	storedshard.add_fingerprint(user)
	if(storedrods)
		storedrods.add_fingerprint(user)
	hit(50)
	return 1

/obj/structure/window/attack_hand(mob/user as mob)
	if(!can_be_reached(user))
		return
	user.changeNext_move(CLICK_CD_MELEE)
	user.visible_message("[user] knocks on [src].")
	add_fingerprint(user)
	playsound(loc, 'sound/effects/Glassknock.ogg', 50, 1)

/obj/structure/window/attack_paw(mob/user as mob)
	return attack_hand(user)

/obj/structure/window/proc/attack_generic(mob/user as mob, damage = 0)	//used by attack_alien, attack_animal, and attack_slime
	if(!can_be_reached(user))
		return
	user.changeNext_move(CLICK_CD_MELEE)
	health -= damage
	if(health <= 0)
		user.visible_message("[user] smashes through [src]!")
		spawnfragments()
	else	//for nicer text~
		user.visible_message("[user] smashes into [src]!")
		playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)

/obj/structure/window/attack_alien(mob/living/user as mob)
	user.do_attack_animation(src)
	if(islarva(user)) return
	attack_generic(user, 15)
	update_nearby_icons()

/obj/structure/window/attack_animal(mob/living/user as mob)
	if(!isanimal(user))
		return

	var/mob/living/simple_animal/M = user
	M.do_attack_animation(src)
	if(M.melee_damage_upper <= 0)
		return

	attack_generic(M, M.melee_damage_upper)
	update_nearby_icons()

/obj/structure/window/attack_slime(mob/living/carbon/slime/user as mob)
	user.do_attack_animation(src)
	if(!user.is_adult)
		return

	attack_generic(user, rand(10, 15))
	update_nearby_icons()

/obj/structure/window/attackby(obj/item/I, mob/living/user, params)
	if(!can_be_reached(user))
		return 1 //skip the afterattack
	if(!user.IsAdvancedToolUser())
		if(I.damtype == BRUTE || I.damtype == BURN)
			user.changeNext_move(CLICK_CD_MELEE)
			hit(I.force)
		else
			playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
		..()
		return

	add_fingerprint(user)
	if(istype(I, /obj/item/weapon/screwdriver))
		playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
		if(reinf && (state == 2 || state == 1))
			user << (state == 2 ? "You begin to unscrew the window from the frame." : "You begin to screw the window to the frame.")
		else if(reinf && state == 0)
			user << (anchored ? "You begin to unscrew the frame from the floor." : "You begin to screw the frame to the floor.")
		else if(!reinf)
			user << (anchored ? "You begin to unscrew the window from the floor." : "You begin to screw the window to the floor.")

		if(do_after(user, 20))
			if(reinf && (state == 1 || state == 2))
				//If state was unfastened, fasten it, else do the reverse
				state = (state == 1 ? 2 : 1)
				user << (state == 1 ? "You have unfastened the window from the frame." : "You have fastened the window to the frame.")
			else if(reinf && state == 0)
				anchored = !anchored
				update_nearby_icons()
				user << (anchored ? "You have fastened the frame to the floor." : "You have unfastened the frame from the floor.")
			else if(!reinf)
				anchored = !anchored
				update_nearby_icons()
				user << (anchored ? "You have fastened the window to the floor." : "You have unfastened the window.")

	else if (istype(I, /obj/item/weapon/crowbar) && reinf && (state == 0 || state == 1))
		user << (state == 0 ? "You begin to lever the window into the frame." : "You begin to lever the window out of the frame.")
		playsound(loc, 'sound/items/Crowbar.ogg', 75, 1)
		if(do_after(user, 30))
			//If state was out of frame, put into frame, else do the reverse
			state = (state == 0 ? 1 : 0)
			user << (state == 1 ? "You have pried the window into the frame." : "You have pried the window out of the frame.")

	else if(istype(I, /obj/item/weapon/weldingtool))
		var/obj/item/weapon/weldingtool/WT = I
		if(user.a_intent == "help") //so you can still break windows with welding tools
			if(health < maxhealth)
				if(WT.remove_fuel(0,user))
					user << "You begin repairing [src]."
					playsound(loc, 'sound/items/Welder.ogg', 40, 1)
					if(do_after(user, 40))
						health = maxhealth
						playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
			else
				user << "[src] is already in good condition."
		update_nearby_icons()

	else if(istype(I, /obj/item/weapon/wrench) && !anchored)
		playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
		user << " You begin to disassemble [src]."
		if(do_after(user, 40))
			if(disassembled)
				return //Prevents multiple deconstruction attempts

			if(reinf)
				var/obj/item/stack/sheet/rglass/RG = new (user.loc)
				RG.add_fingerprint(user)
				if(fulltile) //fulltiles drop two panes
					RG = new (user.loc)
					RG.add_fingerprint(user)

			else
				var/obj/item/stack/sheet/glass/G = new (user.loc)
				G.add_fingerprint(user)
				if(fulltile)
					G = new (user.loc)
					G.add_fingerprint(user)

			playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
			disassembled = 1
			user << " You successfully disassemble [src]."
			qdel(src)

	else
		if(I.damtype == BRUTE || I.damtype == BURN)
			user.changeNext_move(CLICK_CD_MELEE)
			hit(I.force)
		else
			playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
		..()
	return

/obj/structure/window/mech_melee_attack(obj/mecha/M)
	if(..())
		hit(M.force, 1)

/obj/structure/window/proc/can_be_reached(mob/user)
	if(!fulltile)
		if(get_dir(user,src) & dir)
			for(var/obj/O in loc)
				if(!O.CanPass(user, user.loc, 1))
					return 0
	return 1

/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
	if(reinf) damage *= 0.5
	health = max(0, health - damage)
	update_nearby_icons()
	if(sound_effect)
		playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
	if(health <= 0)
		if(dir == SOUTHWEST)
			var/index = null
			index = 0
			while(index < 2)
				spawnfragments()
				index++
		else
			spawnfragments()
		return

/obj/structure/window/proc/spawnfragments()
	var/turf/T = loc
	storedshard.loc = T
	transfer_fingerprints_to(storedshard)
	if(storedrods)
		storedrods.loc = T
		transfer_fingerprints_to(storedrods)
	qdel(src)
	update_nearby_icons()

/obj/structure/window/verb/rotate()
	set name = "Rotate Window Counter-Clockwise"
	set category = "Object"
	set src in oview(1)

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

	if(anchored)
		usr << "It is fastened to the floor therefore you can't rotate it!"
		return 0

	dir = turn(dir, 90)
//	updateSilicate()
	air_update_turf(1)
	ini_dir = dir
	add_fingerprint(usr)
	return

/obj/structure/window/verb/revrotate()
	set name = "Rotate Window Clockwise"
	set category = "Object"
	set src in oview(1)

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

	if(anchored)
		usr << "It is fastened to the floor therefore you can't rotate it!"
		return 0

	dir = turn(dir, 270)
//	updateSilicate()
	air_update_turf(1)
	ini_dir = dir
	add_fingerprint(usr)
	return

/*
/obj/structure/window/proc/updateSilicate()
	if(silicateIcon && silicate)
		icon = initial(icon)

		var/icon/I = icon(icon,icon_state,dir)

		var/r = (silicate / 100) + 1
		var/g = (silicate / 70) + 1
		var/b = (silicate / 50) + 1
		I.SetIntensity(r,g,b)
		icon = I
		silicateIcon = I
*/

/obj/structure/window/Destroy()
	density = 0
	air_update_turf(1)
	if(!disassembled)
		playsound(src, "shatter", 70, 1)
	update_nearby_icons()
	..()

/obj/structure/window/Move()
	var/turf/T = loc
	..()
	dir = ini_dir
	move_update_air(T)

/obj/structure/window/CanAtmosPass(turf/T)
	if(get_dir(loc, T) == dir)
		return !density
	if(dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST)
		return !density
	return 1

//This proc is used to update the icons of nearby windows.
/obj/structure/window/proc/update_nearby_icons()
	update_icon()
	for(var/direction in cardinal)
		for(var/obj/structure/window/W in get_step(src,direction) )
			W.update_icon()

//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
/obj/structure/window/update_icon()
	//A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
	//this way it will only update full-tile ones
	//This spawn is here so windows get properly updated when one gets deleted.
	spawn(2)
		if(!src) return
		if(!fulltile)
			return
		var/junction = 0 //will be used to determine from which side the window is connected to other windows
		if(anchored)
			for(var/obj/structure/window/W in orange(src,1))
				if(W.anchored && W.density	&& W.fulltile) //Only counts anchored, not-destroyed fill-tile windows.
					if(src.wtype == W.wtype)
						if(abs(x-W.x)-abs(y-W.y) ) 		//doesn't count windows, placed diagonally to src
							junction |= get_dir(src,W)
		icon_state = "[initial(icon_state)][junction]"

		overlays.Cut()
		var/ratio = health / maxhealth
		ratio = Ceiling(ratio*4) * 25
		overlays += "damage[ratio]"
		return

/obj/structure/window/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
	if(exposed_temperature > T0C + 800)
		hit(round(exposed_volume / 100), 0)
	..()

/obj/structure/window/reinforced
	name = "reinforced window"
	icon_state = "rwindow"
	reinf = 1
	maxhealth = 50

/obj/structure/window/reinforced/tinted
	name = "tinted window"
	icon_state = "twindow"
	opacity = 1

/obj/structure/window/reinforced/tinted/frosted
	name = "frosted window"
	icon_state = "fwindow"

/* Full Tile Windows (more health) */

/obj/structure/window/fulltile
	dir = 5
	maxhealth = 50
	fulltile = 1

/obj/structure/window/reinforced/fulltile
	dir = 5
	maxhealth = 100
	fulltile = 1

/obj/structure/window/reinforced/tinted/fulltile
	dir = 5
	fulltile = 1

/obj/structure/window/shuttle
	name = "shuttle window"
	desc = "A reinforced, air-locked pod window."
	icon_state = "swindow"
	dir = 5
	maxhealth = 100
	wtype = "shuttle"
	fulltile = 1
	reinf = 1


code:
/obj/item/weapon/
	name = "weapon"
	icon = 'icons/obj/weapons.dmi'
	var/no_hitsound = 0 //Make this 1 if you want no hitsounds

/obj/item/weapon/New()
	..()
	if(!hitsound && !no_hitsound)
		if(damtype == "fire")
			hitsound = 'sound/items/welder.ogg'
		if(damtype == "brute")
			hitsound = "swing_hit"

/obj/item/weapon/Bump(mob/M as mob)
	spawn(0)
		..()
	return


code:
/*
/tg/station13 /atom/movable Pool:
---------------------------------
By RemieRichards

Creation/Deletion is laggy, so let's reduce reuse and recycle!

Locked to /atom/movable and it's subtypes due to Loc being a const var on /atom
but being read&write on /movable due to how they... move.

Usage:

To get a object, just called PoolOrNew(type, list of args to pass to New)

To put a object back in the pool, call place in pool.
This will call destroy on the object, set its loc to null,
and reset all of its vars to their default

You can override your object's destroy to return QDEL_HINT_PLACEINPOOL
to ensure its always placed in this pool (this will only be acted on if qdel calls destroy, and destroy will not get called twice)

Usage:

To get a object, just called PoolOrNew(type, list of args to pass to New)

To put a object back in the pool, call place in pool.
This will call destroy on the object, set its loc to null,
and reset all of its vars to their default

You can override your object's destroy to return QDEL_HINT_PLACEINPOOL
to ensure its always placed in this pool (this will only be acted on if qdel calls destroy, and destroy will not get called twice)

*/

var/global/list/GlobalPool = list()

//You'll be using this proc 90% of the time.
//It grabs a type from the pool if it can
//And if it can't, it creates one
//The pool is flexible and will expand to fit
//The new created atom when it eventually
//Goes into the pool

//Second argument can be a new location
//Or a list of arguments
//Either way it gets passed to new

/proc/PoolOrNew(var/get_type,var/second_arg)
	if(!get_type)
		return

	var/atom/movable/AM
	AM = GetFromPool(get_type,second_arg)

	if(!AM)
		if(ispath(get_type))
			if(islist(second_arg))
				AM = new get_type (arglist(second_arg))
			else
				AM = new get_type (second_arg)

	if(AM)
		return AM

/proc/GetFromPool(var/get_type,var/second_arg)
	if(!get_type)
		return 0

	if(isnull(GlobalPool[get_type]))
		return 0

	if(length(GlobalPool[get_type]) == 0)
		return 0

	var/atom/movable/AM = pick_n_take(GlobalPool[get_type])
	if(AM)
		AM.ResetVars()
		if(islist(second_arg))
			AM.loc = second_arg[1]
			AM.New(arglist(second_arg))
		else
			AM.loc = second_arg
			AM.New(second_arg)
		return AM
	return 0

/proc/PlaceInPool(var/atom/movable/AM, destroy = 1)
	if(!istype(AM))
		return

	if(AM in GlobalPool[AM.type])
		return

	if(!GlobalPool[AM.type])
		GlobalPool[AM.type] = list()

	GlobalPool[AM.type] |= AM

	if (destroy)
		AM.Destroy()

	AM.ResetVars()

/atom/movable/proc/ResetVars()
	var/list/excluded = list("animate_movement", "loc", "locs", "parent_type", "vars", "verbs", "type")

	for(var/V in vars)
		if(V in excluded)
			continue

		vars[V] = initial(vars[V])

	vars["loc"] = null


code:
/*
 	Miauw's big Say() rewrite.
	This file has the basic atom/movable level speech procs.
	And the base of the send_speech() proc, which is the core of saycode.
*/
var/list/freqtospan = list(
	"1351" = "sciradio",
	"1355" = "medradio",
	"1357" = "engradio",
	"1347" = "suppradio",
	"1349" = "servradio",
	"1359" = "secradio",
	"1353" = "comradio",
	"1447" = "aiprivradio",
	"1213" = "syndradio",
	"1441" = "dsquadradio"
	)

/atom/movable/proc/say(message)
	if(!can_speak())
		return
	if(message == "" || !message)
		return
	send_speech(message)

/atom/movable/proc/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq)
	return

/atom/movable/proc/can_speak()
	return 1

/atom/movable/proc/send_speech(message, range)
	var/rendered = compose_message(src, languages, message)
	for(var/atom/movable/AM in get_hearers_in_view(range, src))
		AM.Hear(rendered, src, languages, message)

/atom/movable/proc/compose_message(atom/movable/speaker, message_langs, raw_message, radio_freq)
	//This proc uses text() because it is faster than appending strings. Thanks BYOND.
	//Basic span
	var/spanpart1 = ""
	//Start name span.
	var/spanpart2 = ""
	//Radio freq/name display
	var/freqpart = radio_freq ? "\[[get_radio_name(radio_freq)]\] " : ""
	//Speaker name
	var/namepart =  "[speaker.GetVoice()][speaker.get_alt_name()]"
	//End name span.
	var/endspanpart = ""
	//Message
	var/messagepart = " [lang_treat(speaker, message_langs, raw_message)]"

	return "[spanpart1][spanpart2][freqpart][compose_track_href(speaker, namepart)][namepart][compose_job(speaker, message_langs, raw_message, radio_freq)][endspanpart][messagepart]"

/atom/movable/proc/compose_track_href(atom/movable/speaker, message_langs, raw_message, radio_freq)
	return ""

/atom/movable/proc/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq)
	return ""

/atom/movable/proc/say_quote(var/text)
	if(!text)
		return "says, \"...\""	//not the best solution, but it will stop a large number of runtimes. The cause is somewhere in the Tcomms code
	var/ending = copytext(text, length(text))
	if(ending == "?")
		return "asks, \"[text]\""
	if(copytext(text, length(text) - 1) == "!!")
		return "yells, \"[text]\""
	if(ending == "!")
		return "exclaims, \"[text]\""

	return "says, \"[text]\""

/atom/movable/proc/lang_treat(atom/movable/speaker, message_langs, raw_message)
	if(languages & message_langs)
		var/atom/movable/AM = speaker.GetSource()
		if(AM)
			return AM.say_quote(raw_message)
		else
			return speaker.say_quote(raw_message)
	else if(message_langs & HUMAN)
		var/atom/movable/AM = speaker.GetSource()
		if(AM)
			return AM.say_quote(stars(raw_message))
		else
			return speaker.say_quote(stars(raw_message))
	else if(message_langs & MONKEY)
		return "chimpers."
	else if(message_langs & ALIEN)
		return "hisses."
	else if(message_langs & ROBOT)
		return "beeps rapidly."
	else if(message_langs & DRONE)
		return "chitters."
	else
		return "makes a strange sound."

/proc/get_radio_span(freq)
	var/returntext = freqtospan["[freq]"]
	if(returntext)
		return returntext
	return "radio"

/proc/get_radio_name(freq)
	var/returntext = radiochannelsreverse["[freq]"]
	if(returntext)
		return returntext
	return "[copytext("[freq]", 1, 4)].[copytext("[freq]", 4, 5)]"

/atom/movable/proc/GetVoice()
	return name

/atom/movable/proc/IsVocal()
	return 1

/atom/movable/proc/get_alt_name()
	return

//these exist mostly to deal with the AIs hrefs and job stuff.
/atom/movable/proc/GetJob()
	return

/atom/movable/proc/GetSource()
	return

/atom/movable/proc/GetRadio()

/atom/movable/virtualspeaker
	var/job
	var/atom/movable/source
	var/obj/item/device/radio/radio

/atom/movable/virtualspeaker/GetJob()
	return job

/atom/movable/virtualspeaker/GetSource()
	return source

/atom/movable/virtualspeaker/GetRadio()
	return radio


code:
/obj/structure/shuttle
	name = "shuttle"
	icon = 'icons/turf/shuttle.dmi'

/obj/structure/shuttle/CanAtmosPass(turf/T)
	return 0
/obj/structure/shuttle/engine
	name = "engine"
	density = 1
	anchored = 1.0

/obj/structure/shuttle/engine/heater
	name = "heater"
	icon_state = "heater"

/obj/structure/shuttle/engine/platform
	name = "platform"
	icon_state = "platform"

/obj/structure/shuttle/engine/propulsion
	name = "propulsion"
	icon_state = "propulsion"
	opacity = 1

/obj/structure/shuttle/engine/propulsion/burst
	name = "burst"

/obj/structure/shuttle/engine/propulsion/burst/left
	name = "left"
	icon_state = "burst_l"

/obj/structure/shuttle/engine/propulsion/burst/right
	name = "right"
	icon_state = "burst_r"

/obj/structure/shuttle/engine/router
	name = "router"
	icon_state = "router"


code:
/mob/var/skincmds = list()
/obj/proc/SkinCmd(mob/user as mob, var/data as text)

/proc/SkinCmdRegister(var/mob/user, var/name as text, var/O as obj)
			user.skincmds[name] = O

/mob/verb/skincmd(data as text)
	set hidden = 1

	var/ref = copytext(data, 1, findtext(data, ";"))
	if (src.skincmds[ref] != null)
		var/obj/a = src.skincmds[ref]
		a.SkinCmd(src, copytext(data, findtext(data, ";") + 1))


code:
// OKAY I DON'T KNOW WHO THE FUCK ORIGINALLY CODED THIS BUT THEY ARE OFFICIALLY FIRED FOR BEING DRUNK AND STUPID
// FUCK YOU MYSTERY CODERS
// FOR THIS SHIT I'M GOING TO MAKE ALL MY COMMENTS IN CAPS

/atom
	var/list/canSmoothWith=list() // TYPE PATHS I CAN SMOOTH WITH~~~~~

// MOVED INTO UTILITY FUNCTION FOR LESS DUPLICATED CODE.
/atom/proc/findSmoothingNeighbors()
	// THIS IS A BITMAP BECAUSE NORTH/SOUTH/ETC ARE ALL BITFLAGS BECAUSE BYOND IS DUMB AND
	// DOESN'T FUCKING MAKE SENSE, BUT IT WORKS TO OUR ADVANTAGE
	var/junction = 0
	for(var/cdir in cardinal)
		var/turf/T = get_step(src,cdir)
		if(isSmoothableNeighbor(T))
			junction |= cdir
			continue // NO NEED FOR FURTHER SEARCHING IN THIS TILE
		for(var/atom/A in T)
			if(isSmoothableNeighbor(A))
				junction |= cdir
				break // NO NEED FOR FURTHER SEARCHING IN THIS TILE

	return junction

/atom/proc/isSmoothableNeighbor(var/atom/A)
	return is_type_in_list(A,canSmoothWith)

/turf/simulated/wall/isSmoothableNeighbor(var/atom/A)
	if(is_type_in_list(A,canSmoothWith))
		// COLON OPERATORS ARE TERRIBLE BUT I HAVE NO CHOICE
		if(src.mineral == A:mineral) //mineral not walltype so reinf still smooths with normal and vice versa
			return 1
	return 0

/**
 * WALL SMOOTHING SHIT
 *
 * IN /ATOM BECAUSE /TURFS ARE /ATOMS AND SO ARE /OBJ/STRUCTURE/FALSEWALLS
 * THIS IS STUPID BUT IS FAIRLY ELEGANT FOR BYOND
 *
 * HOWEVER, INSTEAD OF MAKING ONE BIG GODDAMN MONOLITHIC PROC LIKE A FUCKING
 * SHITTY FUNCTIONAL PROGRAMMER, WE WILL BE COOL AND MODERN AND USE INHERITANCE.
 */
/atom/proc/relativewall()
	return // DOES JACK SHIT BY DEFAULT. OLD BEHAVIOR WAS TO SPAM LOOPS ANYWAY.

/*
 * SEE?  NOW WE ONLY HAVE TO PROGRAM THIS SHIT INTO WHAT WE WANT TO SMOOTH
 * INSTEAD OF BEING DUMB AND HAVING A BIG FUCKING IFTREE WITH TYPECHECKS
 * MY GOD, WE COULD EVEN MOVE THE CODE TO BE WITH THE REST OF THE WALL'S CODE!
 * HOW FUCKING INNOVATIVE.  ISN'T INHERITANCE NICE?
 *
 * WE COULD STANDARDIZE THIS BUT EVERYONE'S A FUCKING SNOWFLAKE
 */
/turf/simulated/wall/relativewall()
	var/junction=findSmoothingNeighbors()
	icon_state = "[walltype][junction]" // WHY ISN'T THIS IN UPDATE_ICON OR SIMILAR

// AND NOW WE HAVE TO YELL AT THE NEIGHBORS FOR BEING LOUD AND NOT PAINTING WITH HOA-APPROVED COLORS
/atom/proc/relativewall_neighbours()
	// OPTIMIZE BY NOT CHECKING FOR NEIGHBORS IF WE DON'T FUCKING SMOOTH
	if(canSmoothWith.len>0)
		relativewall()
		for(var/cdir in cardinal)
			var/turf/T = get_step(src,cdir)
			if(isSmoothableNeighbor(T))
				T.relativewall()
			for(var/atom/A in T)
				if(isSmoothableNeighbor(A))
					A.relativewall()

/turf/simulated/wall/New()

	..()
	relativewall_neighbours()

/*/turf/simulated/shuttle/wall/New()

	spawn(20) //testing if this will make /obj/machinery/shuttle and /door count - It does, it stays.
		if(src.icon_state in list("wall1", "wall", "diagonalWall", "wall_floor", "wall_space")) //so wizard den, syndie shuttle etc will remain black
			for(var/turf/simulated/shuttle/wall/W in range(src,1))
				W.relativewall()

	..()*/

/turf/simulated/wall/Destroy()

	if(!del_suppress_resmoothing)
		spawn(10)
			relativewall_neighbours()

	// JESUS WHY
	for(var/direction in cardinal)
		for(var/obj/effect/glowshroom/shroom in get_step(src,direction))
			if(!shroom.floor) //shrooms drop to the floor
				shroom.floor = 1
				shroom.icon_state = "glowshroomf"
				shroom.pixel_x = 0
				shroom.pixel_y = 0
	..()

// DE-HACK
/turf/simulated/wall/vault/relativewall()
 	return

/obj/structure/alien/resin/relativewall()
	var/junction = findSmoothingNeighbors()
	icon_state = "[resintype][junction]"
	return


code:
/proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, surround = 1)

	soundin = get_sfx(soundin) // same sound for everyone

	if(isarea(source))
		ERROR("[source] is an area and is trying to make the sound: [soundin]")
		return

	var/frequency = get_rand_frequency() // Same frequency for everybody
	var/turf/turf_source = get_turf(source)

 	// Looping through the player list has the added bonus of working for mobs inside containers
	for (var/P in player_list)
		var/mob/M = P
		if(!M || !M.client)
			continue
		if(get_dist(M, turf_source) <= world.view + extrarange)
			var/turf/T = get_turf(M)
			if(T && T.z == turf_source.z)
				M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, surround)

/atom/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1)
	soundin = get_sfx(soundin)

	var/sound/S = sound(soundin)
	S.wait = 0 //No queue
	S.channel = 0 //Any channel
	S.volume = vol

	if (vary)
		if(frequency)
			S.frequency = frequency
		else
			S.frequency = get_rand_frequency()

	if(isturf(turf_source))
		var/turf/T = get_turf(src)

		//Atmosphere affects sound
		var/pressure_factor = 1
		var/datum/gas_mixture/hearer_env = T.return_air()
		var/datum/gas_mixture/source_env = turf_source.return_air()

		if(hearer_env && source_env)
			var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure())
			if(pressure < ONE_ATMOSPHERE)
				pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0)
		else //space
			pressure_factor = 0

		var/distance = get_dist(T, turf_source)
		if(distance <= 1)
			pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound

		S.volume *= pressure_factor
		//End Atmosphere affecting sound

		if(S.volume <= 0)
			return //No sound

		// 3D sounds, the technology is here!
		if (surround)
			var/dx = turf_source.x - T.x // Hearing from the right/left
			S.x = round(max(-SURROUND_CAP, min(SURROUND_CAP, dx)), 1)

			var/dz = turf_source.y - T.y // Hearing from infront/behind
			S.z = round(max(-SURROUND_CAP, min(SURROUND_CAP, dz)), 1)

		// The y value is for above your head, but there is no ceiling in 2d spessmens.
		S.y = 1
		S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)

	src << S

/mob/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, surround = 1)
	if(!client || ear_deaf > 0)
		return
	..()

/client/proc/playtitlemusic()
	if(!ticker || !ticker.login_music)	return
	if(prefs.toggles & SOUND_LOBBY)
		src << sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1) // MAD JAMS

/proc/get_rand_frequency()
	return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.

/proc/get_sfx(soundin)
	if(istext(soundin))
		switch(soundin)
			if ("shatter") soundin = pick('sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg')
			if ("explosion") soundin = pick('sound/effects/Explosion1.ogg','sound/effects/Explosion2.ogg')
			if ("sparks") soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks4.ogg')
			if ("rustle") soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg')
			if ("bodyfall") soundin = pick('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg')
			if ("punch") soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg')
			if ("clownstep") soundin = pick('sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg')
			if ("swing_hit") soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')
			if ("hiss") soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
			if ("pageturn") soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')
			if ("gunshot") soundin = pick('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg')
	return soundin


code:
/turf/simulated
	name = "station"
	var/wet = 0
	var/image/wet_overlay = null

	var/thermite = 0
	oxygen = MOLES_O2STANDARD
	nitrogen = MOLES_N2STANDARD
	var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed
	var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to

/turf/simulated/New()
	..()
	levelupdate()

/turf/simulated/proc/burn_tile()

/turf/simulated/proc/MakeSlippery(var/wet_setting = 1) // 1 = Water, 2 = Lube
	if(wet >= wet_setting)
		return
	wet = wet_setting
	if(wet_setting == 1)
		if(wet_overlay)
			overlays -= wet_overlay
			wet_overlay = null
		wet_overlay = image('icons/effects/water.dmi', src, "wet_floor_static")
		overlays += wet_overlay

	spawn(rand(790, 820)) // Purely so for visual effect
		if(!istype(src, /turf/simulated)) //Because turfs don't get deleted, they change, adapt, transform, evolve and deform. they are one and they are all.
			return
		if(wet > wet_setting) return
		wet = 0
		if(wet_overlay)
			overlays -= wet_overlay

/turf/simulated/Entered(atom/A, atom/OL)
	..()
	if (istype(A,/mob/living/carbon))
		var/mob/living/carbon/M = A
		if(M.lying)	return
		switch (src.wet)
			if(1) //wet floor
				if(!M.slip(4, 2, null, (NO_SLIP_WHEN_WALKING|STEP)))
					M.inertia_dir = 0
				return
			if(2) //lube
				M.slip(0, 7, null, (STEP|SLIDE|GALOSHES_DONT_HELP))


code:
//Janitors!  Janitors, janitors, janitors!  -Sayu

//Conspicuously not-recent versions of suspicious cleanables

/obj/effect/decal/cleanable/blood/old
	name = "dried blood"
	desc = "Looks like it's been here a while.  Eew."

/obj/effect/decal/cleanable/blood/old/New()
	..()
	icon_state += "-old"

/obj/effect/decal/cleanable/blood/gibs/old
	name = "old rotting gibs"
	desc = "Oh god, why didn't anyone clean this up?  It smells terrible."

/obj/effect/decal/cleanable/blood/gibs/old/New()
	..()
	icon_state += "-old"
	dir = pick(1,2,4,8)

/obj/effect/decal/cleanable/vomit/old
	name = "crusty dried vomit"
	desc = "You try not to look at the chunks, and fail."

/obj/effect/decal/cleanable/vomit/old/New()
	..()
	icon_state += "-old"

/obj/effect/decal/cleanable/robot_debris/old
	name = "dusty robot debris"
	desc = "Looks like nobody has touched this in a while."

//Making the station dirty, one tile at a time. Called by master controller's setup_objects

/turf/simulated/floor/proc/MakeDirty()
	if(prob(66))	//fastest possible exit 2/3 of the time
		return

	// These look weird if you make them dirty
	if(istype(src, /turf/simulated/floor/fancy/carpet) || istype(src, /turf/simulated/floor/fancy/grass) || istype(src, /turf/simulated/floor/plating/beach) || istype(src, /turf/simulated/floor/holofloor) || istype(src, /turf/simulated/floor/plating/snow) || istype(src, /turf/simulated/floor/plating/ironsand))
		return

	if(locate(/obj/structure/grille) in contents)
		return

	var/area/A = loc

				//zero dirt
	if(!istype(A) || istype(A, /area/centcom) || istype(A, /area/holodeck) || istype(A, /area/library) || istype(A, /area/janitor) || istype(A, /area/chapel) || istype(A, /area/mine/explored) || istype(A, /area/mine/unexplored) || istype(A, /area/solar) || istype(A, /area/atmos) || istype(A, /area/medical/virology))
		return

				//high dirt - 1/3
	if(istype(A, /area/toxins/test_area) || istype(A, /area/mine/production) || istype(A, /area/mine/living_quarters) || istype(A, /area/mine/north_outpost) || istype(A, /area/wreck) || istype(A, /area/derelict) || istype(A, /area/djstation))
		new /obj/effect/decal/cleanable/dirt(src)	//vanilla, but it works
		return

	if(prob(80))	//mid dirt  - 1/15
		return

	if(istype(A, /area/engine) || istype(A,/area/assembly) || istype(A,/area/maintenance) || istype(A,/area/construction))
	 	//Blood, sweat, and oil.  Oh, and dirt.
		if(prob(3))
			new /obj/effect/decal/cleanable/blood/old(src)
		else
			if(prob(35))
				if(prob(4))
					new /obj/effect/decal/cleanable/robot_debris/old(src)
				else
					new /obj/effect/decal/cleanable/oil(src)
			else
				new /obj/effect/decal/cleanable/dirt(src)
		return

	if(istype(A, /area/crew_quarters/toilet) || istype(A, /area/crew_quarters/locker/locker_toilet) || istype(A, /area/crew_quarters/bar))
		if(prob(40))
			if(prob(90))
				new /obj/effect/decal/cleanable/vomit/old(src)
			else
				new /obj/effect/decal/cleanable/blood/old(src)
		return

	if(istype(A, /area/quartermaster))
		if(prob(25))
			new /obj/effect/decal/cleanable/oil(src)
		return

	if(prob(75))	//low dirt  - 1/60
		return

	if(istype(A, /area/turret_protected) || istype(A, /area/security))	//chance of incident
		if(prob(20))
			if(prob(5))
				new /obj/effect/decal/cleanable/blood/gibs/old(src)
			else
				new /obj/effect/decal/cleanable/blood/old(src)
		return

	if(istype(A, /area/crew_quarters/kitchen))	//Kitchen messes
		if(prob(60))
			if(prob(50))
				new /obj/effect/decal/cleanable/egg_smudge(src)
			else
				new /obj/effect/decal/cleanable/flour(src)
		return

	if(istype(A, /area/medical))	//Kept clean, but chance of blood
		if(prob(66))
			if(prob(5))
				new /obj/effect/decal/cleanable/blood/gibs/old(src)
			else
				new /obj/effect/decal/cleanable/blood/old(src)
		else
			if(prob(30))
				if(istype(A, /area/medical/morgue))
					new /obj/item/weapon/ectoplasm(src)
				else
					new /obj/effect/decal/cleanable/vomit/old(src)
		return

	if(istype(A, /area/toxins))
		if(prob(20))
			new /obj/effect/decal/cleanable/greenglow(src)	//this cleans itself up but it might startle you when you see it.
		return

	return


code:
//This is so damaged or burnt tiles or platings don't get remembered as the default tile
var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3","damaged4",
				"damaged5","panelscorched","floorscorched1","floorscorched2","platingdmg1","platingdmg2",
				"platingdmg3","plating","light_on","light_on_flicker1","light_on_flicker2",
				"light_on_clicker3","light_on_clicker4","light_on_clicker5","light_broken",
				"light_on_broken","light_off","wall_thermite","grass1","grass2","grass3","grass4",
				"asteroid","asteroid_dug",
				"asteroid0","asteroid1","asteroid2","asteroid3","asteroid4",
				"asteroid5","asteroid6","asteroid7","asteroid8","asteroid9","asteroid10","asteroid11","asteroid12",
				"oldburning","light-on-r","light-on-y","light-on-g","light-on-b", "wood", "wood-broken",
				"carpetcorner", "carpetside", "carpet", "ironsand1", "ironsand2", "ironsand3", "ironsand4", "ironsand5",
				"ironsand6", "ironsand7", "ironsand8", "ironsand9", "ironsand10", "ironsand11",
				"ironsand12", "ironsand13", "ironsand14", "ironsand15")

/turf/simulated/floor
	//NOTE: Floor code has been refactored, many procs were removed and refactored
	//- you should use istype() if you want to find out whether a floor has a certain type
	//- floor_tile is now a path, and not a tile obj
	//- builtin_tile should be dropped if needed for performance reasons (eg singularity_act())
	name = "floor"
	icon = 'icons/turf/floors.dmi'

	var/icon_regular_floor = "floor" //used to remember what icon the tile should have by default
	var/icon_plating = "plating"
	icon_state = "floor" //fuck it
	thermal_conductivity = 0.040
	heat_capacity = 10000
	intact = 1
	var/lava = 0
	var/broken = 0
	var/burnt = 0
	var/floor_tile = null //tile that this floor drops
	var/obj/item/stack/tile/builtin_tile = null //needed for performance reasons when the singularity rips off floor tiles
	var/list/broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
	var/list/burnt_states = list()
	var/dirt = 0
	var/ignoredirt = 0

/turf/simulated/floor/proc/try_destroy()
	return

/turf/simulated/floor/New()
	..()
	if(icon_state in icons_to_ignore_at_floor_init) //so damaged/burned tiles or plating icons aren't saved as the default
		icon_regular_floor = "floor"
	else
		icon_regular_floor = icon_state
	if(floor_tile)
		builtin_tile = new floor_tile

/turf/simulated/floor/ex_act(severity, target)
	..()
	if(target == src)
		src.ChangeTurf(src.baseturf)
	if(target != null)
		ex_act(3)
		return
	switch(severity)
		if(1.0)
			src.ChangeTurf(src.baseturf)
		if(2.0)
			switch(pick(1,2;75,3))
				if(1)
					src.ReplaceWithLattice()
					if(prob(33)) new /obj/item/stack/sheet/metal(src)
				if(2)
					src.ChangeTurf(src.baseturf)
				if(3)
					if(prob(80))
						src.break_tile_to_plating()
					else
						src.break_tile()
					src.hotspot_expose(1000,CELL_VOLUME)
					if(prob(33)) new /obj/item/stack/sheet/metal(src)
		if(3.0)
			if (prob(50))
				src.break_tile()
				src.hotspot_expose(1000,CELL_VOLUME)
	return

/turf/simulated/floor/blob_act()
	return

/turf/simulated/floor/proc/update_icon()
	if(lava)
		return 0
	if(air)
		update_visuals(air)
	return 1

/turf/simulated/floor/attack_paw(mob/user as mob)
	return src.attack_hand(user)

/turf/simulated/floor/proc/gets_drilled()
	return

/turf/simulated/floor/proc/break_tile_to_plating()
	var/turf/simulated/floor/plating/T = make_plating()
	T.break_tile()

/turf/simulated/floor/proc/break_tile()
	if(broken)
		return
	icon_state = pick(broken_states)
	broken = 1

/turf/simulated/floor/burn_tile()
	if(broken || burnt)
		return
	if(burnt_states.len)
		icon_state = pick(burnt_states)
	else
		icon_state = pick(broken_states)
	burnt = 1

/turf/simulated/floor/proc/make_plating()
	return ChangeTurf(/turf/simulated/floor/plating)

/turf/simulated/floor/ChangeTurf(turf/simulated/floor/T)
	if(!istype(src,/turf/simulated/floor)) return ..() //fucking turfs switch the fucking src of the fucking running procs
	if(!ispath(T,/turf/simulated/floor)) return ..()
	var/old_icon = icon_regular_floor
	var/old_dir = dir
	var/turf/simulated/floor/W = ..()
	W.icon_regular_floor = old_icon
	W.dir = old_dir
	W.update_icon()
	return W

/turf/simulated/floor/attackby(obj/item/C as obj, mob/user as mob, params)
	if(!C || !user)
		return 1
	if(..())
		return 1
	if(intact && istype(C, /obj/item/weapon/crowbar))
		if(broken || burnt)
			broken = 0
			burnt = 0
			user << "You remove the broken plating."
		else
			if(istype(src, /turf/simulated/floor/wood))
				user << "You forcefully pry off the planks, destroying them in the process."
			else
				user << "You remove the floor tile."
				builtin_tile.loc = src
		make_plating()
		playsound(src, 'sound/items/Crowbar.ogg', 80, 1)
		return 1
	return 0

/turf/simulated/floor/singularity_pull(S, current_size)
	if(current_size == STAGE_THREE)
		if(prob(30))
			if(builtin_tile)
				builtin_tile.loc = src
				make_plating()
	else if(current_size == STAGE_FOUR)
		if(prob(50))
			if(builtin_tile)
				builtin_tile.loc = src
				make_plating()
	else if(current_size >= STAGE_FIVE)
		if(builtin_tile)
			if(prob(70))
				builtin_tile.loc = src
				make_plating()
		else if(prob(50))
			ReplaceWithLattice()

/turf/simulated/floor/narsie_act()
	if(prob(20))
		ChangeTurf(/turf/simulated/floor/plasteel/cult)

/turf/simulated/floor/Entered(atom/A, atom/OL)
	..()
	if(!ignoredirt)
		if(has_gravity(src))
			if(istype(A,/mob/living/carbon))
				var/mob/living/carbon/M = A
				if(M.lying)	return
				if(prob(80))
					dirt++
				var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src)
				if(dirt >= 100)
					if(!dirtoverlay)
						dirtoverlay = new/obj/effect/decal/cleanable/dirt(src)
						dirtoverlay.alpha = 10
					else if(dirt > 100)
						dirtoverlay.alpha = min(dirtoverlay.alpha+10, 200)


code:
/* In this file:
 * Wood floor
 * Grass floor
 * Carpet floor
 */

/turf/simulated/floor/wood
	icon_state = "wood"
	floor_tile = /obj/item/stack/tile/wood
	broken_states = list("wood-broken", "wood-broken2", "wood-broken3", "wood-broken4", "wood-broken5", "wood-broken6", "wood-broken7")

/turf/simulated/floor/wood/attackby(obj/item/C as obj, mob/user as mob, params)
	if(..())
		return
	if(istype(C, /obj/item/weapon/screwdriver))
		if(broken || burnt)
			return
		user << "You unscrew the planks."
		new floor_tile(src)
		make_plating()
		playsound(src, 'sound/items/Screwdriver.ogg', 80, 1)
		return

/turf/simulated/floor/fancy
	name = "fancy floor"

//updates neighboring fancy flooring
/turf/simulated/floor/fancy/proc/fancy_update(turf/simulated/floor/fancy/fancy_type, later = 0)
	spawn(later) //sorry
		for(var/direction in list(1,2,4,8,5,6,9,10))
			if(istype(get_step(src,direction), fancy_type))
				var/turf/simulated/floor/fancy/FF = get_step(src,direction)
				FF.update_icon()

/turf/simulated/floor/fancy/ChangeTurf(turf/T as turf)
	fancy_update(type, 2) //needs a spawn() because we don't want to update before we're ChangeTurf()ed
	return ..()

/turf/simulated/floor/fancy/grass
	name = "Grass patch"
	icon_state = "grass1"
	floor_tile = /obj/item/stack/tile/grass
	broken_states = list("sand1", "sand2", "sand3")
	ignoredirt = 1

/turf/simulated/floor/fancy/grass/New()
	..()
	icon_state = "grass[pick("1","2","3","4")]"
	spawn(1)
		update_icon()
		fancy_update(type)

/turf/simulated/floor/fancy/grass/attackby(obj/item/C as obj, mob/user as mob, params)
	if(..())
		return
	if(istype(C, /obj/item/weapon/shovel))
		new /obj/item/weapon/ore/glass(src)
		new /obj/item/weapon/ore/glass(src) //Make some sand if you shovel grass
		user << "You shovel the grass."
		make_plating()

/turf/simulated/floor/fancy/grass/return_siding_icon_state()
	..()
	var/dir_sum = 0
	for(var/direction in cardinal)
		if(!istype(get_step(src,direction), /turf/simulated/floor/fancy/grass))
			dir_sum += direction
	if(dir_sum)
		return "wood_siding[dir_sum]"
	else
		return 0

/turf/simulated/floor/fancy/carpet
	name = "Carpet"
	icon_state = "carpet"
	floor_tile = /obj/item/stack/tile/carpet
	broken_states = list("carpet-broken")

/turf/simulated/floor/fancy/carpet/New()
	..()
	spawn(1)
		update_icon()
		fancy_update(type)

/turf/simulated/floor/fancy/carpet/update_icon()
	if(!..())
		return 0
	if(!broken && !burnt)
		if(icon_state == "carpetsymbol") //le snowflake :^)
			return

		var/connectdir = 0
		for(var/direction in cardinal)
			if(istype(get_step(src,direction),/turf/simulated/floor/fancy/carpet))
				var/turf/simulated/floor/fancy/carpet/FF = get_step(src,direction)
				if(istype(FF, /turf/simulated/floor/fancy/carpet))
					connectdir |= direction

		//Check the diagonal connections for corners, where you have, for example, connections both north and east. In this case it checks for a north-east connection to determine whether to add a corner marker or not.
		var/diagonalconnect = 0 //1 = NE; 2 = SE; 4 = NW; 8 = SW

		//Northeast
		if(connectdir & NORTH && connectdir & EAST)
			if(istype(get_step(src,NORTHEAST),/turf/simulated/floor))
				var/turf/simulated/floor/FF = get_step(src,NORTHEAST)
				if(istype(FF, /turf/simulated/floor/fancy/carpet))
					diagonalconnect |= 1

		//Southeast
		if(connectdir & SOUTH && connectdir & EAST)
			if(istype(get_step(src,SOUTHEAST),/turf/simulated/floor))
				var/turf/simulated/floor/FF = get_step(src,SOUTHEAST)
				if(istype(FF, /turf/simulated/floor/fancy/carpet))
					diagonalconnect |= 2

		//Northwest
		if(connectdir & NORTH && connectdir & WEST)
			if(istype(get_step(src,NORTHWEST),/turf/simulated/floor))
				var/turf/simulated/floor/FF = get_step(src,NORTHWEST)
				if(istype(FF, /turf/simulated/floor/fancy/carpet))
					diagonalconnect |= 4

		//Southwest
		if(connectdir & SOUTH && connectdir & WEST)
			if(istype(get_step(src,SOUTHWEST),/turf/simulated/floor))
				var/turf/simulated/floor/FF = get_step(src,SOUTHWEST)
				if(istype(FF, /turf/simulated/floor/fancy/carpet))
					diagonalconnect |= 8

		icon_state = "carpet[connectdir]-[diagonalconnect]"


code:
/* In this file:
 *
 * Light floor
 */
/turf/simulated/floor/light
    name = "Light floor"
    light_range = 5
    icon_state = "light_on"
    floor_tile = /obj/item/stack/tile/light
    broken_states = list("light_broken")
    var/on = 1
    var/state //0 = fine, 1 = flickering, 2 = breaking, 3 = broken
    var/list/coloredlights = list("g", "r", "y", "b", "p", "w", "s","o","g")
    var/currentcolor = 1
/turf/simulated/floor/light/New()
    ..()
    spawn(5) //needed because when placing a light floor tile it will take a short while before setting state
        if(istype(builtin_tile, /obj/item/stack/tile/light))
            var/obj/item/stack/tile/light/L = builtin_tile
            L.state = state
    update_icon()
/turf/simulated/floor/light/update_icon()
    ..()
    if(on)
        switch(state)
            if(0)
                icon_state = "light_on-[coloredlights[currentcolor]]"
                set_light(1)
            if(1)
                var/num = pick("1","2","3","4")
                icon_state = "light_on_flicker[num]"
                set_light(1)
            if(2)
                icon_state = "light_on_broken"
                set_light(1)
            if(3)
                icon_state = "light_off"
                set_light(0)
    else
        set_light(0)
        icon_state = "light_off"
/turf/simulated/floor/light/ChangeTurf(turf/T as turf)
    set_light(0)
    ..()
/turf/simulated/floor/light/attack_hand(mob/user as mob)
    if(!on)
        on = 1
        currentcolor = 1
        return
    else
        currentcolor++
    if ( currentcolor > coloredlights.len)
        on = 0
    update_icon()
    ..()  //I am not sure what the parent procs have for attack_hand, best to check later.

/turf/simulated/floor/light/attack_ai(mob/user)
    attack_hand(user)

/turf/simulated/floor/light/attackby(obj/item/C as obj, mob/user as mob, params)
    if(..())
        return
    if(istype(C,/obj/item/weapon/light/bulb)) //only for light tiles
        if(state)
            user.drop_item()
            qdel(C)
            state = 0 //fixing it by bashing it with a light bulb, fun eh?
            update_icon()
            user << "You replace the light bulb."
        else
            user << "The lightbulb seems fine, no need to replace it."
        return


code:
/* In this file:
 *
 * Plasma floor
 * Gold floor
 * Silver floor
 * Bananium floor
 * Diamond floor
 * Uranium floor
 */

/turf/simulated/floor/mineral
	name = "mineral floor"
	icon_state = ""
	var/list/icons = list()

/turf/simulated/floor/mineral/New()
	..()
	broken_states = list("[initial(icon_state)]_dam")

/turf/simulated/floor/mineral/update_icon()
	if(!..())
		return 0
	if(!broken && !burnt)
		if( !(icon_state in icons) )
			icon_state = initial(icon_state)

//PLASMA

/turf/simulated/floor/mineral/plasma
	name = "plasma floor"
	icon_state = "plasma"
	floor_tile = /obj/item/stack/tile/mineral/plasma
	icons = list("plasma","plasma_dam")

/turf/simulated/floor/mineral/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
	if(exposed_temperature > 300)
		PlasmaBurn()

/turf/simulated/floor/mineral/plasma/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
	if(is_hot(W) > 300)//If the temperature of the object is over 300, then ignite
		message_admins("Plasma flooring was ignited by [key_name(user, user.client)](?) in ([x],[y],[z] - JMP)",0,1)
		log_game("Plasma flooring was ignited by [user.ckey]([user]) in ([x],[y],[z])")
		ignite(is_hot(W))
		return
	..()

/turf/simulated/floor/mineral/plasma/proc/PlasmaBurn()
	make_plating()
	atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, 20)

/turf/simulated/floor/mineral/plasma/proc/ignite(exposed_temperature)
	if(exposed_temperature > 300)
		PlasmaBurn()

//GOLD

/turf/simulated/floor/mineral/gold
	name = "gold floor"
	icon_state = "gold"
	floor_tile = /obj/item/stack/tile/mineral/gold
	icons = list("gold","gold_dam")

//SILVER

/turf/simulated/floor/mineral/silver
	name = "silver floor"
	icon_state = "silver"
	floor_tile = /obj/item/stack/tile/mineral/silver
	icons = list("silver","silver_dam")

//BANANIUM

/turf/simulated/floor/mineral/bananium
	name = "bananium floor"
	icon_state = "bananium"
	floor_tile = /obj/item/stack/tile/mineral/bananium
	icons = list("bananium","bananium_dam")
	var/spam_flag = 0

/turf/simulated/floor/mineral/bananium/Entered(var/mob/AM)
	.=..()
	if(!.)
		if(istype(AM))
			squeek()

/turf/simulated/floor/mineral/bananium/attackby(obj/item/weapon/W, mob/user, params)
	.=..()
	if(!.)
		honk()

/turf/simulated/floor/mineral/bananium/attack_hand(mob/user)
	.=..()
	if(!.)
		honk()

/turf/simulated/floor/mineral/bananium/attack_paw(mob/user)
	.=..()
	if(!.)
		honk()

/turf/simulated/floor/mineral/bananium/proc/honk()
	if(!spam_flag)
		spam_flag = 1
		playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
		spawn(20)
			spam_flag = 0

/turf/simulated/floor/mineral/bananium/proc/squeek()
	if(!spam_flag)
		spam_flag = 1
		playsound(src, "clownstep", 50, 1)
		spawn(10)
			spam_flag = 0

/turf/simulated/floor/mineral/bananium/airless
	oxygen = 0.01
	nitrogen = 0.01
	temperature = TCMB

//DIAMOND

/turf/simulated/floor/mineral/diamond
	name = "diamond floor"
	icon_state = "diamond"
	floor_tile = /obj/item/stack/tile/mineral/diamond
	icons = list("diamond","diamond_dam")

//URANIUM

/turf/simulated/floor/mineral/uranium
	name = "uranium floor"
	icon_state = "uranium"
	floor_tile = /obj/item/stack/tile/mineral/uranium
	icons = list("uranium","uranium_dam")
	var/last_event = 0
	var/active = null

/turf/simulated/floor/mineral/uranium/Entered(var/mob/AM)
	.=..()
	if(!.)
		if(istype(AM))
			radiate()

/turf/simulated/floor/mineral/uranium/attackby(obj/item/weapon/W, mob/user, params)
	.=..()
	if(!.)
		radiate()

/turf/simulated/floor/mineral/uranium/attack_hand(mob/user)
	.=..()
	if(!.)
		radiate()

/turf/simulated/floor/mineral/uranium/attack_paw(mob/user)
	.=..()
	if(!.)
		radiate()

/turf/simulated/floor/mineral/uranium/proc/radiate()
	if(!active)
		if(world.time > last_event+15)
			active = 1
			for(var/mob/living/L in range(3,src))
				L.apply_effect(1,IRRADIATE,0)
			for(var/turf/simulated/floor/mineral/uranium/T in range(3,src))
				T.radiate()
			last_event = world.time
			active = 0
			return


code:
/* In this file:
 *
 * Commemorative Plaque
 * Vault floor
 * Vault wall (why)
 * Blue grid
 * Green grid
 * Shuttle floor
 * Beach
 * Ocean
 * Iron Sand
 * Snow
 * High-traction
 */

/turf/simulated/floor/goonplaque
	name = "Commemorative Plaque"
	icon_state = "plaque"
	desc = "\"This is a plaque in honour of our comrades on the G4407 Stations. Hopefully TG4407 model can live up to your fame and fortune.\" Scratched in beneath that is a crude image of a meteor and a spaceman. The spaceman is laughing. The meteor is exploding."
	floor_tile = /obj/item/stack/tile/plasteel

/turf/simulated/floor/vault
	icon_state = "rockvault"
	floor_tile = /obj/item/stack/tile/plasteel

/turf/simulated/floor/bluegrid
	icon = 'icons/turf/floors.dmi'
	icon_state = "bcircuit"
	floor_tile = /obj/item/stack/tile/plasteel

/turf/simulated/floor/greengrid
	icon = 'icons/turf/floors.dmi'
	icon_state = "gcircuit"
	floor_tile = /obj/item/stack/tile/plasteel

/turf/simulated/floor/plating/beach
	name = "Beach"
	icon = 'icons/misc/beach.dmi'
	ignoredirt = 1

/turf/simulated/floor/beach/ex_act(severity, target)
	contents_explosion(severity, target)

/turf/simulated/floor/plating/beach/sand
	name = "Sand"
	icon_state = "sand"

/turf/simulated/floor/plating/beach/coastline
	name = "Coastline"
	icon = 'icons/misc/beach2.dmi'
	icon_state = "sandwater"

/turf/simulated/floor/plating/beach/water
	name = "Water"
	icon_state = "water"

/turf/simulated/floor/plating/ironsand/New()
	..()
	name = "Iron Sand"
	icon_state = "ironsand[rand(1,15)]"
	ignoredirt = 1

/turf/simulated/floor/plating/snow
	name = "snow"
	icon = 'icons/turf/snow.dmi'
	icon_state = "snow"
	ignoredirt = 1

/turf/simulated/floor/plating/snow/ex_act(severity, target)
	contents_explosion(severity, target)

/turf/simulated/floor/plating/snow/gravsnow
	icon_state = "gravsnow"

/turf/simulated/floor/plating/snow/gravsnow/corner
	icon_state = "gravsnow_corner"

/turf/simulated/floor/plating/snow/gravsnow/surround
	icon_state = "gravsnow_surround"

/turf/simulated/floor/noslip
	name = "high-traction floor"
	icon_state = "noslip"
	floor_tile = /obj/item/stack/tile/noslip
	broken_states = list("noslip-damaged1","noslip-damaged2","noslip-damaged3")
	burnt_states = list("noslip-scorched1","noslip-scorched2")

/turf/simulated/floor/noslip/MakeSlippery()
	return

/turf/simulated/floor/plating/sand
	name = "sand"
	icon = 'icons/misc/beach.dmi'
	icon_state = "sand"

/turf/simulated/floor/plating/maze
	name = "maze floor"
	heat_capacity = 6000000 // it's like another shoah
	icon = 'icons/misc/beach.dmi'
	icon_state= "sand"
	toxins = 229.8
	oxygen = 0
	carbon_dioxide = 173.4
	nitrogen = 135.1
	temperature = 363.9

/turf/simulated/floor/plating/dust
	name = "dust"
	icon = 'icons/turf/floors.dmi'
	icon_state = "asteroid"


code:
/turf/simulated/floor/plasteel
	icon_state = "floor"
	floor_tile = /obj/item/stack/tile/plasteel
	broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5")
	burnt_states = list("floorscorched1", "floorscorched2")

/turf/simulated/floor/plasteel/update_icon()
	if(!..())
		return 0
	if(!broken && !burnt)
		icon_state = icon_regular_floor

/turf/simulated/floor/plasteel/black
	icon_state = "dark"

/turf/simulated/floor/plasteel/green
	icon_state = "greenfull"
/turf/simulated/floor/plasteel/green/side
	icon_state = "green"
/turf/simulated/floor/plasteel/green/corner
	icon_state = "greencorner"

/turf/simulated/floor/plasteel/darkgreen
	icon_state = "darkgreenfull"
/turf/simulated/floor/plasteel/darkgreen/side
	icon_state = "darkgreen"
/turf/simulated/floor/plasteel/darkgreen/corner
	icon_state = "darkgreencorners"

/turf/simulated/floor/plasteel/brown
	icon_state = "brown"
/turf/simulated/floor/plasteel/brown/corner
	icon_state = "browncorner"

/turf/simulated/floor/plasteel/red
	icon_state = "redfull"
/turf/simulated/floor/plasteel/red/side
	icon_state = "red"
/turf/simulated/floor/plasteel/red/corner
	icon_state = "redcorner"

/turf/simulated/floor/plasteel/darkred
	icon_state = "darkredfull"
/turf/simulated/floor/plasteel/darkred/side
	icon_state = "darkred"
/turf/simulated/floor/plasteel/darkred/corner
	icon_state = "darkredcorners"

/turf/simulated/floor/plasteel/neutral
	icon_state = "neutralfull"
/turf/simulated/floor/plasteel/neutral/side
	icon_state = "neutral"
/turf/simulated/floor/plasteel/neutral/corner
	icon_state = "neutralcorner"

/turf/simulated/floor/plasteel/warning
	icon_state = "warning"
/turf/simulated/floor/plasteel/warning/corner
	icon_state = "warningcorner"

/turf/simulated/floor/plasteel/redyellow
	icon_state = "redyellowfull"
/turf/simulated/floor/plasteel/redyellow/side
	icon_state = "redyellow"

/turf/simulated/floor/plasteel/redblue
	icon_state = "redbluefull"
/turf/simulated/floor/plasteel/redblue/side
	icon_state = "redblue"

/turf/simulated/floor/plasteel/darkwarning
	icon_state = "warndark"
/turf/simulated/floor/plasteel/darkwarning/corner
	icon_state = "warndarkcorners"

/turf/simulated/floor/plasteel/yellowsiding
	icon_state = "yellowsiding"
/turf/simulated/floor/plasteel/yellowsiding/corner
	icon_state = "yellowcornersiding"

/turf/simulated/floor/plasteel/podhatch
	icon_state = "podhatch"
/turf/simulated/floor/plasteel/podhatch/corner
	icon_state = "podhatchcorner"

/turf/simulated/floor/plasteel/loadingarea
	icon_state = "loadingarea"

/turf/simulated/floor/plasteel/delivery
	icon_state = "delivery"

/turf/simulated/floor/plasteel/freezer
	icon_state = "freezerfloor"

/turf/simulated/floor/plasteel/bar
	icon_state = "bar"

/turf/simulated/floor/plasteel/grimy
	icon_state = "grimy"

/turf/simulated/floor/plasteel/cafeteria
	icon_state = "cafeteria"

/turf/simulated/floor/plasteel/cult
	icon_state = "cult"
	name = "engraved floor"

/turf/simulated/floor/plasteel/cult/narsie_act()
	return

/turf/simulated/floor/plasteel/shuttle
	icon = 'icons/turf/shuttle.dmi'
	icon_state = "floor"
	shuttle = 1

/turf/simulated/floor/plasteel/shuttle/red
	name = "Brig floor"
	icon_state = "floor4"