mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-29 15:08:02 +01:00
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:
co-authored by
Contrabang
Burzah
parent
d175f3d1e4
commit
6862135913
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user