diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm
index 78e6e78d5cb..5b35a5b144c 100644
--- a/code/__DEFINES/colors.dm
+++ b/code/__DEFINES/colors.dm
@@ -63,7 +63,6 @@
#define COLOR_PAI_GREEN "#00FF88"
#define COLOR_PALE_GREEN "#20e28e"
-#define COLOR_BLUE_WHITE "#CCCEFF"
#define COLOR_CYAN "#00FFFF"
#define COLOR_DARK_CYAN "#00A2FF"
#define COLOR_TEAL "#008080"
@@ -174,6 +173,9 @@
///Colors for eigenstates
#define COLOR_PERIWINKLEE "#9999FF"
+
+/// Starlight!
+#define COLOR_STARLIGHT "#8589fa"
/**
* Some defines to generalise colours used in lighting.
*
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index d526b9c87b0..82bf1f9c807 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -47,9 +47,15 @@
#define O_LIGHTING_VISUAL_PLANE 11
#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE"
+#define EMISSIVE_PLANE 13
/// This plane masks out lighting to create an "emissive" effect, ie for glowing lights in otherwise dark areas.
-#define EMISSIVE_PLANE 14
+#define EMISSIVE_RENDER_PLATE 14
#define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE"
+// Ensures all the render targets that point at the emissive plate layer correctly
+#define EMISSIVE_Z_BELOW_LAYER 1
+#define EMISSIVE_FLOOR_LAYER 2
+#define EMISSIVE_SPACE_LAYER 3
+#define EMISSIVE_WALL_LAYER 4
/// Masks the emissive plane
#define EMISSIVE_MASK_PLANE 15
@@ -210,11 +216,18 @@
//---------- LIGHTING -------------
-#define LIGHTING_PRIMARY_LAYER 15 //The layer for the main lights of the station
-#define LIGHTING_PRIMARY_DIMMER_LAYER 15.1 //The layer that dims the main lights of the station
-#define LIGHTING_SECONDARY_LAYER 16 //The colourful, usually small lights that go on top
-
-
+// LIGHTING_PLANE layers
+// The layer of turf underlays starts at 0.01 and goes up by 0.01
+// Based off the z level. No I do not remember why, should check that
+/// Typically overlays, that "hide" portions of the turf underlay layer
+/// I'm allotting 100 z levels before this breaks. That'll never happen
+/// --Lemon
+#define LIGHTING_MASK_LAYER 10
+/// Misc things that draw on the turf lighting plane
+/// Space, solar beams, etc
+#define LIGHTING_PRIMARY_LAYER 15
+/// Stuff that needs to draw above everything else on this plane
+#define LIGHTING_ABOVE_ALL 20
//---------- EMISSIVES -------------
diff --git a/code/__HELPERS/lighting.dm b/code/__HELPERS/lighting.dm
index cb6fd5ea049..66a869ef4b8 100644
--- a/code/__HELPERS/lighting.dm
+++ b/code/__HELPERS/lighting.dm
@@ -31,3 +31,31 @@
var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, offset_spokesman, EMISSIVE_PLANE, alpha, appearance_flags | EMISSIVE_APPEARANCE_FLAGS, offset_const)
appearance.color = GLOB.em_block_color
return appearance
+
+/// Takes a non area atom and a threshold
+/// Makes it block emissive with any pixels with more alpha then that threshold, with the rest allowing the light to pass
+/// Returns a list of objects, automatically added to your vis_contents, that apply this effect
+/// QDEL them when appropriate
+/proc/partially_block_emissives(atom/make_blocker, alpha_to_leave)
+ var/static/uid = 0
+ uid++
+ if(!make_blocker.render_target)
+ make_blocker.render_target = "partial_emissive_block_[uid]"
+
+ // First, we cut away a constant amount
+ var/cut_away = (alpha_to_leave - 1) / 255
+ var/atom/movable/render_step/color/alpha_threshold_down = new(make_blocker, make_blocker.render_target, list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,-cut_away))
+ alpha_threshold_down.render_target = "*emissive_block_alpha_down_[uid]"
+ // Then we multiply what remains by the amount we took away
+ var/atom/movable/render_step/color/alpha_threshold_up = new(make_blocker, alpha_threshold_down.render_target, list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,alpha_to_leave, 0,0,0,0))
+ alpha_threshold_up.render_target = "*emissive_block_alpha_up_[uid]"
+ // Now we just feed that into an emissive blocker
+ var/atom/movable/render_step/emissive_blocker/em_block = new(make_blocker, alpha_threshold_up.render_target)
+ var/list/hand_back = list()
+ hand_back += alpha_threshold_down
+ hand_back += alpha_threshold_up
+ hand_back += em_block
+ // Cast to movable so we can use vis_contents. will work for turfs, but not for areas
+ var/atom/movable/vis_cast = make_blocker
+ vis_cast.vis_contents += hand_back
+ return hand_back
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index 9b157b9d7eb..325c719156b 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -198,6 +198,7 @@
icon_state = "flash"
transform = matrix(200, 0, 0, 0, 200, 0)
plane = LIGHTING_PLANE
+ layer = LIGHTING_ABOVE_ALL
blend_mode = BLEND_OVERLAY
show_when_dead = TRUE
needs_offsetting = FALSE
@@ -215,5 +216,6 @@
/atom/movable/screen/fullscreen/see_through_darkness
icon_state = "nightvision"
plane = LIGHTING_PLANE
+ layer = LIGHTING_ABOVE_ALL
blend_mode = BLEND_ADD
show_when_dead = TRUE
diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm
index 996f047bf56..343ff6b1625 100644
--- a/code/_onclick/hud/rendering/plane_master.dm
+++ b/code/_onclick/hud/rendering/plane_master.dm
@@ -248,6 +248,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
render_relay_planes = list(RENDER_PLANE_GAME, EMISSIVE_MASK_PLANE)
critical = PLANE_CRITICAL_FUCKO_PARALLAX // goes funny when touched. no idea why I don't trust byond
+/atom/movable/screen/plane_master/parallax_white/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_SPACE_LAYER)
+
///Contains space parallax
/atom/movable/screen/plane_master/parallax
name = "Parallax"
@@ -325,12 +329,20 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
plane = FLOOR_PLANE
render_relay_planes = list(RENDER_PLANE_GAME, EMISSIVE_MASK_PLANE)
+/atom/movable/screen/plane_master/floor/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_FLOOR_LAYER, relay_color = GLOB.em_block_color)
+
/atom/movable/screen/plane_master/wall
name = "Wall"
documentation = "Holds all walls. We render this onto the game world. Separate so we can use this + space and floor planes as a guide for where byond blackness is NOT."
plane = WALL_PLANE
render_relay_planes = list(RENDER_PLANE_GAME_WORLD, EMISSIVE_MASK_PLANE)
+/atom/movable/screen/plane_master/wall/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color)
+
/atom/movable/screen/plane_master/game
name = "Lower game world"
documentation = "Exists mostly because of FOV shit. Basically, if you've just got a normal not ABOVE fov thing, and you don't want it masked, stick it here yeah?"
@@ -380,6 +392,10 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
plane = WALL_PLANE_UPPER
render_relay_planes = list(RENDER_PLANE_GAME_WORLD, EMISSIVE_MASK_PLANE)
+/atom/movable/screen/plane_master/wall_upper/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset), relay_layer = EMISSIVE_WALL_LAYER, relay_color = GLOB.em_block_color)
+
/atom/movable/screen/plane_master/game_world_upper_fov_hidden
name = "Upper game world fov hidden"
documentation = "Just as we need a place to draw things \"above\" the hidden fov plane, we also need to be able to hide stuff that draws over the upper game plane."
@@ -473,25 +489,15 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/plane_master)
*/
/atom/movable/screen/plane_master/emissive
name = "Emissive"
- documentation = "This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.\
-
Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.\
-
Emissive blockers are pasted with an atom color that converts them to be entirely some different color.\
-
Emissive overlays and emissive blockers are put onto the same plane (This one).\
-
The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.\
-
A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.\
-
This is then used to alpha mask the lighting plane."
+ documentation = "Holds things that will be used to mask the lighting plane later on. Masked by the Emissive Mask plane to ensure we don't emiss out under a wall.\
+
Relayed onto the Emissive render plane to do the actual masking of lighting, since we need to be transformed and other emissive stuff needs to be transformed too.\
+
Don't want to double scale now."
plane = EMISSIVE_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- render_target = EMISSIVE_RENDER_TARGET
- render_relay_planes = list()
+ render_relay_planes = list(EMISSIVE_RENDER_PLATE)
critical = PLANE_CRITICAL_DISPLAY
-/atom/movable/screen/plane_master/emissive/Initialize(mapload)
- . = ..()
- add_filter("emissive_mask", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(EMISSIVE_MASK_RENDER_TARGET, offset)))
- add_filter("em_block_masking", 2, color_matrix_filter(GLOB.em_mask_matrix))
-
/atom/movable/screen/plane_master/pipecrawl
name = "Pipecrawl"
documentation = "Holds pipecrawl images generated during well, pipecrawling.\
diff --git a/code/_onclick/hud/rendering/render_plate.dm b/code/_onclick/hud/rendering/render_plate.dm
index 8116cc09b48..aa72c325bc8 100644
--- a/code/_onclick/hud/rendering/render_plate.dm
+++ b/code/_onclick/hud/rendering/render_plate.dm
@@ -183,6 +183,29 @@
else
enable_alpha()
+/atom/movable/screen/plane_master/rendering_plate/emissive_slate
+ name = "Emissive Plate"
+ documentation = "This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.\
+
Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.\
+
Emissive blockers are pasted with an atom color that converts them to be entirely some different color.\
+
Emissive overlays and emissive blockers are put onto the same plane (This one).\
+
The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.\
+
A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.\
+
This is then used to alpha mask the lighting plane."
+ plane = EMISSIVE_RENDER_PLATE
+ appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ render_target = EMISSIVE_RENDER_TARGET
+ render_relay_planes = list()
+ critical = PLANE_CRITICAL_DISPLAY
+
+/atom/movable/screen/plane_master/rendering_plate/emissive_slate/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ add_filter("emissive_mask", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(EMISSIVE_MASK_RENDER_TARGET, offset)))
+ add_filter("em_block_masking", 2, color_matrix_filter(GLOB.em_mask_matrix))
+ if(offset != 0)
+ add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset - 1), relay_layer = EMISSIVE_Z_BELOW_LAYER)
+
/atom/movable/screen/plane_master/rendering_plate/mask_emissive
name = "Emissive Mask"
documentation = "Any part of this plane that is transparent will be transparent in the emissive plane.\
@@ -190,11 +213,15 @@
We relay copies of the space, floor and wall planes to it, so we can use them as masks. Then we just boost any existing alpha to 100% and we're done."
plane = EMISSIVE_MASK_PLANE
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
- color = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,255, 0,0,0,0)
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
render_target = EMISSIVE_MASK_RENDER_TARGET
render_relay_planes = list()
+/atom/movable/screen/plane_master/rendering_plate/mask_emissive/Initialize(mapload, datum/plane_master_group/home, offset)
+ . = ..()
+ // Uses a filter cause the alpha slider will fuck up colors and we want to be editable
+ add_filter("pump_alpha", 1, color_matrix_filter(list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,255, 0,0,0,0)))
+
///render plate for OOC stuff like ghosts, hud-screen effects, etc
/atom/movable/screen/plane_master/rendering_plate/non_game
name = "Non-Game rendering plate"
@@ -232,19 +259,18 @@
/// Creates a connection between this plane master and the passed in plane
/// Helper for out of system code, shouldn't be used in this file
/// Build system to differenchiate between generated and non generated render relays
-/atom/movable/screen/plane_master/proc/add_relay_to(target_plane, blend_override)
+/atom/movable/screen/plane_master/proc/add_relay_to(target_plane, blend_override, relay_layer, relay_color)
if(get_relay_to(target_plane))
return
render_relay_planes += target_plane
- if(!relays_generated && isnull(blend_override))
- return
var/client/display_lad = home?.our_hud?.mymob?.client
- generate_relay_to(target_plane, show_to = display_lad, blend_override = blend_override)
+ var/atom/movable/render_plane_relay/relay = generate_relay_to(target_plane, show_to = display_lad, blend_override = blend_override, relay_layer = relay_layer)
+ relay.color = relay_color
/proc/get_plane_master_render_base(name)
return "*[name]: AUTOGENERATED RENDER TGT"
-/atom/movable/screen/plane_master/proc/generate_relay_to(target_plane, relay_loc, client/show_to, blend_override)
+/atom/movable/screen/plane_master/proc/generate_relay_to(target_plane, relay_loc, client/show_to, blend_override, relay_layer)
if(!length(relays) && !initial(render_target))
render_target = OFFSET_RENDER_TARGET(get_plane_master_render_base(name), offset)
if(!relay_loc)
@@ -265,7 +291,8 @@
// 2: lower planes (including offset ones) need to be layered below higher ones (because otherwise they'll render fucky)
// By multiplying LOWEST_EVER_PLANE by 30, we give 30 offsets worth of room to planes before they start going negative
// Bet
- relay.layer = (plane + abs(LOWEST_EVER_PLANE * 30)) //layer must be positive but can be a decimal
+ // We allow for manuel override if requested. careful with this
+ relay.layer = relay_layer || (plane + abs(LOWEST_EVER_PLANE * 30)) //layer must be positive but can be a decimal
relay.blend_mode = blend_to_use
relay.mouse_opacity = mouse_opacity
relay.name = render_target
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 5d63cb89d80..80beabfcbe9 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -879,4 +879,4 @@ GLOBAL_LIST_EMPTY(the_station_areas)
/proc/generate_lighting_appearance_by_z(z_level)
if(length(GLOB.default_lighting_underlays_by_z) < z_level)
GLOB.default_lighting_underlays_by_z.len = z_level
- GLOB.default_lighting_underlays_by_z[z_level] = mutable_appearance(LIGHTING_ICON, "transparent", z_level, null, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM, offset_const = GET_Z_PLANE_OFFSET(z_level))
+ GLOB.default_lighting_underlays_by_z[z_level] = mutable_appearance(LIGHTING_ICON, "transparent", z_level * 0.01, null, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM, offset_const = GET_Z_PLANE_OFFSET(z_level))
diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm
index 1f60a9e71e0..2bc86c0e236 100644
--- a/code/controllers/subsystem/overlays.dm
+++ b/code/controllers/subsystem/overlays.dm
@@ -138,42 +138,32 @@ SUBSYSTEM_DEF(overlays)
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
+ /// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
+ /// Drawn from the underlays list
+ var/list/realized_underlays
/image
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
+ /// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
+ /// Drawn from the underlays list
+ var/list/realized_underlays
-/// Takes the atoms's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
+/// Takes the atoms's existing overlays and underlays, and makes them mutable so they can be properly vv'd in the realized_overlays/underlays list
/atom/proc/realize_overlays()
- realized_overlays = list()
- var/list/queue = overlays.Copy()
- var/queue_index = 0
- while(queue_index < length(queue))
- queue_index++
- // If it's not a command, we assert that it's an appearance
- var/mutable_appearance/appearance = queue[queue_index]
- if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst
- continue
-
- var/mutable_appearance/new_appearance = new /mutable_appearance()
- new_appearance.appearance = appearance
- var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
- var/tmp_key = key
- var/overlay_indx = 1
- while(realized_overlays[tmp_key])
- tmp_key = "[key]-[overlay_indx]"
- overlay_indx++
-
- realized_overlays[tmp_key] = new_appearance
- // Now check its children
- for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
- queue += child_appearance
+ realized_overlays = realize_appearance_queue(overlays)
+ realized_underlays = realize_appearance_queue(underlays)
/// Takes the image's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
/image/proc/realize_overlays()
- realized_overlays = list()
- var/list/queue = overlays.Copy()
+ realized_overlays = realize_appearance_queue(overlays)
+ realized_underlays = realize_appearance_queue(underlays)
+
+/// Takes a list of appearnces, makes them mutable so they can be properly vv'd and inspected
+/proc/realize_appearance_queue(list/appearances)
+ var/list/real_appearances = list()
+ var/list/queue = appearances.Copy()
var/queue_index = 0
while(queue_index < length(queue))
queue_index++
@@ -186,15 +176,21 @@ SUBSYSTEM_DEF(overlays)
new_appearance.appearance = appearance
var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
var/tmp_key = key
- var/overlay_indx = 1
- while(realized_overlays[tmp_key])
- tmp_key = "[key]-[overlay_indx]"
- overlay_indx++
+ var/appearance_indx = 1
+ while(real_appearances[tmp_key])
+ tmp_key = "[key]-[appearance_indx]"
+ appearance_indx++
- realized_overlays[tmp_key] = new_appearance
+ real_appearances[tmp_key] = new_appearance
+ var/add_index = queue_index
// Now check its children
for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
- queue += child_appearance
+ add_index++
+ queue.Insert(add_index, child_appearance)
+ for(var/mutable_appearance/child_appearance as anything in appearance.underlays)
+ add_index++
+ queue.Insert(add_index, child_appearance)
+ return real_appearances
/// Takes two appearances as args, prints out, logs, and returns a text representation of their differences
/// Including suboverlays
diff --git a/code/datums/elements/decals/_decal.dm b/code/datums/elements/decals/_decal.dm
index a15136eb260..ab8d3b053af 100644
--- a/code/datums/elements/decals/_decal.dm
+++ b/code/datums/elements/decals/_decal.dm
@@ -43,7 +43,7 @@
decal.Detach(source)
for(var/result in resulting_decals_params)
- source.AddElement(/datum/element/decal, result["icon"], result["icon_state"], result["dir"], result["plane"], result["layer"], result["alpha"], result["color"], result["smoothing"], result["cleanable"], result["desc"])
+ source.AddElement(/datum/element/decal, result["icon"], result["icon_state"], result["dir"], PLANE_TO_TRUE(result["plane"]), result["layer"], result["alpha"], result["color"], result["smoothing"], result["cleanable"], result["desc"])
/datum/element/decal/proc/get_rotated_parameters(old_dir,new_dir)
@@ -111,7 +111,7 @@
return FALSE
var/temp_image = image(_icon, null, isnull(_smoothing) ? _icon_state : "[_icon_state]-[_smoothing]", _layer, _dir)
pic = new(temp_image)
- pic.plane = _plane
+ SET_PLANE_EXPLICIT(pic, _plane, source)
pic.color = _color
pic.alpha = _alpha
return TRUE
@@ -172,5 +172,5 @@
return NONE
Detach(source)
- source.AddElement(type, pic.icon, base_icon_state, directional, pic.plane, pic.layer, pic.alpha, pic.color, smoothing_junction, cleanable, description)
+ source.AddElement(type, pic.icon, base_icon_state, directional, PLANE_TO_TRUE(pic.plane), pic.layer, pic.alpha, pic.color, smoothing_junction, cleanable, description)
return NONE
diff --git a/code/datums/materials/_material.dm b/code/datums/materials/_material.dm
index aeb1c680957..7151181c409 100644
--- a/code/datums/materials/_material.dm
+++ b/code/datums/materials/_material.dm
@@ -20,6 +20,9 @@ Simple datum which is instanced once per type and is used for every object of sa
var/greyscale_colors
///Base alpha of the material, is used for greyscale icons.
var/alpha = 255
+ ///Starlight color of the material
+ ///This is the color of light it'll emit if its turf is transparent and over space
+ var/starlight_color = COLOR_STARLIGHT
///Bitflags that influence how SSmaterials handles this material.
var/init_flags = MATERIAL_INIT_MAPLOAD
///Materials "Traits". its a map of key = category | Value = Bool. Used to define what it can be used for
@@ -140,8 +143,17 @@ Simple datum which is instanced once per type and is used for every object of sa
O.heavyfootstep = turf_sound_override
if(alpha < 255)
T.AddElement(/datum/element/turf_z_transparency)
+ setup_glow(T)
return
+/datum/material/proc/setup_glow(turf/on)
+ if(GET_TURF_PLANE_OFFSET(on) != GET_LOWEST_STACK_OFFSET(on.z)) // We ain't the bottom brother
+ return
+ // We assume no parallax means no space means no light
+ if(SSmapping.level_trait(on.z, ZTRAIT_NOPARALLAX))
+ return
+ on.set_light(2, 0.75, starlight_color)
+
/datum/material/proc/get_greyscale_config_for(datum/greyscale_config/config_path)
if(!config_path)
return
diff --git a/code/datums/materials/alloys.dm b/code/datums/materials/alloys.dm
index 419b42630c4..ebaccb3cfa2 100644
--- a/code/datums/materials/alloys.dm
+++ b/code/datums/materials/alloys.dm
@@ -84,6 +84,7 @@
color = "#ff80f4"
greyscale_colors = "#ff80f496"
alpha = 150
+ starlight_color = COLOR_STRONG_MAGENTA
init_flags = MATERIAL_INIT_MAPLOAD
integrity_modifier = 0.5
armor_modifiers = list(MELEE = 0.8, BULLET = 0.8, LASER = 1.2, ENERGY = 1.2, BOMB = 0.3, BIO = 1.2, FIRE = 2, ACID = 2)
@@ -103,6 +104,7 @@
color = "#cfbee0"
greyscale_colors = "#cfbee096"
alpha = 150
+ starlight_color = COLOR_COMMAND_BLUE
init_flags = MATERIAL_INIT_MAPLOAD
armor_modifiers = list(MELEE = 1.2, BULLET = 1.2, LASER = 0.8, ENERGY = 0.8, BOMB = 0.5, BIO = 1.2, FIRE = 0.8, ACID = 2)
sheet_type = /obj/item/stack/sheet/titaniumglass
@@ -120,6 +122,7 @@
desc = "A specialized silicate-plastitanium alloy."
color = "#5d3369"
greyscale_colors = "#5d336996"
+ starlight_color = COLOR_CENTCOM_BLUE
alpha = 150
init_flags = MATERIAL_INIT_MAPLOAD
integrity_modifier = 1.1
diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm
index a934932d972..7cdb5fc054b 100644
--- a/code/datums/materials/basemats.dm
+++ b/code/datums/materials/basemats.dm
@@ -18,6 +18,7 @@
desc = "Glass forged by melting sand."
color = "#88cdf1"
greyscale_colors = "#88cdf196"
+ starlight_color = COLOR_STARLIGHT
alpha = 150
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
integrity_modifier = 0.1
@@ -77,6 +78,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
alpha = 132
+ starlight_color = COLOR_BLUE_LIGHT
value_per_unit = 0.25
beauty_modifier = 0.3
armor_modifiers = list(MELEE = 1.3, BULLET = 1.3, LASER = 0.6, ENERGY = 1, BOMB = 1.2, BIO = 1, FIRE = 1, ACID = 1)
@@ -158,6 +160,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
greyscale_colors = "#4e7dffC8"
alpha = 200
+ starlight_color = COLOR_BLUE
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_ITEM_MATERIAL = TRUE)
beauty_modifier = 0.5
sheet_type = /obj/item/stack/sheet/bluespace_crystal
@@ -338,6 +341,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
color = "#88cdf1"
greyscale_colors = "#88cdf196"
alpha = 150
+ starlight_color = COLOR_BLUE_LIGHT
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/hot_ice
value_per_unit = 0.2
@@ -362,6 +366,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
color = "#f2d5d7"
greyscale_colors = "#f2d5d796"
alpha = 150
+ starlight_color = COLOR_MODERATE_BLUE
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/mineral/metal_hydrogen
value_per_unit = 0.35
diff --git a/code/datums/materials/hauntium.dm b/code/datums/materials/hauntium.dm
index f00d1c73e6d..9a4e09f9081 100644
--- a/code/datums/materials/hauntium.dm
+++ b/code/datums/materials/hauntium.dm
@@ -4,6 +4,7 @@
color = list(460/255, 464/255, 460/255, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
greyscale_colors = "#FFFFFF64"
alpha = 100
+ starlight_color = COLOR_ALMOST_BLACK
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE, MAT_CATEGORY_ITEM_MATERIAL=TRUE)
sheet_type = /obj/item/stack/sheet/hauntium
value_per_unit = 0.05
diff --git a/code/game/area/areas/misc.dm b/code/game/area/areas/misc.dm
index ac085cd2c94..8ffa8e452a5 100644
--- a/code/game/area/areas/misc.dm
+++ b/code/game/area/areas/misc.dm
@@ -7,6 +7,7 @@
static_lighting = FALSE
base_lighting_alpha = 255
+ base_lighting_color = COLOR_STARLIGHT
power_light = FALSE
power_equip = FALSE
power_environ = FALSE
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index d67695d0093..4b04d1b2a4a 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -76,7 +76,7 @@
/// Either FALSE, [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE]
var/blocks_emissive = FALSE
///Internal holder for emissive blocker object, do not use directly use blocks_emissive
- var/atom/movable/emissive_blocker/em_block
+ var/atom/movable/render_step/emissive_blocker/em_block
///Used for the calculate_adjacencies proc for icon smoothing.
var/can_be_unanchored = FALSE
@@ -221,6 +221,53 @@
em_block = new(src, render_target)
return em_block
+/// Generates a space underlay for a turf
+/// This provides proper lighting support alongside just looking nice
+/// Accepts the appearance to make "spaceish", and the turf we're doing this for
+/proc/generate_space_underlay(mutable_appearance/underlay_appearance, turf/generate_for)
+ underlay_appearance.icon = 'icons/turf/space.dmi'
+ underlay_appearance.icon_state = "space"
+ SET_PLANE(underlay_appearance, PLANE_SPACE, generate_for)
+ if(!generate_for.render_target)
+ generate_for.render_target = ref(generate_for)
+ var/atom/movable/render_step/emissive_blocker/em_block = new(null, generate_for.render_target)
+ underlay_appearance.overlays += em_block
+ // We used it because it's convienient and easy, but it's gotta go now or it'll hang refs
+ QDEL_NULL(em_block)
+ // We're gonna build a light, and mask it with the base turf's appearance
+ // grab a 32x32 square of it
+ var/mutable_appearance/light = new(GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(generate_for) + 1])
+ light.appearance_flags |= KEEP_TOGETHER
+ // Now apply a copy of the turf, set to multiply
+ // This will multiply against our light, so we only light up the bits that aren't "on" the wall
+ var/mutable_appearance/mask = new(generate_for.appearance)
+ mask.blend_mode = BLEND_MULTIPLY
+ mask.render_target = ""
+ mask.pixel_x = 0
+ mask.pixel_y = 0
+ mask.pixel_w = 0
+ mask.pixel_z = 0
+ mask.transform = null
+ mask.underlays = list() // Begone foul lighting overlay
+ SET_PLANE(mask, FLOAT_PLANE, generate_for)
+ mask.layer = FLOAT_LAYER
+
+ // Bump the opacity to full, will this work?
+ mask.color = list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,255, 0,0,0,0)
+ light.overlays += mask
+ underlay_appearance.overlays += light
+
+ // Now, we're going to make a copy of the mask. Instead of using it to multiply against our light
+ // We're going to use it to multiply against the turf lighting plane. Going to mask away the turf light
+ // And rely on LIGHTING_MASK_LAYER to ensure we mask ONLY that bit
+ var/mutable_appearance/turf_mask = new(mask.appearance)
+ SET_PLANE(turf_mask, LIGHTING_PLANE, generate_for)
+ turf_mask.layer = LIGHTING_MASK_LAYER
+ /// Any color becomes white. Anything else is black, and it's fully opaque
+ /// Ought to work
+ turf_mask.color = list(255,255,255,0, 255,255,255,0, 255,255,255,0, 0,0,0,0, 0,0,0,255)
+ underlay_appearance.overlays += turf_mask
+
/atom/movable/update_overlays()
. = ..()
var/emissive_block = update_emissive_block()
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index a84cc10f9d5..df248bdc38a 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -63,6 +63,7 @@
icon = 'icons/effects/alphacolors.dmi'
icon_state = "white"
plane = LIGHTING_PLANE
+ layer = LIGHTING_ABOVE_ALL
blend_mode = BLEND_ADD
luminosity = 1
diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm
index eec30f3b7d1..e74c62fe948 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube.dm
@@ -18,7 +18,7 @@
if(newdirection)
setDir(newdirection)
init_tube_dirs()
- generate_tube_overlays()
+ update_appearance()
AddElement(/datum/element/climbable)
/obj/structure/transit_tube/Destroy()
@@ -123,24 +123,24 @@
if(WEST)
tube_dirs = list(EAST, WEST)
-
-/obj/structure/transit_tube/proc/generate_tube_overlays()
+/obj/structure/transit_tube/update_overlays()
+ . = ..()
for(var/direction in tube_dirs)
- if(ISDIAGONALDIR(direction))
- if(direction & NORTH)
- create_tube_overlay(direction ^ 3, NORTH)
+ if(!ISDIAGONALDIR(direction))
+ . += create_tube_overlay(direction)
+ continue
+ if(!(direction & NORTH))
+ continue
- if(direction & EAST)
- create_tube_overlay(direction ^ 12, EAST)
-
- else
- create_tube_overlay(direction ^ 12, WEST)
+ . += create_tube_overlay(direction ^ 3, NORTH)
+ if(direction & EAST)
+ . += create_tube_overlay(direction ^ 12, EAST)
else
- create_tube_overlay(direction)
-
+ . += create_tube_overlay(direction ^ 12, WEST)
/obj/structure/transit_tube/proc/create_tube_overlay(direction, shift_dir)
- var/image/tube_overlay = new(dir = direction)
+ // We use image() because a mutable appearance will have its dir mirror the parent which sort of fucks up what we're doing here
+ var/image/tube_overlay = image(icon, dir = direction)
if(shift_dir)
tube_overlay.icon_state = "decorative_diag"
switch(shift_dir)
@@ -154,10 +154,9 @@
tube_overlay.pixel_x = -32
else
tube_overlay.icon_state = "decorative"
- add_overlay(tube_overlay)
-
-
+ tube_overlay.overlays += emissive_blocker(icon, tube_overlay.icon_state, src)
+ return tube_overlay
//Some of these are mostly for mapping use
/obj/structure/transit_tube/horizontal
diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm
index 702212b1bc6..3a1cc8aaac3 100644
--- a/code/game/turfs/change_turf.dm
+++ b/code/game/turfs/change_turf.dm
@@ -77,7 +77,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_directional_opacity = directional_opacity
var/old_dynamic_lumcount = dynamic_lumcount
var/old_rcd_memory = rcd_memory
- var/old_always_lit = always_lit
+ var/old_space_lit = space_lit
var/old_explosion_throw_details = explosion_throw_details
// We get just the bits of explosive_resistance that aren't the turf
var/old_explosive_resistance = explosive_resistance - get_explosive_block()
@@ -132,11 +132,12 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
lattice_underneath = old_lattice_underneath
- if(new_turf.always_lit)
+ var/area/our_area = new_turf.loc
+ if(new_turf.space_lit && !our_area.area_has_base_lighting)
// We are guarenteed to have these overlays because of how generation works
var/mutable_appearance/overlay = GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]
new_turf.add_overlay(overlay)
- else if (old_always_lit)
+ else if (old_space_lit && !our_area.area_has_base_lighting)
var/mutable_appearance/overlay = GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]
new_turf.cut_overlay(overlay)
@@ -154,9 +155,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
// We will only run this logic if the tile is not on the prime z layer, since we use area overlays to cover that
if(SSmapping.z_level_to_plane_offset[z])
- var/area/thisarea = get_area(new_turf)
- if(thisarea.lighting_effects)
- new_turf.add_overlay(thisarea.lighting_effects[SSmapping.z_level_to_plane_offset[z] + 1])
+ if(our_area.lighting_effects)
+ new_turf.add_overlay(our_area.lighting_effects[SSmapping.z_level_to_plane_offset[z] + 1])
if(flags_1 & INITIALIZED_1) // only queue for smoothing if SSatom initialized us
QUEUE_SMOOTH_NEIGHBORS(src)
diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm
index b761591b3c4..a29488f2ebf 100644
--- a/code/game/turfs/closed/walls.dm
+++ b/code/game/turfs/closed/walls.dm
@@ -42,9 +42,7 @@
if(smoothing_flags & SMOOTH_DIAGONAL_CORNERS && fixed_underlay) //Set underlays for the diagonal walls.
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, offset_spokesman = src, plane = FLOOR_PLANE)
if(fixed_underlay["space"])
- underlay_appearance.icon = 'icons/turf/space.dmi'
- underlay_appearance.icon_state = "space"
- SET_PLANE(underlay_appearance, PLANE_SPACE, src)
+ generate_space_underlay(underlay_appearance, src)
else
underlay_appearance.icon = fixed_underlay["icon"]
underlay_appearance.icon_state = fixed_underlay["icon_state"]
diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm
index 9b2fa3c61bb..f25dbe4244c 100644
--- a/code/game/turfs/open/floor/fancy_floor.dm
+++ b/code/game/turfs/open/floor/fancy_floor.dm
@@ -815,7 +815,5 @@
return list("damaged")
/turf/open/floor/fakespace/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
- underlay_appearance.icon = 'icons/turf/space.dmi'
- underlay_appearance.icon_state = "space"
- SET_PLANE(underlay_appearance, PLANE_SPACE, src)
+ generate_space_underlay(underlay_appearance, asking_turf)
return TRUE
diff --git a/code/game/turfs/open/floor/glass.dm b/code/game/turfs/open/floor/glass.dm
index d00d25998f1..beb1535e694 100644
--- a/code/game/turfs/open/floor/glass.dm
+++ b/code/game/turfs/open/floor/glass.dm
@@ -16,6 +16,13 @@
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
floor_tile = /obj/item/stack/tile/glass
overfloor_placed = FALSE
+ /// List of /atom/movable/render_step that are being used to make this glass floor glow
+ /// These are OWNED by this floor, they delete when we delete them, not before not after
+ var/list/glow_stuff
+ /// How much alpha to leave when cutting away emissive blockers
+ var/alpha_to_leave = 255
+ /// Color of starlight to use
+ var/starlight_color = COLOR_STARLIGHT
/turf/open/floor/glass/broken_states()
return list("glass-damaged1", "glass-damaged2", "glass-damaged3")
@@ -28,6 +35,23 @@
/turf/open/floor/glass/LateInitialize()
. = ..()
AddElement(/datum/element/turf_z_transparency)
+ setup_glow()
+
+/turf/open/floor/glass/Destroy()
+ . = ..()
+ QDEL_LIST(glow_stuff)
+
+/// If this turf is at the bottom of the local rendering stack
+/// Then we're gonna make it emissive block so the space below glows
+/turf/open/floor/glass/proc/setup_glow()
+ if(GET_TURF_PLANE_OFFSET(src) != GET_LOWEST_STACK_OFFSET(z)) // We ain't the bottom brother
+ return
+ // We assume no parallax means no space means no light
+ if(SSmapping.level_trait(z, ZTRAIT_NOPARALLAX))
+ return
+
+ glow_stuff = partially_block_emissives(src, alpha_to_leave)
+ set_light(2, 0.75, starlight_color)
/turf/open/floor/glass/make_plating()
return
@@ -45,7 +69,7 @@
icon_state = "reinf_glass-0"
base_icon_state = "reinf_glass"
floor_tile = /obj/item/stack/tile/rglass
-
+ alpha_to_leave = 206
/turf/open/floor/glass/reinforced/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
@@ -60,6 +84,8 @@
icon_state = "plasma_glass-0"
base_icon_state = "plasma_glass"
floor_tile = /obj/item/stack/tile/glass/plasma
+ starlight_color = COLOR_STRONG_VIOLET
+ alpha_to_leave = 255
/turf/open/floor/glass/plasma/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
@@ -74,6 +100,8 @@
icon_state = "reinf_plasma_glass-0"
base_icon_state = "reinf_plasma_glass"
floor_tile = /obj/item/stack/tile/rglass/plasma
+ starlight_color = COLOR_STRONG_VIOLET
+ alpha_to_leave = 206
/turf/open/floor/glass/reinforced/plasma/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm
index 28f91340186..f2ae490bb0a 100644
--- a/code/game/turfs/open/space/space.dm
+++ b/code/game/turfs/open/space/space.dm
@@ -19,8 +19,9 @@
run_later = TRUE
plane = PLANE_SPACE
layer = SPACE_LAYER
- light_power = 0.25
- always_lit = TRUE
+ light_power = 0.75
+ light_color = COLOR_STARLIGHT
+ space_lit = TRUE
bullet_bounce_sound = null
vis_flags = VIS_INHERIT_ID //when this be added to vis_contents of something it be associated with something on clicking, important for visualisation of turf in openspace and interraction with openspace that show you turf.
@@ -58,7 +59,7 @@
plane = PLANE_SPACE - (PLANE_RANGE * SSmapping.z_level_to_plane_offset[z])
var/area/our_area = loc
- if(!our_area.area_has_base_lighting && always_lit) //Only provide your own lighting if the area doesn't for you
+ if(!our_area.area_has_base_lighting && space_lit) //Only provide your own lighting if the area doesn't for you
// Intentionally not add_overlay for performance reasons.
// add_overlay does a bunch of generic stuff, like creating a new list for overlays,
// queueing compile, cloning appearance, etc etc etc that is not necessary here.
@@ -106,7 +107,7 @@
if(isspaceturf(t))
//let's NOT update this that much pls
continue
- set_light(2, 1.25, COLOR_BLUE_WHITE)
+ set_light(2)
return
set_light(0)
@@ -184,9 +185,7 @@
return FALSE
/turf/open/space/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
- underlay_appearance.icon = 'icons/turf/space.dmi'
- underlay_appearance.icon_state = "space"
- SET_PLANE(underlay_appearance, PLANE_SPACE, src)
+ generate_space_underlay(underlay_appearance, asking_turf)
return TRUE
@@ -244,6 +243,7 @@
/turf/open/space/openspace/Initialize(mapload) // handle plane and layer here so that they don't cover other obs/turfs in Dream Maker
. = ..()
icon_state = "invisible"
+ update_starlight()
return INITIALIZE_HINT_LATELOAD
/turf/open/space/openspace/LateInitialize()
@@ -283,3 +283,17 @@
return FALSE
return TRUE
return FALSE
+
+/turf/open/space/openspace/update_starlight()
+ if(!CONFIG_GET(flag/starlight))
+ return
+ var/turf/below = SSmapping.get_turf_below(src)
+ if(!isspaceturf(below))
+ return
+ for(var/t in RANGE_TURFS(1,src)) //RANGE_TURFS is in code\__HELPERS\game.dm
+ if(isspaceturf(t))
+ //let's NOT update this that much pls
+ continue
+ set_light(2)
+ return
+ set_light(0)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 3ecadaed44a..4bbe3f8f2cc 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -54,7 +54,8 @@ GLOBAL_LIST_EMPTY(station_turfs)
var/dynamic_lumcount = 0
///Bool, whether this turf will always be illuminated no matter what area it is in
- var/always_lit = FALSE
+ ///Makes it look blue, be warned
+ var/space_lit = FALSE
var/tmp/lighting_corners_initialised = FALSE
@@ -154,7 +155,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
Entered(content, null)
var/area/our_area = loc
- if(!our_area.area_has_base_lighting && always_lit) //Only provide your own lighting if the area doesn't for you
+ if(!our_area.area_has_base_lighting && space_lit) //Only provide your own lighting if the area doesn't for you
var/mutable_appearance/overlay = GLOB.fullbright_overlays[GET_TURF_PLANE_OFFSET(src) + 1]
add_overlay(overlay)
diff --git a/code/modules/awaymissions/cordon.dm b/code/modules/awaymissions/cordon.dm
index eaebbaca5a9..0c6685b1aae 100644
--- a/code/modules/awaymissions/cordon.dm
+++ b/code/modules/awaymissions/cordon.dm
@@ -11,7 +11,7 @@
density = TRUE
blocks_air = TRUE
init_air = FALSE
- always_lit = TRUE
+ space_lit = TRUE
bullet_bounce_sound = null
turf_flags = NOJAUNT
baseturfs = /turf/cordon
diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm
deleted file mode 100644
index a3f291526ff..00000000000
--- a/code/modules/lighting/emissive_blocker.dm
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Internal atom that copies an appearance on to the blocker plane
- *
- * Copies an appearance vis render_target and render_source on to the emissive blocking plane.
- * This means that the atom in question will block any emissive sprites.
- * This should only be used internally. If you are directly creating more of these, you're
- * almost guaranteed to be doing something wrong.
- */
-/atom/movable/emissive_blocker
- name = "emissive blocker"
- plane = EMISSIVE_PLANE
- layer = FLOAT_LAYER
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- //Why?
- //render_targets copy the transform of the target as well, but vis_contents also applies the transform
- //to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform.
- //Since only render_target handles transform we don't get any applied transform "stacking"
- appearance_flags = EMISSIVE_APPEARANCE_FLAGS
-
-/atom/movable/emissive_blocker/Initialize(mapload, source)
- . = ..()
- verbs.Cut() //Cargo culting from lighting object, this maybe affects memory usage?
-
- render_source = source
- color = GLOB.em_block_color
-
-
-/atom/movable/emissive_blocker/ex_act(severity)
- return FALSE
-
-/atom/movable/emissive_blocker/singularity_act()
- return
-
-/atom/movable/emissive_blocker/singularity_pull()
- return
-
-/atom/movable/emissive_blocker/blob_act()
- return
-
-//Prevents people from moving these after creation, because they shouldn't be.
-/atom/movable/emissive_blocker/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
- if(harderforce)
- return ..()
diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm
index 63b038b4026..541569be0fb 100644
--- a/code/modules/lighting/lighting_setup.dm
+++ b/code/modules/lighting/lighting_setup.dm
@@ -5,7 +5,7 @@
continue
for(var/turf/T as anything in A.get_contained_turfs())
- if(T.always_lit)
+ if(T.space_lit)
continue
new/datum/lighting_object(T)
CHECK_TICK
diff --git a/code/modules/lighting/static_lighting_area.dm b/code/modules/lighting/static_lighting_area.dm
index e4d222dfe81..dc8e9c48879 100644
--- a/code/modules/lighting/static_lighting_area.dm
+++ b/code/modules/lighting/static_lighting_area.dm
@@ -7,6 +7,7 @@ GLOBAL_LIST_INIT_TYPED(fullbright_overlays, /mutable_appearance, list(create_ful
SET_PLANE_W_SCALAR(lighting_effect, LIGHTING_PLANE, offset)
lighting_effect.layer = LIGHTING_PRIMARY_LAYER
lighting_effect.blend_mode = BLEND_ADD
+ lighting_effect.color = COLOR_STARLIGHT
return lighting_effect
/area
@@ -20,7 +21,7 @@ GLOBAL_LIST_INIT_TYPED(fullbright_overlays, /mutable_appearance, list(create_ful
///regenerates lighting objects for turfs in this area, primary use is VV changes
/area/proc/create_area_lighting_objects()
for(var/turf/T in src)
- if(T.always_lit)
+ if(T.space_lit)
continue
T.lighting_build_overlay()
CHECK_TICK
@@ -28,7 +29,7 @@ GLOBAL_LIST_INIT_TYPED(fullbright_overlays, /mutable_appearance, list(create_ful
///Removes lighting objects from turfs in this area if we have them, primary use is VV changes
/area/proc/remove_area_lighting_objects()
for(var/turf/T in src)
- if(T.always_lit)
+ if(T.space_lit)
continue
T.lighting_clear_overlay()
CHECK_TICK
diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm
index 40bef56bd5e..b87a1142e2c 100644
--- a/code/modules/mapping/map_template.dm
+++ b/code/modules/mapping/map_template.dm
@@ -99,7 +99,7 @@
SSatoms.InitializeAtoms(areas + turfs + movables, returns_created_atoms ? created_atoms : null)
for(var/turf/unlit as anything in turfs)
- if(unlit.always_lit)
+ if(unlit.space_lit)
continue
var/area/loc_area = unlit.loc
if(!loc_area.static_lighting)
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
index 2d89df51336..0d48bd11e62 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
@@ -59,6 +59,7 @@
icon_state = "solar_beam"
icon = 'icons/effects/beam.dmi'
plane = LIGHTING_PLANE
+ layer = LIGHTING_PRIMARY_LAYER
duration = 5
randomdir = FALSE
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index c34c53ce04b..f7325bcda80 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -51,10 +51,13 @@
SET_PLANE(panel_edge, PLANE_TO_TRUE(panel_edge.plane), new_turf)
SET_PLANE(panel, PLANE_TO_TRUE(panel.plane), new_turf)
+/obj/effect/overlay/solar_panel
+ vis_flags = VIS_INHERIT_ID | VIS_INHERIT_ICON
+ appearance_flags = TILE_BOUND
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
+
/obj/machinery/power/solar/proc/add_panel_overlay(icon_state, z_offset)
- var/obj/effect/overlay/overlay = new()
- overlay.vis_flags = VIS_INHERIT_ID | VIS_INHERIT_ICON
- overlay.appearance_flags = TILE_BOUND
+ var/obj/effect/overlay/solar_panel/overlay = new()
overlay.icon_state = icon_state
SET_PLANE_EXPLICIT(overlay, ABOVE_GAME_PLANE, src)
overlay.pixel_z = z_offset
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index 0421f5b4861..b58d1bc6f79 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -43,12 +43,15 @@
SET_PLANE(tracker_dish_edge, PLANE_TO_TRUE(tracker_dish_edge.plane), new_turf)
SET_PLANE(tracker_dish, PLANE_TO_TRUE(tracker_dish.plane), new_turf)
+/obj/effect/overlay/tracker
+ vis_flags = VIS_INHERIT_ID | VIS_INHERIT_ICON
+ appearance_flags = TILE_BOUND
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
+ layer = FLY_LAYER
+
/obj/machinery/power/tracker/proc/add_panel_overlay(icon_state, z_offset)
var/obj/effect/overlay/overlay = new()
- overlay.vis_flags = VIS_INHERIT_ID | VIS_INHERIT_ICON
- overlay.appearance_flags = TILE_BOUND
overlay.icon_state = icon_state
- overlay.layer = FLY_LAYER
SET_PLANE_EXPLICIT(overlay, ABOVE_GAME_PLANE, src)
overlay.pixel_z = z_offset
vis_contents += overlay
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index bc649ea23a0..3ff34a58610 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -39,7 +39,7 @@ All ShuttleMove procs go here
else //non-living mobs shouldn't be affected by shuttles, which is why this is an else
- if(istype(thing, /obj/singularity) || istype(thing, /obj/energy_ball))
+ if(istype(thing, /obj/effect/abstract) || istype(thing, /obj/singularity) || istype(thing, /obj/energy_ball))
continue
if(!thing.anchored)
step(thing, shuttle_dir)
diff --git a/code/modules/visuals/render_steps.dm b/code/modules/visuals/render_steps.dm
new file mode 100644
index 00000000000..239d8ba421f
--- /dev/null
+++ b/code/modules/visuals/render_steps.dm
@@ -0,0 +1,71 @@
+/**
+ * Internal atom that uses render relays to apply "appearance things" to a render source
+ * Branch, subtypes have behavior
+*/
+/atom/movable/render_step
+ name = "render step"
+ plane = DEFAULT_PLANE
+ layer = FLOAT_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ //Why?
+ //render_targets copy the transform of the target as well, but vis_contents also applies the transform
+ //we'll display using that, so we gotta reset
+ appearance_flags = KEEP_APART|KEEP_TOGETHER|RESET_TRANSFORM
+
+/atom/movable/render_step/Initialize(mapload, source)
+ . = ..()
+ verbs.Cut() //Cargo cultttttt
+ render_source = source
+
+/atom/movable/render_step/ex_act(severity)
+ return FALSE
+
+/atom/movable/render_step/singularity_act()
+ return
+
+/atom/movable/render_step/singularity_pull()
+ return
+
+/atom/movable/render_step/blob_act()
+ return
+
+//Prevents people from moving these after creation, because they shouldn't be.
+/atom/movable/render_step/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
+ if(harderforce)
+ return ..()
+
+/**
+ * Render step that modfies an atom's color
+ * Useful for creating coherent emissive blockers out of things like glass floors by lowering alpha statically using matrixes
+ * Other stuff too I'm sure
+ */
+/atom/movable/render_step/color
+ name = "color step"
+ //RESET_COLOR is obvious I hope
+ appearance_flags = KEEP_APART|KEEP_TOGETHER|RESET_COLOR|RESET_TRANSFORM
+
+/atom/movable/render_step/color/Initialize(mapload, source, color)
+ . = ..()
+ src.color = color
+
+/**
+ * Render step that makes the passed in render source block emissives
+ *
+ * Copies an appearance vis render_target and render_source on to the emissive blocking plane.
+ * This means that the atom in question will block any emissive sprites.
+ * This should only be used internally. If you are directly creating more of these, you're
+ * almost guaranteed to be doing something wrong.
+ */
+/**
+ * Render step that modfies an atom's color
+ * Useful for creating coherent emissive blockers out of things like glass floors by lowering alpha statically using matrixes
+ * Other stuff too I'm sure
+ */
+/atom/movable/render_step/emissive_blocker
+ name = "emissive blocker"
+ plane = EMISSIVE_PLANE
+ appearance_flags = EMISSIVE_APPEARANCE_FLAGS|RESET_TRANSFORM
+
+/atom/movable/render_step/emissive_blocker/Initialize(mapload, source)
+ . = ..()
+ src.color = GLOB.em_block_color
diff --git a/tgstation.dme b/tgstation.dme
index 0d90180660a..b9b6620c0c7 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3575,7 +3575,6 @@
#include "code\modules\library\skill_learning\job_skillchips\research_director.dm"
#include "code\modules\library\skill_learning\job_skillchips\roboticist.dm"
#include "code\modules\library\skill_learning\job_skillchips\station_engineer.dm"
-#include "code\modules\lighting\emissive_blocker.dm"
#include "code\modules\lighting\lighting_area.dm"
#include "code\modules\lighting\lighting_atom.dm"
#include "code\modules\lighting\lighting_corner.dm"
@@ -4927,6 +4926,7 @@
#include "code\modules\vending\toys.dm"
#include "code\modules\vending\wardrobes.dm"
#include "code\modules\vending\youtool.dm"
+#include "code\modules\visuals\render_steps.dm"
#include "code\modules\wiremod\components\abstract\compare.dm"
#include "code\modules\wiremod\components\abstract\equpiment_action.dm"
#include "code\modules\wiremod\components\abstract\list_variable.dm"