From 94167afa03f36f90fea886dbd3328be6a8b0e8b6 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sun, 22 Oct 2023 00:21:55 +0200 Subject: [PATCH] [MIRROR] Adds lighting height control (space color consistency) [MDB IGNORE] (#24501) * 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 :cl: add: Starlight should be a bit more intense, and flow better onto non space tiles /:cl: --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@ users.noreply.github.com> Co-authored-by: san7890 * Adds lighting height control (space color consistency) --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Zephyr <12817816+ZephyrTFA@ users.noreply.github.com> Co-authored-by: san7890 --- .../signals_atom/signals_atom_lighting.dm | 4 ++++ code/__DEFINES/lighting.dm | 4 ++++ code/datums/materials/_material.dm | 2 +- code/game/atoms.dm | 11 ++++++++- code/game/turfs/open/floor/glass.dm | 2 +- code/game/turfs/open/space/space.dm | 3 ++- code/game/turfs/turf.dm | 3 ++- code/modules/lighting/lighting_atom.dm | 17 ++++++++++++- code/modules/lighting/lighting_source.dm | 24 ++++++++++++------- 9 files changed, 55 insertions(+), 15 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm index 1289ca3a46c..391ed0112ac 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_lighting.dm @@ -31,6 +31,10 @@ #define COMSIG_ATOM_SET_LIGHT_ON "atom_set_light_on" ///Called right after the atom changes the value of light_on to a different one, from base of [/atom/proc/set_light_on]: (old_value) #define COMSIG_ATOM_UPDATE_LIGHT_ON "atom_update_light_on" +///Called right before the atom changes the value of light_height to a different one, from base [atom/proc/set_light_height]: (new_value) +#define COMSIG_ATOM_SET_LIGHT_HEIGHT "atom_set_light_height" +///Called right after the atom changes the value of light_height to a different one, from base of [/atom/proc/set_light_height]: (old_value) +#define COMSIG_ATOM_UPDATE_LIGHT_HEIGHT "atom_update_light_height" ///Called right before the atom changes the value of light_flags to a different one, from base [atom/proc/set_light_flags]: (new_flags) #define COMSIG_ATOM_SET_LIGHT_FLAGS "atom_set_light_flags" ///Called right after the atom changes the value of light_flags to a different one, from base of [/atom/proc/set_light_flags]: (old_flags) diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 6c56105f0ec..dba718901fb 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -28,6 +28,10 @@ #define LIGHTING_FALLOFF 1 /// use lambertian shading for light sources #define LIGHTING_LAMBERTIAN 0 +/// light UNDER the floor. primarily used for starlight, shouldn't fuck with this +#define LIGHTING_HEIGHT_SPACE -0.5 +/// light ON the floor +#define LIGHTING_HEIGHT_FLOOR 0 /// height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone #define LIGHTING_HEIGHT 1 /// Value used to round lumcounts, values smaller than 1/129 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY. diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm index 623f48b619c..53e661d39d8 100644 --- a/code/datums/materials/_material.dm +++ b/code/datums/materials/_material.dm @@ -165,7 +165,7 @@ Simple datum which is instanced once per type and is used for every object of sa if(!starlight_color) on.RegisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED, TYPE_PROC_REF(/turf, material_starlight_changed)) RegisterSignal(on, COMSIG_QDELETING, PROC_REF(lit_turf_deleted)) - on.set_light(2, 0.75, starlight_color || GLOB.starlight_color) + on.set_light(2, 1, starlight_color || GLOB.starlight_color, l_height = LIGHTING_HEIGHT_SPACE) /turf/proc/material_starlight_changed(datum/source, old_star, new_star) if(light_color == old_star) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 143c0c8f468..74bbb3f7cba 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -110,6 +110,8 @@ var/light_dir = NORTH ///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values. var/light_on = TRUE + /// How many tiles "up" this light is. 1 is typical, should only really change this if it's a floor light + var/light_height = LIGHTING_HEIGHT ///Bitflags to determine lighting-related atom properties. var/light_flags = NONE ///Our light source. Don't fuck with this directly unless you have a good reason! @@ -1300,8 +1302,15 @@ if(light_system == STATIC_LIGHT) set_light(l_dir = var_value) . = TRUE + if(NAMEOF(src, light_height)) + if(light_system == STATIC_LIGHT) + set_light(l_height = var_value) + . = TRUE if(NAMEOF(src, light_on)) - set_light_on(var_value) + if(light_system == STATIC_LIGHT) + set_light(l_on = var_value) + else + set_light_on(var_value) . = TRUE if(NAMEOF(src, light_flags)) set_light_flags(var_value) diff --git a/code/game/turfs/open/floor/glass.dm b/code/game/turfs/open/floor/glass.dm index de65179b561..c28ec9e1d4e 100644 --- a/code/game/turfs/open/floor/glass.dm +++ b/code/game/turfs/open/floor/glass.dm @@ -56,7 +56,7 @@ RegisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED, PROC_REF(starlight_changed)) else UnregisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED) - set_light(2, 0.75, starlight_color || GLOB.starlight_color) + set_light(2, 1, starlight_color || GLOB.starlight_color, l_height = LIGHTING_HEIGHT_SPACE) /turf/open/floor/glass/proc/starlight_changed(datum/source, old_star, new_star) if(light_color == old_star) diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 63a8f3449dd..182e918dc33 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -64,9 +64,10 @@ GLOBAL_LIST_EMPTY(starlight) run_later = TRUE plane = PLANE_SPACE layer = SPACE_LAYER - light_power = 0.75 + light_power = 1 light_range = 2 light_color = COLOR_STARLIGHT + light_height = LIGHTING_HEIGHT_SPACE light_on = FALSE space_lit = TRUE bullet_bounce_sound = null diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index d2fd05460b8..a16c5710521 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -5,7 +5,8 @@ GLOBAL_LIST_EMPTY(station_turfs) icon = 'icons/turf/floors.dmi' vis_flags = VIS_INHERIT_ID // Important for interaction with and visualization of openspace. luminosity = 1 - + light_height = LIGHTING_HEIGHT_FLOOR + ///what /mob/oranges_ear instance is already assigned to us as there should only ever be one. ///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration var/mob/oranges_ear/assigned_oranges_ear diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 2ab7ad1c134..5d82c33e23f 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -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)) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 73815ce86ce..90af6a855ce 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -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 @@ -216,20 +218,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 @@ -240,30 +242,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 @@ -428,6 +430,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]