Adds lighting height control (space color consistency) (#79046)

## About The Pull Request

Adds support for modifying a light's "height"
You can think of this as the distance it is from the ground below it
(Really it's the distance to the corners around it + 0.5 but yaknow) We
use it to keep wall lights from looking weird, but well, not everything
is a wall light

Floors tend to not be, and space in particular does not want to be
treated as such.
In fact, it wants a NEGATIVE height, so it acts as if it in on top of
all of its corners. This allows us to ensure that the starlight from
space and the starlight from starlight overlays always have the same
intensity and color, preventing weird lines from where the two
intersect, or starlight feeling not very present in cases with only one
turf

I've also bumped starlight's intensity form 0.75 to 1, this should help
with the lines thing discussed above.

## Why It's Good For The Game


![image](https://github.com/tgstation/tgstation/assets/58055496/240d1b3f-52c8-4569-8e74-0d801cbdb84d)

## Changelog
🆑
add: Starlight should be a bit more intense, and flow better onto non
space tiles
/🆑

---------

Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
LemonInTheDark
2023-10-21 20:44:18 +01:00
committed by GitHub
co-authored by Zephyr san7890
parent c276d0e3c8
commit a823708054
9 changed files with 55 additions and 15 deletions
+16 -1
View File
@@ -1,6 +1,6 @@
// The proc you should always use to set the light of this atom.
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_angle, l_dir, l_on)
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_angle, l_dir, l_height, l_on)
// We null everything but l_dir, because we don't want to allow for modifications while frozen
if(light_flags & LIGHT_FROZEN)
l_range = null
@@ -8,6 +8,7 @@
l_color = null
l_on = null
l_angle = null
l_height = null
if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
@@ -33,6 +34,9 @@
if(!isnull(l_on))
set_light_on(l_on)
if(!isnull(l_height))
set_light_height(l_height)
update_light()
/// Will update the light (duh).
@@ -167,6 +171,17 @@
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
return .
/// Setter for the height of our light
/atom/proc/set_light_height(new_value)
if(new_value == light_height || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_HEIGHT, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_height
light_height = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_HEIGHT, .)
return .
/// Setter for the light flags of this atom.
/atom/proc/set_light_flags(new_value)
if(new_value == light_flags || (light_flags & LIGHT_FROZEN && new_value & LIGHT_FROZEN))
+15 -9
View File
@@ -23,6 +23,8 @@
var/light_range
/// The colour of the light, string, decomposed by parse_light_color()
var/light_color
/// The height of the light. The larger this is, the dimmer we'll start
var/light_height
// Variables for keeping track of the colour.
var/lum_r
@@ -217,20 +219,20 @@
/datum/light_source/proc/get_sheet(multiz = FALSE)
var/list/static/key_to_sheet = list()
var/range = max(1, light_range);
var/key = "[range]-[visual_offset]-[offset_x]-[offset_y]-[light_dir]-[light_angle]-[multiz]"
var/key = "[range]-[visual_offset]-[offset_x]-[offset_y]-[light_dir]-[light_angle]-[light_height]-[multiz]"
var/list/hand_back = key_to_sheet[key]
if(!hand_back)
if(multiz)
hand_back = generate_sheet_multiz(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
hand_back = generate_sheet_multiz(range, visual_offset, offset_x, offset_y, light_dir, light_angle, light_height)
else
hand_back = generate_sheet(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
hand_back = generate_sheet(range, visual_offset, offset_x, offset_y, light_dir, light_angle, light_height)
key_to_sheet[key] = hand_back
return hand_back
/// Returns a list of lists that encodes the light falloff of our source
/// Takes anything that impacts our generation as input
/// This function should be "pure", no side effects or reads from the source object
/datum/light_source/proc/generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, z_level = 0)
/datum/light_source/proc/generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, height, z_level = 0)
var/list/encode = list()
// How far away the turfs we get are, and how many there are are often not the same calculation
// So we need to include the visual offset, so we can ensure our sheet is large enough to accept all the distance differences
@@ -241,30 +243,30 @@
for(var/x in (-(bound_range) + x_offset - 0.5) to (bound_range + x_offset + 0.5))
var/list/row = list()
for(var/y in (-(bound_range) + y_offset - 0.5) to (bound_range + y_offset + 0.5))
row += falloff_at_coord(x, y, z_level, range, center_dir, light_angle)
row += falloff_at_coord(x, y, z_level, range, center_dir, angle, height)
encode += list(row)
return encode
/// Returns a THREE dimensional list of lists that encodes the lighting falloff of our source
/// Takes anything that impacts our generation as input
/// This function should be "pure", no side effects or reads from the passed object
/datum/light_source/proc/generate_sheet_multiz(range, visual_offset, x_offset, y_offset, center_dir, angle)
/datum/light_source/proc/generate_sheet_multiz(range, visual_offset, x_offset, y_offset, center_dir, angle, height)
var/list/encode = list()
var/z_range = SSmapping.max_plane_offset // Let's just be safe yeah?
for(var/z in -z_range to z_range)
var/list/sheet = generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, z)
var/list/sheet = generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, height, z)
encode += list(sheet)
return encode
/// Takes x y and z offsets from the source as input, alongside our source's range
/// Returns a value between 0 and 1, 0 being dark on that tile, 1 being fully lit
/datum/light_source/proc/falloff_at_coord(x, y, z, range, center_dir, angle)
/datum/light_source/proc/falloff_at_coord(x, y, z, range, center_dir, angle, height)
var/range_divisor = max(1, range)
// You may notice we use squares here even though there are three components
// Because z diffs are so functionally small, cubes and cube roots are too aggressive
// The larger the distance is, the less bright our light will be
var/multiplier = 1 - CLAMP01(sqrt(x ** 2 + y ** 2 + z ** 2 + LIGHTING_HEIGHT) / range_divisor)
var/multiplier = 1 - CLAMP01(sqrt(x ** 2 + y ** 2 + z ** 2 + height) / range_divisor)
if(angle >= 360 || angle <= 0)
return multiplier
@@ -429,6 +431,10 @@
light_angle = source_atom.light_angle
update = TRUE
if(source_atom.light_height != light_height)
light_height = source_atom.light_height
update = TRUE
var/list/visual_offsets = calculate_light_offset(visual_source)
if(visual_offsets[1] != offset_x || visual_offsets[2] != offset_y || source_turf != old_source_turf)
offset_x = visual_offsets[1]