Ports some old TG lighting + opacity refactors (#29724)

* lighting ports

* missed these

* fix

* tweak optical scanners

* Update code/datums/elements/light_blocking.dm

Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
Signed-off-by: kyunkyunkyun <120701975+kyunkyunkyun@users.noreply.github.com>

---------

Signed-off-by: Burzah <116982774+Burzah@users.noreply.github.com>
Signed-off-by: kyunkyunkyun <120701975+kyunkyunkyun@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: Contrabang <91113370+Contrabang@users.noreply.github.com>
This commit is contained in:
kyunkyunkyun
2025-09-08 19:25:37 +00:00
committed by GitHub
co-authored by Contrabang Burzah
parent d175f3d1e4
commit 6862135913
41 changed files with 456 additions and 506 deletions
+22 -11
View File
@@ -48,25 +48,36 @@
/atom/proc/extinguish_light(force = FALSE)
return
// Should always be used to change the opacity of an atom.
// It notifies (potentially) affected light sources so they can update (if needed).
/**
* Updates the atom's opacity value.
*
* This exists to act as a hook for associated behavior.
* It notifies (potentially) affected light sources so they can update (if needed).
*/
/atom/proc/set_opacity(new_opacity)
if(new_opacity == opacity)
return
SEND_SIGNAL(src, COMSIG_ATOM_SET_OPACITY, new_opacity)
. = opacity
opacity = new_opacity
var/turf/T = loc
if(!isturf(T))
/atom/movable/set_opacity(new_opacity)
. = ..()
if(isnull(.) || !isturf(loc))
return
if(new_opacity)
T.has_opaque_atom = TRUE
T.reconsider_lights()
if(opacity)
AddElement(/datum/element/light_blocking)
else
var/old_has_opaque_atom = T.has_opaque_atom
T.recalc_atom_opacity()
if(old_has_opaque_atom != T.has_opaque_atom)
T.reconsider_lights()
RemoveElement(/datum/element/light_blocking)
/turf/set_opacity(new_opacity)
. = ..()
if(isnull(.))
return
recalculate_directional_opacity()
/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = LIGHT_COLOR_WHITE, _duration = FLASH_LIGHT_DURATION, _reset_lighting = TRUE)
return
+99 -63
View File
@@ -2,34 +2,37 @@
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list.
GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST))
/datum/lighting_corner
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.
/// Light sources affecting us.
var/list/datum/light_source/affecting
var/x = 0
var/y = 0
var/z = 0
var/x = 0
var/y = 0
var/turf/master_NE
var/turf/master_SE
var/turf/master_SW
var/turf/master_NW
// "raw" color values, changed by update_lumcount()
var/lum_r = 0
var/lum_g = 0
var/lum_b = 0
var/needs_update = FALSE
// true color values, guaranteed to be between 0 and 1
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_mx = 0
/// the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this
var/largest_color_luminosity = 0
/// whether we are to be added to SSlighting's corners_queue list for an update
var/needs_update = FALSE
/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
masters = list()
masters[new_turf] = turn(diagonal, 180)
z = new_turf.z
save_master(new_turf, turn(diagonal, 180))
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one.
@@ -40,50 +43,49 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
var/turf/T
var/i
var/turf/new_master_turf
// Diagonal one is easy.
T = get_step(new_turf, diagonal)
if(T) // In case we're on the map's border.
if(!T.corners)
T.corners = list(null, null, null, null)
masters[T] = diagonal
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
T.corners[i] = src
new_master_turf = get_step(new_turf, diagonal)
if(new_master_turf) // In case we're on the map's border.
save_master(new_master_turf, diagonal)
// Now the horizontal one.
T = get_step(new_turf, horizontal)
if(T) // Ditto.
if(!T.corners)
T.corners = list(null, null, null, null)
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
new_master_turf = get_step(new_turf, horizontal)
if(new_master_turf) // Ditto.
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
// And finally the vertical one.
T = get_step(new_turf, vertical)
if(T)
if(!T.corners)
T.corners = list(null, null, null, null)
new_master_turf = get_step(new_turf, vertical)
if(new_master_turf)
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
T.corners[i] = src
/datum/lighting_corner/proc/save_master(turf/master, dir)
switch(dir)
if(NORTHEAST)
master_NE = master
master.lighting_corner_SW = src
if(SOUTHEAST)
master_SE = master
master.lighting_corner_NW = src
if(SOUTHWEST)
master_SW = master
master.lighting_corner_NE = src
if(NORTHWEST)
master_NW = master
master.lighting_corner_SE = src
update_active()
/datum/lighting_corner/proc/self_destruct_if_idle()
if(!LAZYLEN(affecting))
qdel(src, force = TRUE)
/datum/lighting_corner/proc/update_active()
active = FALSE
var/turf/T
var/thing
for(thing in masters)
T = thing
if(T.lighting_object)
active = TRUE
return
/datum/lighting_corner/proc/vis_update()
for(var/datum/light_source/light_source as anything in affecting)
light_source.vis_update()
/datum/lighting_corner/proc/full_update()
for(var/datum/light_source/light_source as anything in affecting)
light_source.recalc_corner(src)
// God that was a mess, now to do the rest of the corner code! Hooray!
/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b)
@@ -104,13 +106,13 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
var/lum_r = src.lum_r
var/lum_g = src.lum_g
var/lum_b = src.lum_b
var/mx = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
. = 1 // factor
if(mx > 1)
. = 1 / mx
if(largest_color_luminosity > 1)
. = 1 / largest_color_luminosity
#if LIGHTING_SOFT_THRESHOLD != 0
else if(mx < LIGHTING_SOFT_THRESHOLD)
else if(largest_color_luminosity < LIGHTING_SOFT_THRESHOLD)
. = 0 // 0 means soft lighting.
cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
@@ -121,13 +123,30 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE)
cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE)
#endif
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
for(var/TT in masters)
var/turf/T = TT
if(T.lighting_object && !T.lighting_object.needs_update)
T.lighting_object.needs_update = TRUE
SSlighting.objects_queue += T.lighting_object
src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE)
var/datum/lighting_object/lighting_object = master_NE?.lighting_object
if(lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SE?.lighting_object
if(lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SW?.lighting_object
if(lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_NW?.lighting_object
if(lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
self_destruct_if_idle()
/datum/lighting_corner/dummy/New()
@@ -138,6 +157,23 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
if(!force)
return QDEL_HINT_LETMELIVE
stack_trace("Attempted qdel of a lighting corner.")
for(var/datum/light_source/light_source as anything in affecting)
LAZYREMOVE(light_source.effect_str, src)
affecting = null
if(master_NE)
master_NE.lighting_corner_SW = null
master_NE.lighting_corners_initialised = FALSE
if(master_SE)
master_SE.lighting_corner_NW = null
master_SE.lighting_corners_initialised = FALSE
if(master_SW)
master_SW.lighting_corner_NE = null
master_SW.lighting_corners_initialised = FALSE
if(master_NW)
master_NW.lighting_corner_SE = null
master_NW.lighting_corners_initialised = FALSE
if(needs_update)
SSlighting.corners_queue -= src
return ..()
+62 -106
View File
@@ -1,66 +1,45 @@
/atom/movable/lighting_object
name = ""
anchored = TRUE
icon = LIGHTING_ICON
icon_state = "transparent"
color = null //we manually set color in init instead
plane = LIGHTING_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
layer = LIGHTING_LAYER
invisibility = INVISIBILITY_LIGHTING
simulated = FALSE
/datum/lighting_object
/// the underlay we are currently applying to our turf to apply light
var/mutable_appearance/current_underlay
/// whether we are already in the SSlighting.objects_queue list
var/needs_update = FALSE
var/turf/myturf
/// the turf that our light is applied to
var/turf/affected_turf
/atom/movable/lighting_object/Initialize(mapload)
/datum/lighting_object/New(turf/source)
if(!isturf(source))
qdel(src, force = TRUE)
stack_trace("a lighting object was assigned to [source], a non turf!")
return
. = ..()
verbs.Cut()
//We avoid setting this in the base as if we do then the parent atom handling will add_atom_color it and that
//is totally unsuitable for this object, as we are always changing it's colour manually
color = LIGHTING_BASE_MATRIX
current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", -LIGHTING_LAYER, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
myturf = loc
if(myturf.lighting_object)
qdel(myturf.lighting_object, force = TRUE)
myturf.lighting_object = src
myturf.luminosity = 0
affected_turf = source
if(affected_turf.lighting_object)
qdel(affected_turf.lighting_object, force = TRUE)
stack_trace("a lighting object was assigned to a turf that already had a lighting object!")
for(var/turf/space/S in RANGE_TURFS(1, src)) //RANGE_TURFS is in code\__HELPERS\game.dm
S.update_starlight()
affected_turf.lighting_object = src
affected_turf.luminosity = 0
for(var/turf/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.update_starlight()
needs_update = TRUE
SSlighting.objects_queue += src
/atom/movable/lighting_object/Destroy(force)
if(force)
SSlighting.objects_queue -= src
if(loc != myturf)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
stack_trace("A lighting object was qdeleted with a different loc then it is suppose to have ([COORD(oldturf)] -> [COORD(newturf)])")
if(isturf(myturf))
myturf.lighting_object = null
myturf.luminosity = 1
myturf = null
return ..()
else
/datum/lighting_object/Destroy(force)
if(!force)
return QDEL_HINT_LETMELIVE
SSlighting.objects_queue -= src
if(isturf(affected_turf))
affected_turf.lighting_object = null
affected_turf.luminosity = 1
affected_turf.underlays -= current_underlay
affected_turf = null
return ..()
/atom/movable/lighting_object/proc/update()
if(loc != myturf)
if(loc)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
warning("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
qdel(src, TRUE)
return
/datum/lighting_object/proc/update()
// 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.
@@ -69,37 +48,30 @@
// 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.
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
var/list/corners = myturf.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) //done this way for speed
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/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner
var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner
var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner
var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity)
var/rr = cr.cache_r
var/rg = cr.cache_g
var/rb = cr.cache_b
var/rr = red_corner.cache_r
var/rg = red_corner.cache_g
var/rb = red_corner.cache_b
var/gr = cg.cache_r
var/gg = cg.cache_g
var/gb = cg.cache_b
var/gr = green_corner.cache_r
var/gg = green_corner.cache_g
var/gb = green_corner.cache_b
var/br = cb.cache_r
var/bg = cb.cache_g
var/bb = cb.cache_b
var/br = blue_corner.cache_r
var/bg = blue_corner.cache_g
var/bb = blue_corner.cache_b
var/ar = ca.cache_r
var/ag = ca.cache_g
var/ab = ca.cache_b
var/ar = alpha_corner.cache_r
var/ag = alpha_corner.cache_g
var/ab = alpha_corner.cache_b
#if LIGHTING_SOFT_THRESHOLD != 0
var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
@@ -110,42 +82,26 @@
#endif
if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8))
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
icon_state = "transparent"
color = null
// anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "lighting_transparent"
current_underlay.color = null
affected_turf.underlays += current_underlay
else if(!set_luminosity)
icon_state = "dark"
color = null
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "lighting_dark"
current_underlay.color = null
affected_turf.underlays += current_underlay
else
icon_state = null
color = list(
affected_turf.underlays -= current_underlay
current_underlay.icon_state = null
current_underlay.color = list(
rr, rg, rb, 00,
gr, gg, gb, 00,
br, bg, bb, 00,
ar, ag, ab, 00,
00, 00, 00, 01
)
affected_turf.underlays += current_underlay
luminosity = set_luminosity
// Variety of overrides so the overlays don't get affected by weird things.
/atom/movable/lighting_object/ex_act(severity)
return 0
/atom/movable/lighting_object/singularity_act()
return
/atom/movable/lighting_object/singularity_pull()
return
/atom/movable/lighting_object/blob_act(obj/structure/blob/B)
return
/atom/movable/lighting_object/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE)
return ..()
// Override here to prevent things accidentally moving around overlays.
/atom/movable/lighting_object/forceMove(atom/destination, no_tp = FALSE, harderforce = FALSE)
if(harderforce)
. = ..()
affected_turf.luminosity = set_luminosity
+1 -1
View File
@@ -7,6 +7,6 @@
if(!IS_DYNAMIC_LIGHTING(T))
continue
new/atom/movable/lighting_object(T)
new /datum/lighting_object(T)
CHECK_TICK
CHECK_TICK
+82 -105
View File
@@ -2,14 +2,21 @@
// These are the main datums that emit light.
/datum/light_source
var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/source_atom // The atom that we belong to.
/// The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/top_atom
/// The atom that we belong to.
var/atom/source_atom
var/turf/source_turf // The turf under the above.
var/turf/pixel_turf // The turf the top_atom appears to over.
var/light_power // Intensity of the emitter light.
var/light_range // The range of the emitted light.
var/light_color // The colour of the light, string, decomposed by parse_light_color()
/// The turf under the above.
var/turf/source_turf
/// The turf the top_atom appears to over.
var/turf/pixel_turf
/// Intensity of the emitter light.
var/light_power
/// The range of the emitted light.
var/light_range
/// The colour of the light, string, decomposed by parse_light_color()
var/light_color
// Variables for keeping track of the colour.
var/lum_r
@@ -21,12 +28,14 @@
var/tmp/applied_lum_g
var/tmp/applied_lum_b
var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
var/list/turf/affecting_turfs
/// List used to store how much we're affecting corners.
var/list/datum/lighting_corner/effect_str
var/applied = FALSE // Whether we have applied our light yet or not.
/// Whether we have applied our light yet or not.
var/applied = FALSE
var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update.
/// Whether we are queued for an update.
var/needs_update = LIGHTING_NO_UPDATE
/datum/light_source/New(atom/owner, atom/top)
@@ -110,55 +119,44 @@
// The braces and semicolons are there to be able to do this on a single line.
#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 APPLY_CORNER(C) \
. = LUM_FALLOFF(C, pixel_turf); \
. *= 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) \
#define APPLY_CORNER(C) \
. = LUM_FALLOFF(C, pixel_turf); \
. *= light_power; \
var/OLD = effect_str[C]; \
\
C.update_lumcount \
( \
(. * lum_r) - (OLD * applied_lum_r), \
(. * lum_g) - (OLD * applied_lum_g), \
(. * lum_b) - (OLD * applied_lum_b) \
); \
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
);
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
);
// This is the define used to calculate falloff.
/// This is the define used to calculate falloff.
/datum/light_source/proc/remove_lum()
applied = FALSE
var/thing
for(thing in affecting_turfs)
var/turf/T = thing
LAZYREMOVE(T.affecting_lights, src)
affecting_turfs = null
var/datum/lighting_corner/C
for(thing in effect_str)
C = thing
REMOVE_CORNER(C)
LAZYREMOVE(C.affecting, src)
for(var/datum/lighting_corner/corner as anything in effect_str)
REMOVE_CORNER(corner)
LAZYREMOVE(corner.affecting, src)
effect_str = null
/datum/light_source/proc/recalc_corner(datum/lighting_corner/C)
/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner)
LAZYINITLIST(effect_str)
if(effect_str[C]) // Already have one.
REMOVE_CORNER(C)
effect_str[C] = 0
if(effect_str[corner]) // Already have one.
REMOVE_CORNER(corner)
effect_str[corner] = 0
APPLY_CORNER(C)
UNSETEMPTY(effect_str)
APPLY_CORNER(corner)
effect_str[corner] = .
/datum/light_source/proc/update_corners()
var/update = FALSE
@@ -194,9 +192,9 @@
pixel_turf = get_turf_pixel(top_atom)
update = TRUE
else
var/P = get_turf_pixel(top_atom)
if(P != pixel_turf)
pixel_turf = P
var/pixel_loc = get_turf_pixel(top_atom)
if(pixel_loc != pixel_turf)
pixel_turf = pixel_loc
update = TRUE
if(!isturf(source_turf))
@@ -224,77 +222,56 @@
return //nothing's changed
var/list/datum/lighting_corner/corners = list()
var/list/turf/turfs = list()
var/thing
var/datum/lighting_corner/C
var/turf/T
var/list/turf/turfs = list()
if(source_turf)
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(T in view(CEILING(light_range, 1), source_turf))
if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources))
continue
if(!T.has_opaque_atom)
for(var/turf/T in view(CEILING(light_range, 1), source_turf))
if(!IS_OPAQUE_TURF(T))
if(!T.lighting_corners_initialised)
T.generate_missing_corners()
for(thing in T.corners)
C = thing
corners[C] = 0
corners[T.lighting_corner_NE] = 0
corners[T.lighting_corner_SE] = 0
corners[T.lighting_corner_SW] = 0
corners[T.lighting_corner_NW] = 0
turfs += T
source_turf.luminosity = oldlum
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)
var/list/datum/lighting_corner/new_corners = (corners - effect_str)
LAZYINITLIST(effect_str)
if(needs_update == LIGHTING_VIS_UPDATE)
for(thing in corners - effect_str) // New corners
C = thing
LAZYADD(C.affecting, src)
if(!C.active)
effect_str[C] = 0
continue
APPLY_CORNER(C)
for(var/datum/lighting_corner/corner as anything in new_corners)
APPLY_CORNER(corner)
if(. != 0)
LAZYADD(corner.affecting, src)
effect_str[corner] = .
else
L = corners - effect_str
for(thing in L) // New corners
C = thing
LAZYADD(C.affecting, src)
if(!C.active)
effect_str[C] = 0
continue
APPLY_CORNER(C)
for(var/datum/lighting_corner/corner as anything in new_corners)
APPLY_CORNER(corner)
if(. != 0)
LAZYADD(corner.affecting, src)
effect_str[corner] = .
for(thing in corners - L) // Existing corners
C = thing
if(!C.active)
effect_str[C] = 0
continue
APPLY_CORNER(C)
for(var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners
APPLY_CORNER(corner)
if(. != 0)
effect_str[corner] = .
else
LAZYREMOVE(corner.affecting, src)
effect_str -= corner
L = effect_str - corners
for(thing in L) // Old, now gone, corners.
C = thing
REMOVE_CORNER(C)
LAZYREMOVE(C.affecting, src)
effect_str -= L
var/list/datum/lighting_corner/gone_corners = effect_str - corners
for(var/datum/lighting_corner/corner as anything in gone_corners)
REMOVE_CORNER(corner)
LAZYREMOVE(corner.affecting, src)
effect_str -= gone_corners
applied_lum_r = lum_r
applied_lum_g = lum_g
applied_lum_b = lum_b
UNSETEMPTY(effect_str)
UNSETEMPTY(affecting_turfs)
#undef EFFECT_UPDATE
#undef LUM_FALLOFF
+62 -67
View File
@@ -1,49 +1,20 @@
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()
var/datum/light_source/L
var/thing
for(thing in affecting_lights)
L = thing
L.vis_update()
lighting_corner_NE?.vis_update()
lighting_corner_SE?.vis_update()
lighting_corner_SW?.vis_update()
lighting_corner_NW?.vis_update()
/turf/proc/lighting_clear_overlay()
if(lighting_object)
qdel(lighting_object, TRUE)
var/datum/lighting_corner/C
var/thing
for(thing in corners)
if(!thing)
continue
C = thing
C.update_active()
qdel(lighting_object, force = TRUE)
// Builds a lighting object for us, but only if our area is dynamic.
/turf/proc/lighting_build_overlay()
if(lighting_object)
qdel(lighting_object,force=TRUE) //Shitty fix for lighting objects persisting after death
qdel(lighting_object, force = TRUE) // Shitty fix for lighting objects persisting after death
var/area/A = loc
if(!IS_DYNAMIC_LIGHTING(A) && !light_sources)
return
if(!lighting_corners_initialised)
generate_missing_corners()
new/atom/movable/lighting_object(src)
var/thing
var/datum/lighting_corner/C
var/datum/light_source/S
for(thing in corners)
if(!thing)
continue
C = thing
if(!C.active) // We would activate the corner, calculate the lighting for it.
for(thing in C.affecting)
S = thing
S.recalc_corner(C)
C.active = TRUE
new /datum/lighting_object(src)
// Used to get a scaled lumcount.
/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
@@ -51,13 +22,19 @@
return 1
var/totallums = 0
var/thing
var/datum/lighting_corner/L
for(thing in corners)
if(!thing)
continue
L = thing
totallums += L.lum_r + L.lum_b + L.lum_g
var/datum/lighting_corner/corner
corner = lighting_corner_NE
if(corner)
totallums += corner.lum_r + corner.lum_b + corner.lum_g
corner = lighting_corner_SE
if(corner)
totallums += corner.lum_r + corner.lum_b + corner.lum_g
corner = lighting_corner_SW
if(corner)
totallums += corner.lum_r + corner.lum_b + corner.lum_g
corner = lighting_corner_NW
if(corner)
totallums += corner.lum_r + corner.lum_b + corner.lum_g
totallums /= 12 // 4 corners, each with 3 channels, get the average.
@@ -73,23 +50,39 @@
if(!lighting_object)
return FALSE
return !lighting_object.luminosity
return !luminosity
// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
/turf/proc/recalc_atom_opacity()
has_opaque_atom = opacity
if(!has_opaque_atom)
for(var/atom/A in src.contents) // Loop through every movable atom on our tile PLUS ourselves (we matter too...)
if(A.opacity)
has_opaque_atom = TRUE
break
/// Proc to add movable sources of opacity on the turf and let it handle lighting code.
/turf/proc/add_opacity_source(atom/movable/new_source)
LAZYADD(opacity_sources, new_source)
if(opacity)
return
recalculate_directional_opacity()
/turf/Exited(atom/movable/Obj, direction)
. = ..()
/// Proc to remove movable sources of opacity on the turf and let it handle lighting code.
/turf/proc/remove_opacity_source(atom/movable/old_source)
LAZYREMOVE(opacity_sources, old_source)
if(opacity) // Still opaque, no need to worry on updating.
return
recalculate_directional_opacity()
if(Obj && Obj.opacity)
recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
reconsider_lights()
/// Calculate on which directions this turfs block view.
/turf/proc/recalculate_directional_opacity()
. = directional_opacity
if(opacity)
directional_opacity = ALL_CARDINALS
if(. != directional_opacity)
reconsider_lights()
return
directional_opacity = NONE
for(var/atom/movable/opacity_source in opacity_sources)
if(opacity_source.flags & ON_BORDER)
directional_opacity |= opacity_source.dir
else // If fulltile and opaque, then the whole tile blocks view, no need to continue checking.
directional_opacity = ALL_CARDINALS
break
if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS))
reconsider_lights() // The lighting system only cares whether the tile is fully concealed from all directions or not.
/turf/proc/change_area(area/old_area, area/new_area)
if(SSlighting.initialized)
@@ -102,14 +95,16 @@
machine.reregister_machine()
/turf/proc/generate_missing_corners()
if(!IS_DYNAMIC_LIGHTING(src) && !light_sources)
return
if(!lighting_corner_NE)
lighting_corner_NE = new /datum/lighting_corner(src, NORTH | EAST)
if(!lighting_corner_SE)
lighting_corner_SE = new /datum/lighting_corner(src, SOUTH | EAST)
if(!lighting_corner_SW)
lighting_corner_SW = new /datum/lighting_corner(src, SOUTH | WEST)
if(!lighting_corner_NW)
lighting_corner_NW = new /datum/lighting_corner(src, NORTH | WEST)
lighting_corners_initialised = TRUE
if(!corners)
corners = list(null, null, null, null)
for(var/i = 1 to 4)
if(corners[i]) // Already have a corner on this direction.
continue
corners[i] = new/datum/lighting_corner(src, GLOB.LIGHTING_CORNER_DIAGONAL[i])