diff --git a/code/WorkInProgress/Aryn/Lighting/Controller.dm b/code/WorkInProgress/Aryn/Lighting/Controller.dm
new file mode 100644
index 00000000000..aaeb9ce17f8
--- /dev/null
+++ b/code/WorkInProgress/Aryn/Lighting/Controller.dm
@@ -0,0 +1,115 @@
+/*
+
+Overview:
+ Unlike the previous lighting controller, this is mostly here to hold global lighting procs and vars.
+ It does not process every tick, because not even DAL did something so stupid.
+
+Global Vars:
+ initial_lights - This holds all lights formed before the lighting controller started up. It becomes null on initialization.
+
+Class Vars:
+ starlight - The light value of space.
+
+ icon_updates - The list of turfs which need an update to their overlays.
+
+ light_border - Space turfs which are adjacent to non-space turfs.
+
+Class Procs:
+ Initialize()
+ Starts the lighting system, creating all light points and turf overlays.
+
+ StarLight(n)
+ Sets the light produced by space. If a solar eclipse suddenly happens, it'll probably lag.
+
+ MarkIconUpdate(turf/T)
+ Called when a turf needs an update to its light icon. Ensures that it only gets calculated once per turf.
+
+ FlushIconUpdates()
+ Called when a light is done marking icon updates. Updates every marked turf.
+
+ AddBorder(turf/T) & RemoveBorder(turf/T)
+ Called by turf/CheckForOpaqueObjects() to modify the light_border list.
+
+
+*/
+
+var/datum/controller/lighting/lighting_controller
+var/list/initial_lights = list()
+var/all_lightpoints_made = 0
+
+/datum/controller/lighting
+
+ var/starlight = 4
+ var/list/icon_updates = list()
+
+ var/list/light_border = list()
+
+ //var/icon/border = icon('Icons/Test.dmi', "border")
+
+/datum/controller/lighting/New()
+ lighting_controller = src
+
+/datum/controller/lighting/proc/Initialize()
+
+ var/start_time = world.timeofday
+ world << "Processing lights..."
+
+ var/turfs_updated = 0
+
+ for(var/z = 1, z <= world.maxz, z++)
+ for(var/y = 0, y <= world.maxy, y++)
+ for(var/x = 0, x <= world.maxx, x++)
+ if(x > 0 && y > 0)
+ var/turf/T = locate(x,y,z)
+ if(!T.light_overlay)
+ T.light_overlay = new(T)
+ T.CheckForOpaqueObjects()
+ turfs_updated++
+ if(!all_lightpoints_made) new/lightpoint(x+0.5,y+0.5,z)
+
+ all_lightpoints_made = 1
+
+ for(var/atom/movable/M in initial_lights)
+ if(!M.light)
+ M.SetLight(M.luminosity,M.luminosity)
+ else
+ M.light.Reset()
+
+ StarLight(starlight)
+ initial_lights = null
+
+ world << "Lighting initialization took [(world.timeofday-start_time)/world.fps] seconds."
+ world << "Updated [turfs_updated] turfs."
+
+/datum/controller/lighting/proc/StarLight(n)
+ starlight = n
+ for(var/turf/T in light_border)
+ T.SetLight(5,n-1)
+
+ for(var/turf/T)
+ if(T.is_outside)
+ T.ResetValue()
+
+ FlushIconUpdates()
+
+/datum/controller/lighting/proc/MarkIconUpdate(turf/T)
+ if(!T.needs_light_update)
+ icon_updates.Add(T)
+ T.needs_light_update = 1
+
+/datum/controller/lighting/proc/FlushIconUpdates()
+ for(var/turf/T in icon_updates)
+ T.UpdateLight()
+ T.needs_light_update = 0
+ icon_updates = list()
+
+/datum/controller/lighting/proc/AddBorder(turf/T)
+ if(!T.is_border)
+ light_border.Add(T)
+ T.is_border = 1
+ //T.overlays.Add(border)
+
+/datum/controller/lighting/proc/RemoveBorder(turf/T)
+ if(T.is_border)
+ light_border.Remove(T)
+ T.is_border = 0
diff --git a/code/WorkInProgress/Aryn/Lighting/Engine.dm b/code/WorkInProgress/Aryn/Lighting/Engine.dm
new file mode 100644
index 00000000000..9c7dcfa713e
--- /dev/null
+++ b/code/WorkInProgress/Aryn/Lighting/Engine.dm
@@ -0,0 +1,176 @@
+/*
+
+Overview:
+ Procs given to atom and turf by the lighting engine, as well as the lighting overlay object.
+
+Atom Vars:
+ light - Contains the light object this atom is currently shining with.
+
+Turf Vars:
+ light_overlay - Contains an object showing the lighting icon over this turf.
+
+ lit_value - Stores how brightly lit the turf is.
+
+ has_opaque - A cached value updated by CheckForOpaqueObjects()
+
+ is_outside - Any turf with this set to true will be considered as bright as space.
+
+ needs_light_update - Turf is marked for icon updates when true.
+
+ lightNE, lightSE, lightNW, lightSW - Hold the lightpoints on the four corners of this turf. See Lightpoint.dm
+
+ lit_by - A list of lights that are lighting this turf.
+
+Atom Procs:
+ SetLight(intensity, radius)
+ A more versatile SetLuminosity() that allows independent control of intensity and radius.
+ Called behind the scenes of SetLuminosity().
+
+ SetOpacity(opacity)
+ Does the same thing as DAL.
+
+Turf Procs:
+ UpdateLight()
+ Called by the lighting controller. It is advisable not to call this manually due to the cost of lightpoint/max_value()
+
+ AddLight(light/light)
+ Called by light/Reset() to light this turf with a particular light.
+
+ RemoveLight(light/light)
+ Called by light/Off() to unlight turfs that were lit by it.
+
+ ResetValue()
+ Called when lights are reset or starlight is changed.
+
+ ResetCachedValues()
+ Resets cached values of all four light points. Called by ResetValue().
+
+ CheckForOpaqueObjects()
+ Called by lighting_controller.Initialize(), SetOpacity() or when a turf might change opacity.
+ Resets the opacity cache and looks for opaque objects. Also responsible for adding and removing borders to space.
+*/
+
+
+#define LIGHTCLAMP(x) ( max(0,min(3,round(x,1))) )
+
+obj/effect/lighting_overlay
+ //anchored = 1
+ layer = 9
+ mouse_opacity = 0
+ icon = 'icons/effects/ArynLights.dmi'
+ icon_state = "0000"
+
+atom/var/light/light
+
+turf/var/obj/effect/lighting_overlay/light_overlay
+
+turf/var/lit_value = 0
+turf/var/has_opaque = 0
+turf/var/is_outside = 0
+turf/var/is_border = 0
+turf/var/needs_light_update = 0
+
+turf/var/lightpoint/lightNE
+turf/var/lightpoint/lightNW
+turf/var/lightpoint/lightSE
+turf/var/lightpoint/lightSW
+turf/var/list/lit_by
+
+atom/New()
+ . = ..()
+ if(luminosity || light)
+ if(!lighting_controller)
+ initial_lights.Add(src)
+ else
+ if(!light)
+ SetLight(luminosity,luminosity)
+ else
+ light.Reset()
+ if(lighting_controller)
+ if(opacity)
+ opacity = 0
+ SetOpacity(1)
+
+atom/movable/Move()
+ var/o = opacity
+ if(o) SetOpacity(0)
+ . = ..()
+ if(.)
+ if(o) SetOpacity(1)
+ if(light)
+ light.Reset()
+ lighting_controller.FlushIconUpdates()
+
+atom/proc/SetLight(intensity, radius)
+ if(!light) light = new(src)
+ light.radius = min(radius,15)
+ light.intensity = intensity
+ light.Reset()
+ lighting_controller.FlushIconUpdates()
+
+atom/proc/SetOpacity(o)
+ if(o == opacity) return
+ opacity = o
+ var/turf/T = loc
+ if(isturf(T))
+ for(var/light/A in T.lit_by)
+ A.Reset()
+ lighting_controller.FlushIconUpdates()
+
+turf/proc/UpdateLight()
+ if(light_overlay)
+ light_overlay.icon_state = "[lightSE.max_value()][lightSW.max_value()][lightNW.max_value()][lightNE.max_value()]"
+
+turf/proc/AddLight(light/light)
+ if(!lit_by) lit_by = list()
+ lit_by.Add(light)
+ if(!has_opaque)
+ var/brightness = light.CalculateBrightness(src)
+ if(brightness > lit_value)
+ lit_value = LIGHTCLAMP(brightness)
+ ResetCachedValues()
+ for(var/turf/T in range(1,src))
+ lighting_controller.MarkIconUpdate(T)
+
+turf/proc/RemoveLight(light/light)
+ lit_by.Remove(light)
+ ResetValue()
+ if(!lit_by.len) lit_by = null
+
+turf/proc/ResetValue()
+ CheckForOpaqueObjects()
+ if(has_opaque)
+ lit_value = 0
+ else
+ var/max_brightness = (is_outside?(lighting_controller.starlight):0)
+ for(var/light/light in lit_by)
+ var/brightness = light.CalculateBrightness(src)
+ if(brightness > max_brightness)
+ max_brightness = brightness
+ lit_value = LIGHTCLAMP(max_brightness)
+ ResetCachedValues()
+ for(var/turf/T in range(1,src))
+ lighting_controller.MarkIconUpdate(T)
+
+turf/proc/ResetCachedValues()
+ lightNE.cached_value = -1
+ lightNW.cached_value = -1
+ lightSE.cached_value = -1
+ lightSW.cached_value = -1
+
+turf/proc/CheckForOpaqueObjects()
+ has_opaque = opacity
+ if(!opacity)
+ for(var/atom/movable/M in contents)
+ if(M.opacity)
+ has_opaque = 1
+ break
+ if(is_outside)
+ for(var/d = 1, d < 16, d*=2)
+ var/turf/T = get_step(src,d)
+ if(T && !T.is_outside)
+ lighting_controller.AddBorder(src)
+ return
+ if(is_border) lighting_controller.RemoveBorder(src)
+
+#undef LIGHTCLAMP
\ No newline at end of file
diff --git a/code/WorkInProgress/Aryn/Lighting/Light.dm b/code/WorkInProgress/Aryn/Lighting/Light.dm
new file mode 100644
index 00000000000..40cf88120d4
--- /dev/null
+++ b/code/WorkInProgress/Aryn/Lighting/Light.dm
@@ -0,0 +1,70 @@
+/*
+
+Overview:
+ This object functions similarly to /tg/'s /light. It is responsible for calculating what turfs are lit by it.
+
+Class Vars:
+ radius - Set by atom/SetLight(). This stores how far out turfs will be lit up.
+ intensity - Set by atom/SetLight(). Stores the amount of light generated at the center.
+ lit_turfs - A list of turfs being lit by this light.
+ atom - The atom this light is attached to.
+
+Class Procs:
+ Reset()
+ This is called whenever the light changes, or the underlying atom changes position.
+
+ Off()
+ A quick way to turn off a light. Removes the light from all turfs in lit_turfs.
+
+ CalculateBrightness(turf/T)
+ Returns the brightness that should be displayed by this light on a specific turf.
+
+*/
+
+
+light/var/radius = 0
+light/var/intensity = 0
+light/var/list/lit_turfs
+light/var/atom/atom
+
+light/New(atom/atom)
+ src.atom = atom
+
+light/proc/Reset()
+ Off()
+
+ lit_turfs = list()
+
+ if(intensity > 0)
+ for(var/turf/T in view(atom,radius+1))
+ T.AddLight(src)
+ lit_turfs.Add(T)
+
+light/proc/Off()
+ for(var/turf/T in lit_turfs)
+ T.RemoveLight(src)
+
+light/proc/CalculateBrightness(turf/T)
+ var/square = get_square_dist(atom.x,atom.y,atom.z,T.x,T.y,T.z)
+ if(square > (radius+2)*(radius+2)) return 0
+ //+2 offset gives an ambient light effect.
+
+ var/value = ((radius)/(2*fsqrt(square) + 1)) * intensity - 0.48
+ /*
+ lightRadius
+ ---------------- * lightValue - 0.48
+ 2 * distance + 1
+
+ The light decreases by twice the distance, starting from the radius.
+ The + 1 causes the graph to shift to the left one unit so that division by zero is prevented on the source tile.
+
+ This is then multiplied by the light value to give the final result.
+ The -0.48 offset causes the value to be near zero at the radius.
+
+ This gives a result which is likely close to the inverse-square law in two dimensions instead of three.
+ */
+
+
+ return max(min( value , intensity), 0) //Ensure the value never goes above the maximum light value or below zero.
+
+ //return cos(90 * sqrt(square) / max(1,lightRadius)) * lightValue
\ No newline at end of file
diff --git a/code/WorkInProgress/Aryn/Lighting/Lightpoint.dm b/code/WorkInProgress/Aryn/Lighting/Lightpoint.dm
new file mode 100644
index 00000000000..dfca9db4fd2
--- /dev/null
+++ b/code/WorkInProgress/Aryn/Lighting/Lightpoint.dm
@@ -0,0 +1,60 @@
+/*
+
+Overview:
+ Perhaps the most cryptic datum in the lighting engine, there are four of these at the corners of every turf.
+ Any two turfs that share a corner will also have the same lightpoint. Because of the nature of the icons used,
+ light is shown at the corner of the turf rather than in the middle, necessitating some way to keep track of what
+ icon state to use.
+
+Class Vars:
+ x, y, z - The position of the lightpoint. x and y will usually be expressed in terms of 0.5 due to its location on the corner.
+
+ NE, NW, SE, SW - The turfs that are in these directions relative to the lightpoint.
+
+ cached_value - A cached value of max_value().
+
+Class Procs:
+ max_value()
+ The maximum of the light amounts on the four turfs of this light point.
+
+*/
+
+lightpoint
+ var/x
+ var/y
+ var/z
+
+ var/turf/NE
+ var/turf/NW
+ var/turf/SW
+ var/turf/SE
+
+ var/cached_value = -1
+
+ New(x,y,z)
+ var/turf/T = locate(x+0.5,y+0.5,z)
+ if(T)
+ NE = T
+ T.lightSW = src
+ T = locate(x-0.5,y+0.5,z)
+ if(T)
+ NW = T
+ T.lightSE = src
+ T = locate(x-0.5,y-0.5,z)
+ if(T)
+ SW = T
+ T.lightNE = src
+ T = locate(x+0.5,y-0.5,z)
+ if(T)
+ SE = T
+ T.lightNW = src
+
+ proc/max_value()
+ if(cached_value < 0)
+ var
+ valueA = (NW?(NW.lit_value):0)
+ valueB = (NE?(NE.lit_value):0)
+ valueC = (SW?(SW.lit_value):0)
+ valueD = (SE?(SE.lit_value):0)
+ cached_value = max(valueA,valueB,valueC,valueD)
+ return cached_value
\ No newline at end of file
diff --git a/code/WorkInProgress/Aryn/Lighting/Math.dm b/code/WorkInProgress/Aryn/Lighting/Math.dm
new file mode 100644
index 00000000000..cd8716373be
--- /dev/null
+++ b/code/WorkInProgress/Aryn/Lighting/Math.dm
@@ -0,0 +1,22 @@
+/*
+
+Some math procs used by lighting, including ul's fastroot.
+
+*/
+
+var/list/fastroot = list(0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7)
+
+proc/get_square_dist(Ax,Ay,Az,Bx,By,Bz)
+ var/X = (Ax - Bx)
+ var/Y = (Ay - By)
+ var/Z = (Az - Bz)
+ return (X * X + Y * Y + Z * Z)
+
+proc/fsqrt(n)
+ if (n > fastroot.len)
+ //world << "Adding [n-fastroot.len] entries to root table."
+ for(var/i = fastroot.len, i <= n, i++)
+ fastroot += round(sqrt(i))
+ return fastroot[n + 1]
\ No newline at end of file
diff --git a/icons/effects/ArynLights.dmi b/icons/effects/ArynLights.dmi
new file mode 100644
index 00000000000..f3d21402a33
Binary files /dev/null and b/icons/effects/ArynLights.dmi differ