[MDB IGNORE] Angled Lights & Lighting Prototyping Tool (#74365)

## About The Pull Request

Hello friends, I've been on a bit of a lighting kick recently, and I
decided I clearly do not have enough things to work on as it is.
This pr adds angle support to static lights, and a concepting/debug tool
for playing with lights on a map.

Let's start from first principles yeah?

### Why Angled Lights?

Mappers, since they can't actually see a light's effect in editor, tend
to go off gut.
That gut is based more off what "makes sense" then how things actually
work
This means they'll overplace light sources, and also they tend to treat
lights, particularly light "bars" (the bigger ones) as directional.
So you'll have two lights on either sides of a pillar, lights inside a
room with lights outside pointing out, etc.


![image](https://user-images.githubusercontent.com/58055496/228785032-63b86120-ea4c-4e52-b4e8-40a4b61e5bbc.png)

This has annoying side effects. A lot of our map is overlit, to the
point that knocking out a light does.... pretty much nothing.
I find this sad, and would like to work to prevent it. I think dark and
dim, while it does not suit the normal game, is amazing for vibes, and I
want it to be easier to see that.

Angled lights bring how lights work more in line with how mappers expect
lights work, and avoids bleedover into rooms that shouldn't be bled
into, working towards that goal of mine.

### How Angled Lights?

This is more complex then you'd first think so we'll go step by step


![image](https://user-images.githubusercontent.com/58055496/228786117-d937b408-9bc2-4066-9aee-aae21b047151.png)

Oh before we start, some catchup from the last time I touched lighting
code.
Instead of doing a lighting falloff calculation for each lighting corner
(a block that represents the resolution of our lights) in view we
instead generate cached lightsheets. These precalculate and store all
possible falloffs for x and y distances from a source.

This is very useful for angle work, since it makes it almost totally
free.
 
Atoms get 2 new values. light_angle and light_dir
Light angle is the angle the light uses, and light_dir is a cardinal
direction it displays in

We take these values, and inside sheetbuilding do some optional angle
work. getting the center angle, the angle of a pair of coords, and then
the delta between them.
This is then multiplied against the standard falloff formula, and job
done.

We do need some extra fenangling to make this all work nicely tho.

We currently use a pixel turf var stored on the light source to do
distance calculations.
This is the turf we pretend the light source is on for visuals, most
often used to make wall lights work nice.
The trouble is it's not very granular, and doesn't always have the
effect you might want.

So, instead of generating and storing a pixel turf to do our distance
calculations against, we store x and y offset variables.
We use them to expand our working range and sheet size to ensure things
visually make sense, and then offset any positions by them.

I've added a way for sources to have opinions on their offsets too, and
am using them for wall lights.
This ensures the angle calculations don't make the wall behind a light
fulldark, which would be silly.

### Debug Tool?

In the interest of helping with that core problem, lights being complex
to display, I've added a prototyping tool to the game.
It's locked behind mapping verbs, and works about like this.

Once the verb is activated, it iterates over all the sources in the
world (except turfs because those are kinda silly), outlining and
"freezing" them, preventing any future changes.
Then, it adds 3 buttons to the owners of a light source.

![image](https://user-images.githubusercontent.com/58055496/228776539-4b1d82af-1244-4ed6-8754-7f07e3e47cda.png)
The first button toggles the light on and off, as desired.
The third allows you to move the source around, with a little targeting
icon replacing your mouse
The second tho, that's more interesting.

The second button opens a debug menu for that light

![image](https://user-images.githubusercontent.com/58055496/228777811-ae620588-f08a-4b50-93a0-beea593aea77.png)
There's a lot here, let's go through it.

Bit on the left is a list of templates, which allow you to sample
existing light types (No I have no idea why the background is fullwhite,
need to work on that pre merge)
You can choose one by clicking it, and hitting the upload button.

This replaces your existing lighting values with the template's,
alongside replacing its icon and icon state so it looks right.
There are three types as of now, mostly for categorization. Bar, which
are the larger typically stronger lights, Bulb, which are well, bulbs,
and Misc which could be expanded, but currently just contains floor
lights.

Alongside that you can manually edit the power, range, color and angle
of the focused light.
I also have support for changing the direction of the light source,
since anything that uses directional lighting would also tie light dir
to it.
This isn't *always* done tho, so I should maybe find a way to edit light
dir too.

My hope is this tool will allow for better concepting of a room's
lights, and easier changing of individual object's light values to suit
the right visuals.

### Lemon No Why What

Ok so I applied angle lights to bars and bulbs, which means I am
changing the lighting of pretty much every map in the codebase.
I'm gonna uh, go check my work.

Alongside this I intend to give lighting some depth. So if there's room
to make a space warmer, or highlight light colors from other sources, I
will do that.

(Images as examples)

![image](https://user-images.githubusercontent.com/58055496/228786801-111b6493-c040-4199-ab99-ac1c914d034c.png)

I also want to work on that other goal of mine, making breaking lights
matter. So I'll be doing what I can to ensure you only need to break one
light to make a meaningful change in the scene.

This is semi complicated by one light source not ever actually reaching
fullbright on its own, but we do what we must because we can.


![image](https://user-images.githubusercontent.com/58055496/228786483-b7ad6ecd-874f-4d90-b5ca-6ef78cb70d2b.png)

I'm as I hope you know biased towards darker spaces, I think contrast
has vibes.
In particular I do not think strong lights really suit maintenance. 

Most of what is used there are bulbs, so I'm planning on replacing most
uses with low power bulbs, to keep light impacts to rooms, alongside
reducing the amount of lights placed in the main tunnels


![image](https://user-images.githubusercontent.com/58055496/228786594-c6d7610c-611e-478b-bcba-173ebf4c4b12.png)

**If you take issue with this methodology please do so NOW**, I don't
want to have to do another pass over things.
Oh also I'm saving station maps for last since ruins are less likely to
get touched in mapping march and all.

### Misc + Finishing Thoughts

Light templates support mirroring vars off typepaths using a subtype,
which means all the templates added here do not require updating if the
source type changes somehow. I'd like to expand the template list at
some point, perhaps in future.

I've opened this as a draft to make my intentions to make my changes to
lights known, and to serve as motivation for all the map changes I need
to do.

### Farish Future

I'm unhappy with how we currently configure lights. I would like a
system that more directly matches the idea of drawing falloff curves,
along with allowing for different falloffs for different colors,
alongside extending the idea to angle falloff.
This would make out of engine lighting easier, allow for nicer looking
lights (red to pink, blue to purple, etc), and improve accessibility by
artists.

This is slightly far off, because I have other obligations and it's
kinda complicated, but I'd like to mention it cause it's one of my many
pipedreams.

## Changelog
🆑
add: Added angle lighting, applies it to most wall lights!
add: Adds a lighting prototyping tool, mappers go try it out (it's
locked behind the mapping verb)
/🆑

---------

Co-authored-by: MMMiracles <lolaccount1@hotmail.com>
This commit is contained in:
LemonInTheDark
2023-07-18 21:39:55 -07:00
committed by GitHub
parent c881f2a34b
commit 41f20bc3ce
190 changed files with 138869 additions and 137213 deletions
+69 -7
View File
@@ -1,6 +1,14 @@
// 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_on)
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_angle, l_dir, 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
l_power = null
l_color = null
l_on = null
l_angle = 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.
@@ -16,6 +24,12 @@
if(l_color != NONSENSICAL_VALUE)
set_light_color(l_color)
if(!isnull(l_angle))
set_light_angle(l_angle)
if(!isnull(l_dir))
set_light_dir(l_dir)
if(!isnull(l_on))
set_light_on(l_on)
@@ -41,6 +55,7 @@
light.update(.)
else
light = new/datum/light_source(src, .)
return .
/**
* Updates the atom's opacity value.
@@ -49,11 +64,12 @@
* It notifies (potentially) affected light sources so they can update (if needed).
*/
/atom/proc/set_opacity(new_opacity)
if (new_opacity == opacity)
if (new_opacity == opacity || light_flags & LIGHT_FROZEN)
return
SEND_SIGNAL(src, COMSIG_ATOM_SET_OPACITY, new_opacity)
. = opacity
opacity = new_opacity
return .
/atom/movable/set_opacity(new_opacity)
. = ..()
@@ -86,50 +102,96 @@
/// Setter for the light power of this atom.
/atom/proc/set_light_power(new_power)
if(new_power == light_power)
if(new_power == light_power || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_power
light_power = new_power
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_POWER, .)
return .
/// Setter for the light range of this atom.
/atom/proc/set_light_range(new_range)
if(new_range == light_range)
if(new_range == light_range || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_range
light_range = new_range
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .)
return .
/// Setter for the light color of this atom.
/atom/proc/set_light_color(new_color)
if(new_color == light_color)
if(new_color == light_color || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_color
light_color = new_color
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .)
return .
/// Setter for the light angle of this atom
/atom/proc/set_light_angle(new_value)
if(new_value == light_angle || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ANGLE, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_angle
light_angle = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ANGLE, .)
return .
/// Setter for the light direction of this atom
/atom/proc/set_light_dir(new_value)
// No frozen check here because we allow direction changes in a freeze
if(new_value == light_dir)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_DIR, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_dir
light_dir = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_DIR, .)
return .
/// Setter for whether or not this atom's light is on.
/atom/proc/set_light_on(new_value)
if(new_value == light_on)
if(new_value == light_on || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_on
light_on = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
return .
/// Setter for the light flags of this atom.
/atom/proc/set_light_flags(new_value)
if(new_value == light_flags)
if(new_value == light_flags || (light_flags & LIGHT_FROZEN && new_value & LIGHT_FROZEN))
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_flags
light_flags = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .)
return .
/atom/proc/get_light_offset()
return list(0, 0)
/// Returns a list of x and y offsets to apply to our visual lighting position
/proc/calculate_light_offset(atom/get_offset)
var/list/hand_back
if(!(get_offset.light_flags & LIGHT_IGNORE_OFFSET))
hand_back = get_visual_offset(get_offset)
hand_back[1] = -hand_back[1] / world.icon_size
hand_back[2] = -hand_back[2] / world.icon_size
else
hand_back = list(0, 0)
var/list/atoms_opinion = get_offset.get_light_offset()
hand_back[1] += atoms_opinion[1]
hand_back[2] += atoms_opinion[2]
return hand_back
+35
View File
@@ -192,3 +192,38 @@
SSlighting.corners_queue -= src
return ..()
/// Debug proc to aid in understanding how corners work
/datum/lighting_corner/proc/display(max_lum)
if(QDELETED(src))
return
var/turf/draw_to = master_SW || master_NE || master_SE || master_NW
var/mutable_appearance/display = mutable_appearance('icons/turf/debug.dmi', "corner_color", LIGHT_DEBUG_LAYER, draw_to, BALLOON_CHAT_PLANE)
if(x > draw_to.x)
display.pixel_x = 16
else
display.pixel_x = -16
if(y > draw_to.y)
display.pixel_y = 16
else
display.pixel_y = -16
display.color = rgb(cache_r * 255, cache_g * 255, cache_b * 255)
draw_to.add_overlay(display)
/datum/lighting_corner/dummy/display()
return
/// Makes all lighting corners visible, debug to aid in understanding
/proc/display_corners()
var/list/corners = list()
var/max_lum = 0
for(var/datum/lighting_corner/corner) // I am so sorry
corners += corner
max_lum = max(max_lum, corner.largest_color_luminosity)
for(var/datum/lighting_corner/corner as anything in corners)
corner.display(max_lum)
+122 -49
View File
@@ -9,8 +9,14 @@
///The turf under the source atom.
var/turf/source_turf
///The turf the top_atom appears to over.
var/turf/pixel_turf
/// How much to x shift our light by when displaying it
var/offset_x = 0
/// How much to y shift our light by when displaying it
var/offset_y = 0
/// How much larger our light sheet should be, based off offset_x and y
/// We clamp to at least 1, so if offset_x is 0.1, then this'll be 1
var/visual_offset
///Intensity of the emitter light.
var/light_power
/// The range of the emitted light.
@@ -23,6 +29,11 @@
var/lum_g
var/lum_b
/// What direction our angled light is pointed
var/light_dir = NONE
/// How many degrees of a circle should our light show. 360 is all of it, 180 is half, etc
var/light_angle = 360
// The lumcount values used to apply the light.
var/tmp/applied_lum_r
var/tmp/applied_lum_g
@@ -45,7 +56,6 @@
add_to_light_sources(top_atom)
source_turf = top_atom
pixel_turf = get_turf_pixel(top_atom) || source_turf
light_power = source_atom.light_power
light_range = source_atom.light_range
@@ -54,6 +64,8 @@
PARSE_LIGHT_COLOR(src)
update()
if(GLOB.light_debug_enabled)
source_atom.debug()
/datum/light_source/Destroy(force)
remove_lum()
@@ -69,7 +81,6 @@
top_atom = null
source_atom = null
source_turf = null
pixel_turf = null
return ..()
@@ -140,23 +151,23 @@
// This exists so we can cache the vars used in this macro, and save MASSIVE time :)
// Most of this is saving off datum var accesses, tho some of it does actually cache computation
// You will NEED to call this before you call APPLY_CORNER
#define SETUP_CORNERS_CACHE(lighting_source) \
var/_turf_x = lighting_source.pixel_turf.x; \
var/_turf_y = lighting_source.pixel_turf.y; \
var/_turf_z = lighting_source.pixel_turf.z; \
var/list/_sheet = get_sheet(); \
var/list/_multiz_sheet = list(); \
if(!!GET_LOWEST_STACK_OFFSET(source_turf.z)) { \
_multiz_sheet = get_sheet(multiz = TRUE); \
} \
var/_range_offset = CEILING(lighting_source.light_range, 1) + 0.5 + 2; \
var/_multiz_offset = SSmapping.max_plane_offset + 1; \
var/_light_power = lighting_source.light_power; \
var/_applied_lum_r = lighting_source.applied_lum_r; \
var/_applied_lum_g = lighting_source.applied_lum_g; \
var/_applied_lum_b = lighting_source.applied_lum_b; \
var/_lum_r = lighting_source.lum_r; \
var/_lum_g = lighting_source.lum_g; \
#define SETUP_CORNERS_CACHE(lighting_source) \
var/_turf_x = lighting_source.source_turf.x; \
var/_turf_y = lighting_source.source_turf.y; \
var/_turf_z = lighting_source.source_turf.z; \
var/list/_sheet = get_sheet(); \
var/list/_multiz_sheet = list(); \
if(!!GET_LOWEST_STACK_OFFSET(source_turf.z)) { \
_multiz_sheet = get_sheet(multiz = TRUE); \
} \
var/_range_offset = CEILING(lighting_source.light_range, 1) + 0.5 + 1 + lighting_source.visual_offset; \
var/_multiz_offset = SSmapping.max_plane_offset + 1; \
var/_light_power = lighting_source.light_power; \
var/_applied_lum_r = lighting_source.applied_lum_r; \
var/_applied_lum_g = lighting_source.applied_lum_g; \
var/_applied_lum_b = lighting_source.applied_lum_b; \
var/_lum_r = lighting_source.lum_r; \
var/_lum_g = lighting_source.lum_g; \
var/_lum_b = lighting_source.lum_b;
#define SETUP_CORNERS_REMOVAL_CACHE(lighting_source) \
@@ -165,7 +176,7 @@
var/_applied_lum_b = lighting_source.applied_lum_b;
// Read out of our sources light sheet, a map of offsets -> the luminosity to use
#define LUM_FALLOFF(C) _sheet[C.x - _turf_x + _range_offset][C.y - _turf_y + _range_offset]
#define LUM_FALLOFF(C) _sheet[C.x - _turf_x + _range_offset][C.y - _turf_y + _range_offset]
#define LUM_FALLOFF_MULTIZ(C) _multiz_sheet[C.z - _turf_z + _multiz_offset][C.x - _turf_x + _range_offset][C.y - _turf_y + _range_offset]
// Macro that applies light to a new corner.
@@ -205,50 +216,98 @@
/datum/light_source/proc/get_sheet(multiz = FALSE)
var/list/static/key_to_sheet = list()
var/range = max(1, light_range);
var/key = "[range]-[multiz]"
var/key = "[range]-[visual_offset]-[offset_x]-[offset_y]-[light_dir]-[light_angle]-[multiz]"
var/list/hand_back = key_to_sheet[key]
if(!hand_back)
if(multiz)
hand_back = generate_sheet_multiz(range)
hand_back = generate_sheet_multiz(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
else
hand_back = generate_sheet(range)
hand_back = generate_sheet(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
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, z_level = 0)
/datum/light_source/proc/generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, z_level = 0)
var/list/encode = list()
var/bound_range = CEILING(range, 1) + 1
// 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
var/bound_range = CEILING(range, 1) + visual_offset
// Corners are placed at 0.5 offsets
// We need our coords to reflect that
for(var/x in (-bound_range - 0.5) to (bound_range + 0.5))
// We need our coords to reflect that (though x_offsets that change the basis for how things are calculated are fine too)
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 - 0.5) to (bound_range + 0.5))
row += falloff_at_coord(x, y, z_level, range)
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)
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)
/datum/light_source/proc/generate_sheet_multiz(range, visual_offset, x_offset, y_offset, center_dir, angle)
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, z)
var/list/sheet = generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, 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)
var/_range_divisor = max(1, range)
/datum/light_source/proc/falloff_at_coord(x, y, z, range, center_dir, angle)
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
return 1 - CLAMP01(sqrt(x ** 2 + y ** 2 + z ** 2 + LIGHTING_HEIGHT) / _range_divisor)
// 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)
if(angle >= 360 || angle <= 0)
return multiplier
// Turn our positional offset into an angle
var/coord_angle = delta_to_angle(x, y)
// Get the difference between the angle we want, and the angle we have
var/center_angle = dir2angle(center_dir)
var/angle_delta = abs(center_angle - coord_angle)
// Now we have to normalize the angle delta to be between 0 and 180, instead of 0 and 360
// This ensures removing say, 15 degrees removes it from both sides, rather then just one
// Turns an unfurling fan into a pair of scissors
if(angle_delta > 180)
angle_delta = 180 - (angle_delta - 180)
// We allow angle deltas to a certian amount, angle / 2
// If we pass that, then it starts effecting the visuals
// Oh and we'll scale it so 30 degrees is the "0" point, where things become fully dark
// This could be variable, it just isn't yet yaknow?
return max(multiplier * (1 - max(angle_delta - (angle / 2), 0) / 30), 0)
/// Dumps the content of a lighting sheet to chat, for debugging
/datum/light_source/proc/print_sheet()
var/list/sheet = get_sheet()
var/list/output = list()
var/multiz_depth = 1
// If we have a list 3 layers down we're multiz
if(length(sheet[1][1]))
multiz_depth = length(sheet)
var/column_seperator = ""
for(var/i in 1 to length(sheet))
column_seperator += "----"
output += column_seperator
for(var/i in 1 to multiz_depth)
for(var/list/column in sheet)
var/list/print_column = list()
for(var/row in column)
print_column += round(row, 0.1)
output += print_column.Join(", ")
output += column_seperator
to_chat(usr, "\n[output.Join("\n")]")
/// Debug proc, for when lighting sheets fuck up
/// Accepts the sheet (2 or 3 (multiz) dimensional list of lighting values at some offset)
/// alongside x and y delta values and the sheet's "offset", which is the amount required to ensure everything indexes at 1
/// Optionally, you can pass similar values for multiz stuff
/proc/read_sheet(list/sheet, x, y, offset, z, z_offset)
var/list/working = sheet
var/offset_x = x + offset
@@ -311,6 +370,7 @@
/datum/light_source/proc/refresh_values()
var/update = FALSE
var/atom/source_atom = src.source_atom
var/turf/old_source_turf = source_turf
if (QDELETED(source_atom))
qdel(src)
@@ -332,19 +392,16 @@
qdel(src)
return FALSE
if (isturf(top_atom))
if (source_turf != top_atom)
var/atom/visual_source = source_atom
if(isturf(top_atom))
visual_source = source_atom
if(source_turf != top_atom)
source_turf = top_atom
pixel_turf = source_turf
update = TRUE
else if (top_atom.loc != source_turf)
source_turf = top_atom.loc
pixel_turf = get_turf_pixel(top_atom)
update = TRUE
else
var/pixel_loc = get_turf_pixel(top_atom)
if (pixel_loc != pixel_turf)
pixel_turf = pixel_loc
visual_source = top_atom
if(top_atom.loc != source_turf)
source_turf = top_atom.loc
update = TRUE
if (!isturf(source_turf))
@@ -363,6 +420,21 @@
else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
update = TRUE
if(source_atom.light_dir != light_dir)
light_dir = source_atom.light_dir
update = TRUE
if (source_atom.light_angle != light_angle)
light_angle = source_atom.light_angle
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]
offset_y = visual_offsets[2]
visual_offset = max(CEILING(abs(offset_x), 1), CEILING(abs(offset_y), 1))
update = TRUE
// If we need to update, well, update
if (update)
needs_update = LIGHTING_CHECK_UPDATE
@@ -381,19 +453,20 @@
return list()
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
var/working_range = CEILING(light_range + visual_offset, 1)
source_turf.luminosity = working_range
var/uses_multiz = !!GET_LOWEST_STACK_OFFSET(source_turf.z)
if(!uses_multiz) // Yes I know this could be acomplished with an if in the for loop, but it's fukin lighting code man
for(var/turf/T in view(CEILING(light_range, 1), source_turf))
for(var/turf/T in view(working_range, source_turf))
if(IS_OPAQUE_TURF(T))
continue
INSERT_CORNERS(corners, T)
source_turf.luminosity = oldlum
return corners
for(var/turf/T in view(CEILING(light_range, 1), source_turf))
for(var/turf/T in view(working_range, source_turf))
if(IS_OPAQUE_TURF(T))
continue
INSERT_CORNERS(corners, T)
-1
View File
@@ -91,7 +91,6 @@
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.
///Transfer the lighting of one area to another
/turf/proc/transfer_area_lighting(area/old_area, area/new_area)
if(SSlighting.initialized && !space_lit)