diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm index e3148e1d2d1..5e0105f4e1e 100644 --- a/code/__defines/lighting.dm +++ b/code/__defines/lighting.dm @@ -16,14 +16,14 @@ // If I were you I'd leave this alone. #define LIGHTING_BASE_MATRIX \ - list \ - ( \ - LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ - LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ - LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ - LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ - 0, 0, 0, 1 \ - ) \ + list \ + ( \ + 1, 1, 1, 0, \ + 1, 1, 1, 0, \ + 1, 1, 1, 0, \ + 1, 1, 1, 0, \ + 0, 0, 0, 1 \ + ) \ // Helpers so we can (more easily) control the colour matrices. #define CL_MATRIX_RR 1 @@ -47,6 +47,12 @@ #define CL_MATRIX_CB 19 #define CL_MATRIX_CA 20 +// Higher numbers override lower. +#define LIGHTING_NO_UPDATE 0 +#define LIGHTING_VIS_UPDATE 1 +#define LIGHTING_CHECK_UPDATE 2 +#define LIGHTING_FORCE_UPDATE 3 + // This color of overlay is very common - most of the station is this color when lit fully. // Tube lights are a bluish-white, so we can't just assume 1-1-1 is full-illumination. #define LIGHTING_DEFAULT_TUBE_R 0.96 diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index db8f48b86bf..66aceef22f2 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -55,7 +55,7 @@ var/datum/controller/subsystem/lighting/SSlighting if (!A.dynamic_lighting) continue - new /atom/movable/lighting_overlay(T, TRUE) + new /atom/movable/lighting_overlay(T) overlaycount++ CHECK_TICK @@ -95,17 +95,9 @@ var/datum/controller/subsystem/lighting/SSlighting var/datum/light_source/L = curr_lights[curr_lights.len] curr_lights.len-- - if(QDELETED(L) || L.check() || L.force_update) - L.remove_lum() - if(!QDELETED(L)) - L.apply_lum() + L.update_corners() - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() - - L.vis_update = FALSE - L.force_update = FALSE - L.needs_update = FALSE + L.needs_update = LIGHTING_NO_UPDATE processed_lights++ diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index 7a3e45e89d8..917769f7b74 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -7,8 +7,8 @@ /var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) /datum/lighting_corner - var/list/turf/masters = list() - var/list/datum/light_source/affecting = list() // Light sources affecting us. + var/list/turf/masters + var/list/datum/light_source/affecting // Light sources affecting us. var/active = FALSE // TRUE if one of our masters has dynamic lighting. var/x = 0 @@ -28,13 +28,13 @@ var/cache_u = 0 var/cache_mx = 0 - var/update_gen = 0 - /datum/lighting_corner/New(var/turf/new_turf, var/diagonal) . = ..() SSlighting.lighting_corners += src + masters = list() + masters[new_turf] = turn(diagonal, 180) z = new_turf.z diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 612c87232f8..b96e61615d8 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -16,7 +16,7 @@ transform = matrix(WORLD_ICON_SIZE / 32, 0, (WORLD_ICON_SIZE - 32) / 2, 0, WORLD_ICON_SIZE / 32, (WORLD_ICON_SIZE - 32) / 2) #endif -/atom/movable/lighting_overlay/New(atom/loc, no_update = FALSE) +/atom/movable/lighting_overlay/New(atom/loc) . = ..() verbs.Cut() SSlighting.lighting_overlays += src @@ -24,11 +24,9 @@ var/turf/T = loc // If this runtimes atleast we'll know what's creating overlays in things that aren't turfs. T.lighting_overlay = src T.luminosity = 0 - - if (no_update) - return - - update_overlay() + + needs_update = TRUE + SSlighting.overlay_queue += src /atom/movable/lighting_overlay/Destroy(force = FALSE) if (!force) @@ -60,20 +58,17 @@ qdel(src, TRUE) return - // To the future coder who sees this and thinks - // "Why didn't he just use a loop?" - // Well my man, it's because the loop performed like shit. - // And there's no way to improve it because - // without a loop you can make the list all at once which is the fastest you're gonna get. - // Oh it's also shorter line wise. - // Including with these comments. - // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. - // No I seriously cannot think of a more efficient method, fuck off Comic. - var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner - var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner - var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner - var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner + var/list/corners = T.corners + var/datum/lighting_corner/cr = dummy_lighting_corner + var/datum/lighting_corner/cg = dummy_lighting_corner + var/datum/lighting_corner/cb = dummy_lighting_corner + var/datum/lighting_corner/ca = dummy_lighting_corner + if (corners) + cr = corners[3] || dummy_lighting_corner + cg = corners[2] || dummy_lighting_corner + cb = corners[4] || dummy_lighting_corner + ca = corners[1] || dummy_lighting_corner var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) luminosity = max > LIGHTING_SOFT_THRESHOLD diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 9cc9df58c85..d36f70ef995 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -25,41 +25,34 @@ var/tmp/applied_lum_u // Variables used to keep track of the atom's angle. - var/tmp/limit_a_x // The first test point's X coord for the cone. - var/tmp/limit_a_y // The first test point's Y coord for the cone. - var/tmp/limit_a_t // The first test point's angle. - var/tmp/limit_b_x // The second test point's X coord for the cone. - var/tmp/limit_b_y // The second test point's Y coord for the cone. - var/tmp/limit_b_t // The second test point's angle. - var/tmp/cached_origin_x // The last known X coord of the origin. - var/tmp/cached_origin_y // The last known Y coord of the origin. - var/tmp/old_direction // The last known direction of the origin. - var/tmp/targ_sign - var/tmp/test_x_offset - var/tmp/test_y_offset + var/tmp/limit_a_x // The first test point's X coord for the cone. + var/tmp/limit_a_y // The first test point's Y coord for the cone. + var/tmp/limit_a_t // The first test point's angle. + var/tmp/limit_b_x // The second test point's X coord for the cone. + var/tmp/limit_b_y // The second test point's Y coord for the cone. + var/tmp/limit_b_t // The second test point's angle. + var/tmp/cached_origin_x // The last known X coord of the origin. + var/tmp/cached_origin_y // The last known Y coord of the origin. + var/tmp/old_direction // The last known direction of the origin. + var/tmp/targ_sign // The sign to test the point against. + var/tmp/test_x_offset // How much the X coord should be offset due to direction. + var/tmp/test_y_offset // How much the Y coord should be offset due to direction. var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. var/list/turf/affecting_turfs var/applied = FALSE // Whether we have applied our light yet or not. - var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became (in)visible to us. - var/needs_update // Whether we are queued for an update. - var/destroyed // Whether we are destroyed and need to stop emitting light. - var/force_update + var/needs_update = LIGHTING_NO_UPDATE /datum/light_source/New(var/atom/owner, var/atom/top) source_atom = owner // Set our new owner. - if (!source_atom.light_sources) - source_atom.light_sources = list() - source_atom.light_sources += src // Add us to the lights of our owner. + LAZYADD(source_atom.light_sources, src) + top_atom = top if (top_atom != source_atom) - if (!top.light_sources) - top.light_sources = list() - - top_atom.light_sources += src + LAZYADD(top_atom.light_sources, src) source_turf = top_atom light_power = source_atom.light_power @@ -70,9 +63,6 @@ parse_light_color() - effect_str = list() - affecting_turfs = list() - update() L_PROF(source_atom, "source_new") @@ -83,47 +73,31 @@ /datum/light_source/Destroy(force) L_PROF(source_atom, "source_destroy") - force_update() - if (source_atom && source_atom.light_sources) - source_atom.light_sources -= src + remove_lum() + if (source_atom) + LAZYREMOVE(source_atom.light_sources, src) - if (top_atom && top_atom.light_sources) - top_atom.light_sources -= src + if (top_atom) + LAZYREMOVE(top_atom.light_sources, src) . = ..() if (!force) return QDEL_HINT_IWILLGC -// Process the light RIGHT NOW. -#define DO_UPDATE \ - if (QDELETED(src) || check() || force_update) { \ - remove_lum(TRUE); \ - if (!QDELETED(src)) { \ - apply_lum(TRUE); \ - } \ - } \ - else if (vis_update) { \ - smart_vis_update(TRUE); \ - } \ - vis_update = FALSE; \ - force_update = FALSE; \ - needs_update = FALSE; - -// Queue an update. -#define QUEUE_UPDATE \ - if (!needs_update) \ - { \ - SSlighting.light_queue += src; \ - needs_update = TRUE; \ - } - // Picks either scheduled or instant updates based on current server load. -#define INTELLIGENT_UPDATE \ - if (world.tick_usage > SSlighting.instant_tick_limit || SSlighting.force_queued) { \ - QUEUE_UPDATE; \ - } \ - else { \ - DO_UPDATE; \ +#define INTELLIGENT_UPDATE(level) \ + var/_should_update = needs_update == LIGHTING_NO_UPDATE; \ + if (needs_update < level) { \ + needs_update = level; \ + } \ + if (_should_update) { \ + if (world.tick_usage > SSlighting.instant_tick_limit || SSlighting.force_queued) { \ + SSlighting.light_queue += src; \ + } \ + else { \ + update_corners(TRUE); \ + needs_update = LIGHTING_NO_UPDATE; \ + } \ } // This proc will cause the light source to update the top atom, and add itself to the update queue. @@ -131,7 +105,7 @@ // This top atom is different. if (new_top_atom && new_top_atom != top_atom) if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom. - top_atom.light_sources -= src + LAZYREMOVE(top_atom.light_sources, src) top_atom = new_top_atom @@ -143,62 +117,19 @@ L_PROF(source_atom, "source_update") - INTELLIGENT_UPDATE + INTELLIGENT_UPDATE(LIGHTING_CHECK_UPDATE) // Will force an update without checking if it's actually needed. /datum/light_source/proc/force_update() L_PROF(source_atom, "source_forceupdate") - force_update = 1 - INTELLIGENT_UPDATE + INTELLIGENT_UPDATE(LIGHTING_FORCE_UPDATE) // Will cause the light source to recalculate turfs that were removed or added to visibility only. /datum/light_source/proc/vis_update() L_PROF(source_atom, "source_visupdate") - vis_update = 1 - INTELLIGENT_UPDATE - -// Will check if we actually need to update, and update any variables that may need to be updated. -/datum/light_source/proc/check() - if (!source_atom || !light_range || !light_power) - qdel(src) - return 1 - - if (!top_atom) - top_atom = source_atom - . = 1 - - if (istype(top_atom, /turf)) - if (source_turf != top_atom) - source_turf = top_atom - . = 1 - else if (top_atom.loc != source_turf) - source_turf = top_atom.loc - . = 1 - - if (source_atom.light_power != light_power) - light_power = source_atom.light_power - . = 1 - - if (source_atom.light_range != light_range) - light_range = source_atom.light_range - . = 1 - - if (light_range && light_power && !applied) - . = 1 - - if (source_atom.light_color != light_color) - light_color = source_atom.light_color - parse_light_color() - . = 1 - - if (top_atom.dir != old_direction && light_angle) - . = 1 - - if (source_atom.light_wedge != light_angle) - light_angle = source_atom.light_wedge - . = 1 + INTELLIGENT_UPDATE(LIGHTING_VIS_UPDATE) // Decompile the hexadecimal colour into lumcounts of each perspective. /datum/light_source/proc/parse_light_color() @@ -221,20 +152,21 @@ // If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. // As such this all gets counted as a single line. // The braces and semicolons are there to be able to do this on a single line. -#define APPLY_CORNER_XY(C,now,Tx,Ty) \ - . = LUM_FALLOFF_XY(C.x, C.y, Tx, Ty); \ - \ - . *= light_power; \ - \ - effect_str[C] = .; \ - \ - C.update_lumcount \ - ( \ - . * applied_lum_r, \ - . * applied_lum_g, \ - . * applied_lum_b, \ - . * applied_lum_u, \ - now \ +#define APPLY_CORNER_XY(C,now,Tx,Ty) \ + . = LUM_FALLOFF_XY(C.x, C.y, Tx, Ty); \ + \ + . *= light_power; \ + var/OLD = effect_str[C]; \ + \ + effect_str[C] = .; \ + \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b), \ + (. * lum_u) - (OLD * applied_lum_u), \ + now \ ); #define APPLY_CORNER(C,now) APPLY_CORNER_XY(C,now,source_turf.x,source_turf.y) @@ -255,6 +187,7 @@ #define POLAR_TO_CART_Y(R,T) ((R) * sin(T)) #define PSEUDO_WEDGE(A_X,A_Y,B_X,B_Y) ((A_X)*(B_Y) - (A_Y)*(B_X)) #define MINMAX(NUM) ((NUM) < 0 ? -round(-(NUM)) : round(NUM)) +#define ARBITRARY_NUMBER 10 /datum/light_source/proc/update_angle() var/turf/T = get_turf(top_atom) @@ -304,17 +237,19 @@ test_x_offset -= 1 // Convert our angle + range into a vector. - limit_a_x = POLAR_TO_CART_X(light_range + 10, limit_a_t) + limit_a_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_a_t) limit_a_x = MINMAX(limit_a_x) - limit_a_y = POLAR_TO_CART_Y(light_range + 10, limit_a_t) // 10 is an arbitrary number, yes. + limit_a_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_a_t) limit_a_y = MINMAX(limit_a_y) - limit_b_x = POLAR_TO_CART_X(light_range + 10, limit_b_t) + limit_b_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_b_t) limit_b_x = MINMAX(limit_b_x) - limit_b_y = POLAR_TO_CART_Y(light_range + 10, limit_b_t) + limit_b_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_b_t) limit_b_y = MINMAX(limit_b_y) // This won't change unless the origin or dir changes, might as well do it here. targ_sign = PSEUDO_WEDGE(limit_a_x, limit_a_y, limit_b_x, limit_b_y) > 0 +#undef ARBITRARY_NUMBER + // I know this is 2D, calling it a cone anyways. Fuck the system. // Returns true if the test point is NOT inside the cone. // Make sure update_angle() is called first if the light's loc or dir have changed. @@ -336,121 +271,174 @@ #define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) #define LUM_FALLOFF_XY(Cx,Cy,Tx,Ty) (1 - CLAMP01(sqrt(((Cx) - (Tx)) ** 2 + ((Cy) - (Ty)) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) -/datum/light_source/proc/apply_lum(var/now = FALSE) - var/static/update_gen = 1 - applied = 1 +/datum/light_source/proc/remove_lum(var/now = FALSE) + applied = FALSE - if (!source_turf) + var/thing + for (thing in affecting_turfs) + var/turf/T = thing + LAZYREMOVE(T.affecting_lights, src) + + affecting_turfs = null + + for (thing in effect_str) + var/datum/lighting_corner/C = thing + REMOVE_CORNER(C,now) + + LAZYREMOVE(C.affecting, src) + + effect_str = null + +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C, var/now = FALSE) + LAZYINITLIST(effect_str) + if (effect_str[C]) // Already have one. + REMOVE_CORNER(C,now) + effect_str[C] = 0 + + APPLY_CORNER(C,now) + UNSETEMPTY(effect_str) + +/datum/light_source/proc/update_corners(now = FALSE) + var/update = FALSE + + if (QDELETED(source_atom)) + qdel(src) return - var/Tx - var/Ty + if (source_atom.light_power != light_power) + light_power = source_atom.light_power + update = TRUE + + if (source_atom.light_range != light_range) + light_range = source_atom.light_range + update = TRUE + + if (!top_atom) + top_atom = source_atom + update = TRUE + + if (top_atom.loc != source_turf) + source_turf = top_atom.loc + update = TRUE + + if (!light_range || !light_power) + qdel(src) + return + + if (isturf(top_atom)) + if (source_turf != top_atom) + source_turf = top_atom + update = TRUE + else if (top_atom.loc != source_turf) + source_turf = top_atom.loc + update = TRUE + + if (!source_turf) + return // Somehow we've got a light in nullspace, no-op. + + if (light_range && light_power && !applied) + update = TRUE + + if (source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + update = TRUE + + else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b) + update = TRUE + + if (source_atom.light_wedge != light_angle) + light_angle = source_atom.light_wedge + update = TRUE + + if (light_angle && top_atom.dir != old_direction) + update = TRUE + + if (update && light_angle) + update_angle() + + if (update) + needs_update = LIGHTING_CHECK_UPDATE + else if (needs_update == LIGHTING_CHECK_UPDATE) + return // No change. + + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + var/thing + var/datum/lighting_corner/C + var/turf/T var/Sx = source_turf.x var/Sy = source_turf.y - // Keep track of the last applied lum values so that the lighting can be reversed - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - applied_lum_u = lum_u - - if (light_angle) - update_angle() - - FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) - Tx = T.x - Ty = T.y - if (light_angle && check_light_cone(Tx, Ty)) + FOR_DVIEW(T, Ceiling(light_range), source_turf, 0) + if (light_angle && check_light_cone(T.x, T.y)) continue - if (!T.lighting_corners_initialised) - T.generate_missing_corners() + for (thing in T.get_corners()) + C = thing + corners[C] = 0 - for (var/datum/lighting_corner/C in T.get_corners()) - if (C.update_gen == update_gen) + turfs += T + END_FOR_DVIEW + + LAZYINITLIST(affecting_turfs) + + var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. + affecting_turfs += L + for (thing in L) + T = thing + LAZYADD(T.affecting_lights, src) + + L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. + affecting_turfs -= L + for (thing in L) + T = thing + LAZYREMOVE(T.affecting_lights, src) + + LAZYINITLIST(effect_str) + if (needs_update == LIGHTING_VIS_UPDATE) + for (thing in corners - effect_str) + C = thing + LAZYADD(C.affecting, src) + if (!C.active) + effect_str[C] = 0 continue - C.update_gen = update_gen - C.affecting += src - + APPLY_CORNER_XY(C, now, Sx, Sy) + else + L = corners - effect_str + for (thing in L) + C = thing + LAZYADD(C.affecting, src) if (!C.active) effect_str[C] = 0 continue APPLY_CORNER_XY(C, now, Sx, Sy) - if (!T.affecting_lights) - T.affecting_lights = list() + for (thing in corners - L) + C = thing + if (!C.active) + effect_str[C] = 0 + continue - T.affecting_lights += src - affecting_turfs += T + APPLY_CORNER_XY(C, now, Sx, Sy) - update_gen++ + L = effect_str - corners + for (thing in L) + C = thing + REMOVE_CORNER(C, now) + LAZYREMOVE(C.affecting, src) -/datum/light_source/proc/remove_lum(var/now = FALSE) - applied = FALSE + effect_str -= L - for (var/turf/T in affecting_turfs) - if (!T.affecting_lights) - T.affecting_lights = list() - else - T.affecting_lights -= src + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + applied_lum_u = lum_u - affecting_turfs.Cut() - - for (var/datum/lighting_corner/C in effect_str) - REMOVE_CORNER(C,now) - - C.affecting -= src - - effect_str.Cut() - -/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C, var/now = FALSE) - if (effect_str.Find(C)) // Already have one. - REMOVE_CORNER(C,now) - - APPLY_CORNER(C,now) - -/datum/light_source/proc/smart_vis_update(var/now = FALSE) - L_PROF(source_atom, "source_smartvisupdate") - var/list/datum/lighting_corner/corners = list() - var/list/turf/turfs = list() - FOR_DVIEW(var/turf/T, light_range, source_turf, 0) - if (!T.lighting_corners_initialised) - T.generate_missing_corners() - if (light_angle && check_light_cone(T.x, T.y)) - continue - - corners |= T.get_corners() - turfs += T - - var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. - affecting_turfs += L - for (var/turf/T in L) - if (!T.affecting_lights) - T.affecting_lights = list(src) - else - T.affecting_lights += src - - L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. - affecting_turfs -= L - for (var/turf/T in L) - if (QDELETED(T)) - continue - T.affecting_lights -= src - - for (var/datum/lighting_corner/C in corners - effect_str) // New corners - C.affecting += src - if (!C.active || check_light_cone(C.x, C.y)) - effect_str[C] = 0 - continue - - APPLY_CORNER(C,now) - - for (var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners. - REMOVE_CORNER(C,now) - C.affecting -= src - effect_str -= C + UNSETEMPTY(effect_str) + UNSETEMPTY(affecting_turfs) #undef QUEUE_UPDATE #undef DO_UPDATE diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 8c22ec0187b..1c72595c7a4 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -145,12 +145,21 @@ lighting_clear_overlay() /turf/proc/get_corners() + if (!dynamic_lighting && !light_sources) + return null + + if (!lighting_corners_initialised) + generate_missing_corners() + if (has_opaque_atom) return null // Since this proc gets used in a for loop, null won't be looped though. return corners /turf/proc/generate_missing_corners() + if (!dynamic_lighting && !light_sources) + return + lighting_corners_initialised = TRUE if (!corners) corners = list(null, null, null, null)