diff --git a/baystation12.dme b/baystation12.dme
index f8c41a625641e..5b8551a5f016b 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -20,6 +20,7 @@
#include "code\__datastructures\priority_queue.dm"
#include "code\__datastructures\stack.dm"
#include "code\__defines\__compile_options.dm"
+#include "code\__defines\__dview.dm"
#include "code\__defines\__initialization.dm"
#include "code\__defines\__renderer.dm"
#include "code\__defines\_excom.dm"
@@ -188,6 +189,7 @@
#include "code\controllers\subsystems\air.dm"
#include "code\controllers\subsystems\airflow.dm"
#include "code\controllers\subsystems\alarm.dm"
+#include "code\controllers\subsystems\ambient_lighting.dm"
#include "code\controllers\subsystems\ao.dm"
#include "code\controllers\subsystems\atoms.dm"
#include "code\controllers\subsystems\chat.dm"
@@ -1991,11 +1993,12 @@
#include "code\modules\library\manuals\medical.dm"
#include "code\modules\library\manuals\nanotrasen.dm"
#include "code\modules\library\manuals\union.dm"
+#include "code\modules\lighting\_lighting_defs.dm"
+#include "code\modules\lighting\darksight.dm"
#include "code\modules\lighting\lighting_area.dm"
#include "code\modules\lighting\lighting_atom.dm"
#include "code\modules\lighting\lighting_corner.dm"
#include "code\modules\lighting\lighting_overlay.dm"
-#include "code\modules\lighting\lighting_planemaster.dm"
#include "code\modules\lighting\lighting_setup.dm"
#include "code\modules\lighting\lighting_source.dm"
#include "code\modules\lighting\lighting_turf.dm"
@@ -2070,6 +2073,7 @@
#include "code\modules\mining\machinery\mineral_unloader.dm"
#include "code\modules\mob\animations.dm"
#include "code\modules\mob\death.dm"
+#include "code\modules\mob\dview.dm"
#include "code\modules\mob\examinations.dm"
#include "code\modules\mob\gender.dm"
#include "code\modules\mob\hear_say.dm"
diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm
index 8e6659624730f..edd52aa3fb13d 100644
--- a/code/__defines/MC.dm
+++ b/code/__defines/MC.dm
@@ -169,3 +169,9 @@ if(Datum.is_processing) {\
****/
#define addtimer(args...) _addtimer(args, source ="[__FILE__]#[__LINE__]")
+
+/****
+ * Helper for waits
+ ****/
+
+#define UNTIL(X) while(!(X)) stoplag()
diff --git a/code/__defines/__dview.dm b/code/__defines/__dview.dm
new file mode 100644
index 0000000000000..52553ef99784a
--- /dev/null
+++ b/code/__defines/__dview.dm
@@ -0,0 +1,14 @@
+//DVIEW defines
+
+#define FOR_DVIEW(type, range, center, invis_flags) \
+ global.dview_mob.loc = center; \
+ global.dview_mob.see_invisible = invis_flags; \
+ for(type in view(range, dview_mob))
+
+#define END_FOR_DVIEW dview_mob.loc = null
+
+#define DVIEW(output, range, center, invis_flags) \
+ global.dview_mob.loc = center; \
+ global.dview_mob.see_invisible = invis_flags; \
+ output = view(range, dview_mob); \
+ global.dview_mob.loc = null;
diff --git a/code/__defines/_renderer.dm b/code/__defines/_renderer.dm
index 90ff79719959c..c46d78b2060a0 100644
--- a/code/__defines/_renderer.dm
+++ b/code/__defines/_renderer.dm
@@ -190,13 +190,6 @@ GLOBAL_LIST_EMPTY(zmimic_renderers)
plane = LIGHTING_PLANE
appearance_flags = PLANE_MASTER | NO_CLIENT_COLOR
relay_blend_mode = BLEND_MULTIPLY
- color = list(
- -1, 0, 0, 0, // R
- 0, -1, 0, 0, // G
- 0, 0, -1, 0, // B
- 0, 0, 0, 0, // A
- 1, 1, 1, 1 // Mapping
- )
mouse_opacity = MOUSE_OPACITY_UNCLICKABLE
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index 5e35bad8636b1..8a5820f42579d 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -1,29 +1,42 @@
-#define FOR_DVIEW(type, range, center, invis_flags) \
- GLOB.dview_mob.loc = center; \
- GLOB.dview_mob.see_invisible = invis_flags; \
- for(type in view(range, GLOB.dview_mob))
+#define LIGHTING_INTERVAL 1 // Frequency, in 1/10ths of a second, of the lighting process.
-#define END_FOR_DVIEW GLOB.dview_mob.loc = null
+#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
+#define LIGHTING_Z_FACTOR 10 // Z diff is multiplied by this and LIGHTING_HEIGHT to get the final height of a light source. Affects how much darker A Z light gets with each level transitioned.
+#define LIGHTING_ROUND_VALUE (1 / 200) //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
-#define LIGHTING_ICON_STATE_DARK "dark" // Change between "soft_dark" and "dark" to swap soft darkvision
+#define LIGHTING_BASE_ICON_STATE "matrix" // icon_state used for normal color-matrix based lighting overlays.
+#define LIGHTING_STATION_ICON_STATE "tubedefault" // icon_state used for lighting overlays that are just displaying standard station lighting.
+#define LIGHTING_DARKNESS_ICON_STATE "black" // icon_state used for lighting overlays with no luminosity.
+#define LIGHTING_TRANSPARENT_ICON_STATE "blank"
-#define LIGHTING_ROUND_VALUE (1 / 64) // Value used to round lumcounts, values smaller than 1/69 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
+#define LIGHTING_BLOCKED_FACTOR 0.5 // How much the range of a directional light will be reduced while facing a wall.
-#define LIGHTING_SOFT_THRESHOLD 0 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. This also should be the transparancy of the "soft_dark" icon state.
+// If defined, instant updates will be used whenever server load permits. Otherwise queued updates are always used.
+#define USE_INTELLIGENT_LIGHTING_UPDATES
+
+/// Maximum light_range before forced to always queue instead of using sync updates. Setting this too high will cause server stutter with moving large lights.
+#define LIGHTING_MAXIMUM_INSTANT_RANGE 8
+
+// mostly identical to below, but doesn't make sure T is valid first. Should only be used by lighting code.
+#define TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) ((T:dynamic_lighting && T:loc:dynamic_lighting))
+#define TURF_IS_DYNAMICALLY_LIT(T) (isturf(T) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
+
+// Note: this does not imply the above, a turf can have ambient light without being dynamically lit.
+#define TURF_IS_AMBIENT_LIT_UNSAFE(T) (T:ambient_active)
+#define TURF_IS_AMBIENT_LIT(T) (isturf(T) && TURF_IS_AMBIENT_LIT_UNSAFE(T))
-#define LIGHTING_MULT_FACTOR 0.9
// If I were you I'd leave this alone.
#define LIGHTING_BASE_MATRIX \
- list \
- ( \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \
- 0, 0, 0, 1 \
- )
+ list \
+ ( \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 0, 0, 0, 1 \
+ ) \
// Helpers so we can (more easily) control the colour matrices.
#define CL_MATRIX_RR 1
@@ -47,12 +60,25 @@
#define CL_MATRIX_CB 19
#define CL_MATRIX_CA 20
+// Higher numbers override lower.
+#define LIGHTING_NO_UPDATE 0
+#define LIGHTING_VIS_UPDATE 1
+#define LIGHTING_CHECK_UPDATE 2
+#define LIGHTING_FORCE_UPDATE 3
+
// Lightbulb statuses
#define LIGHT_OK 0 // A light bulb is installed and functioning.
#define LIGHT_EMPTY 1 // There is no light bulb installed.
#define LIGHT_BROKEN 2 // The light bulb is broken/shattered.
#define LIGHT_BURNED 3 // The light bulb is burned out.
+// This color of overlay is very common - most of the station is this color when lit fully.
+// Tube lights are a bluish-white, so we can't just assume 1-1-1 is full-illumination.
+// -- If you want to change these, find them *by checking in-game*, just converting tubes' RGB color into floats will not work!
+#define LIGHTING_DEFAULT_TUBE_R 0.96
+#define LIGHTING_DEFAULT_TUBE_G 1
+#define LIGHTING_DEFAULT_TUBE_B 1
+
// Lighting color presets
#define LIGHT_COLOUR_WHITE "#fefefe" // Clinical white light bulbs
#define LIGHT_COLOUR_WARM "#fffee0" // Warm yellowish light bulbs
@@ -84,3 +110,16 @@
#define AREA_LIGHTING_WARM "warm"
#define AREA_LIGHTING_COOL "cool"
#define AREA_LIGHTING_DEFAULT "default" // For light replacers, defaults to whatever the area is set to. For areas, uses the initial lighting value from the light bulb itself.
+
+// Some angle presets for directional lighting.
+#define LIGHT_OMNI null
+#define LIGHT_SEMI 180
+#define LIGHT_VERY_WIDE 135
+#define LIGHT_WIDE 90
+#define LIGHT_NARROW 45
+
+#define DARKSIGHT_GRADIENT_SIZE 480
+// Max number of ambient groups, amount over this value will simply not be created
+#define AMBIENT_GROUP_MAX_BITS 24
+// Ambient group used for exterior turfs not on planets - Could also replace Space turf legacy starlight implementation
+#define SPACE_AMBIENT_GROUP 1
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 0d86253502bdd..c8da27040f9d9 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -338,3 +338,5 @@
#define SANITY_CHECK_TOPIC_PHYSICALLY_INTERACT FLAG(6)
#define SANITY_CHECK_DEFAULT (SANITY_CHECK_TOOL_IN_HAND | SANITY_CHECK_BOTH_ADJACENT)
+
+#define Z_ALL_TURFS(Z) block(locate(1, 1, Z), locate(world.maxx, world.maxy, Z))
diff --git a/code/__defines/species.dm b/code/__defines/species.dm
index 58dbcc6e359cf..31b74723209b8 100644
--- a/code/__defines/species.dm
+++ b/code/__defines/species.dm
@@ -42,7 +42,7 @@
#define SKIN_THREAT FLAG(0)
-// Darkvision Levels. Inverted - white is darkest, black is full vision
-#define DARKTINT_NONE "#ffffff"
-#define DARKTINT_MODERATE "#f9f9f5"
-#define DARKTINT_GOOD "#ebebe6"
+// Darkvision Levels. White is brightest, darker tints affect vision negatively
+#define DARKTINT_GOOD "#ffffff"
+#define DARKTINT_MODERATE "#f9f9f5"
+#define DARKTINT_NONE "#ebebe6"
diff --git a/code/__defines/subsystem-priority.dm b/code/__defines/subsystem-priority.dm
index 9e3e1e818a456..add0b6b88c821 100644
--- a/code/__defines/subsystem-priority.dm
+++ b/code/__defines/subsystem-priority.dm
@@ -20,6 +20,7 @@
#define SS_PRIORITY_AIR 80 // ZAS processing.
#define SS_PRIORITY_THROWING 75 // Throwing calculation and constant checks
#define SS_PRIORITY_CHEMISTRY 60 // Multi-tick chemical reactions.
+#define SS_PRIORITY_LIGHTING 50 // Queued lighting engine updates.
#define SS_PRIORITY_SPACEDRIFT 45 // Drifting things
#define SS_PRIORITY_CHAT 40 // Chat
#define SS_PRIORITY_ALARM 20 // Alarm processing.
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
index addaa201bbee6..3257785cc6fef 100644
--- a/code/__defines/subsystems.dm
+++ b/code/__defines/subsystems.dm
@@ -43,10 +43,11 @@
#define SS_INIT_SHUTTLE -5
#define SS_INIT_GOALS -5
#define SS_INIT_LIGHTING -6
-#define SS_INIT_ZCOPY -7
-#define SS_INIT_HOLOMAP -8
-#define SS_INIT_OVERLAYS -9
-#define SS_INIT_XENOARCH -10
+#define SS_INIT_AMBIENT_LIGHT -7
+#define SS_INIT_ZCOPY -8
+#define SS_INIT_HOLOMAP -9
+#define SS_INIT_OVERLAYS -10
+#define SS_INIT_XENOARCH -11
#define SS_INIT_BAY_LEGACY -12
#define SS_INIT_TICKER -20
#define SS_INIT_AI -21
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index 739ca2d00e8f8..fd8df21c08558 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -262,7 +262,8 @@
/proc/get_mobs_and_objs_in_view_fast(turf/T, range, list/mobs, list/objs, checkghosts = null)
- var/list/hear = dview(range,T,INVISIBILITY_MAXIMUM)
+ var/list/hear = list()
+ DVIEW(hear, range, T, INVISIBILITY_MAXIMUM)
var/list/hearturfs = list()
for(var/atom/movable/AM in hear)
diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm
index 9b2fb78d22b49..7b539933c0584 100644
--- a/code/_helpers/time.dm
+++ b/code/_helpers/time.dm
@@ -207,3 +207,19 @@ var/global/round_start_time = 0
var/time_string = time2text(world.realtime, "MM-DD")
var/time_list = splittext(time_string, "-")
return list(text2num(time_list[1]), text2num(time_list[2]))
+
+
+#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
+
+var/global/midnight_rollovers = 0
+var/global/rollovercheck_last_timeofday = 0
+/proc/update_midnight_rollover()
+ if (world.timeofday < global.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
+ global.midnight_rollovers += 1
+ global.rollovercheck_last_timeofday = world.timeofday
+ return global.midnight_rollovers
+
+//time of day but automatically adjusts to the server going into the next day within the same round.
+//for when you need a reliable time number that doesn't depend on byond time.
+#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
+#define MIDNIGHT_ROLLOVER_CHECK ( global.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : global.midnight_rollovers )
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index a642fae1cf57d..7a19e3db3d74d 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -1036,17 +1036,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
. = view(range, GLOB.dview_mob)
GLOB.dview_mob.loc = null
-/mob/dview
- invisibility = INVISIBILITY_ABSTRACT
- density = FALSE
-
- anchored = TRUE
- simulated = FALSE
-
- see_in_dark = 1e6
-
- virtual_mob = null
-
/mob/dview/Destroy()
SHOULD_CALL_PARENT(FALSE)
return QDEL_HINT_LETMELIVE
@@ -1062,7 +1051,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/atom/proc/get_light_and_color(atom/origin)
if(origin)
color = origin.color
- set_light(origin.light_max_bright, origin.light_inner_range, origin.light_outer_range, origin.light_falloff_curve)
+ set_light(origin.light_range, origin.light_power)
// call to generate a stack trace and print to runtime logs
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 3100d3345740b..e11f37874629f 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -335,8 +335,8 @@
var/static/aooc_allowed = TRUE
- /// Whether space turfs have ambient light or not
- var/static/starlight = 0
+ /// Whether space turfs and some exterior turfs have ambient light or not default, 0.5, values over 1 may overpower dynamic lights
+ var/static/starlight = 0.5
var/static/list/ert_species = list(SPECIES_HUMAN)
diff --git a/code/controllers/subsystems/ambient_lighting.dm b/code/controllers/subsystems/ambient_lighting.dm
new file mode 100644
index 0000000000000..a234899708402
--- /dev/null
+++ b/code/controllers/subsystems/ambient_lighting.dm
@@ -0,0 +1,244 @@
+SUBSYSTEM_DEF(ambient_lighting) //A simple SS that handles updating ambient lights of away sites and such places
+ name = "Ambient Lighting"
+ wait = 1
+ priority = SS_PRIORITY_LIGHTING
+ init_order = SS_INIT_AMBIENT_LIGHT
+ runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
+
+ /// List of turfs queued for ambient light evaluation
+ var/list/queued = list()
+
+ /// A bitmap of free ambience group indexes.
+ var/ambient_group_free_bitmap = ~0
+ /// map of ambiient groups
+ var/list/ambient_groups[AMBIENT_GROUP_MAX_BITS]
+
+/datum/ambient_group
+ /// Index in SSambient_lighting map
+ var/global_index
+ var/list/member_turfs_by_z = list()
+ /// Color data, do NOT modify manually
+ var/apparent_r
+ var/apparent_g
+ var/apparent_b
+ /// Prevent modification of member turfs or colour while an operation is taking place
+ var/busy = FALSE
+
+/datum/ambient_group/New(ncolor, nmultiplier, nindex)
+ . = ..()
+ set_color(ncolor, nmultiplier)
+ global_index = nindex
+
+/datum/ambient_group/Destroy()
+ SSambient_lighting.ambient_groups[global_index] = null
+ SSambient_lighting.ambient_group_free_bitmap |= FLAG(global_index)
+ return ..()
+
+/datum/ambient_group/proc/set_color(color, multiplier)
+ var/list/new_parts = rgb2num(color)
+ //Calculate delta from current to desired location
+ var/dr = (new_parts[1] / 255) * multiplier - apparent_r
+ var/dg = (new_parts[2] / 255) * multiplier - apparent_g
+ var/db = (new_parts[3] / 255) * multiplier - apparent_b
+
+ if (round(dr/4, LIGHTING_ROUND_VALUE) == 0 && round(dg/4, LIGHTING_ROUND_VALUE) == 0 && round(db/4, LIGHTING_ROUND_VALUE) == 0)
+ // no-op
+ return
+
+ busy = TRUE
+
+ // Doing it ordered by zlev should ensure that it looks vaguely coherent mid-update regardless of turf insertion order.
+ for (var/zlev in 1 to length(member_turfs_by_z))
+ for (var/turf/T as anything in member_turfs_by_z[zlev])
+ T.add_ambient_light_raw(dr, dg, db)
+ CHECK_TICK
+
+ apparent_r += dr
+ apparent_g += dg
+ apparent_b += db
+
+ busy = FALSE
+
+/**
+ * Adds group ambient light to a turf
+ *
+ * **Parameters**:
+ * - `T` turf - Turf to modify
+ *
+ */
+/datum/ambient_group/proc/set_ambient_light(turf/T)
+ set waitfor = FALSE
+
+ UNTIL(!busy)
+ T.add_ambient_light_raw(apparent_r, apparent_g, apparent_b)
+
+/**
+ * Removes group ambient light from turf
+ *
+ * **Parameters**:
+ * - `T` turf - Turf to modify
+ *
+ */
+/datum/ambient_group/proc/remove_ambient_light(turf/T)
+ set waitfor = FALSE
+
+ UNTIL(!busy)
+ T.add_ambient_light_raw(-apparent_r, -apparent_g, -apparent_b)
+
+/**
+ * Adds turf to ambient group, will set bitflags and set current ambient light
+ *
+ * **Parameters**:
+ * - `T` turf - Turf to add and track
+ *
+ */
+/datum/ambient_group/proc/add_turf(turf/T)
+ set waitfor = FALSE
+
+ UNTIL(!busy)
+ //Already existing
+ if(T.ambient_bitflag & FLAG(global_index))
+ return
+
+ if (T.z > length(member_turfs_by_z))
+ member_turfs_by_z.len = T.z
+
+ LAZYADD(member_turfs_by_z[T.z], T)
+ T.ambient_bitflag |= FLAG(global_index)
+ set_ambient_light(T)
+
+/**
+ * Removes turf from ambient group if it is part of it. Removes group's ambient light and flag from turf
+ *
+ * **Parameters**:
+ * - `T` turf - Turf to remove
+ *
+ */
+/datum/ambient_group/proc/remove_turf(turf/T)
+ set waitfor = FALSE
+
+ UNTIL(!busy)
+ if(!(T.ambient_bitflag & FLAG(global_index)))
+ return
+
+ if (T.z > length(member_turfs_by_z))
+ CRASH("Attempt to remove member turf with Z greater than local max -- this turf is not a member")
+
+ remove_ambient_light(T)
+ T.ambient_bitflag &= ~FLAG(global_index)
+ member_turfs_by_z[T.z] -= T
+
+/**
+ * Find a valid index in the ambient group map for a new group
+ *
+ * Returns index or -1 if no indices are left
+ */
+/datum/controller/subsystem/ambient_lighting/proc/allocate_index()
+ if (ambient_group_free_bitmap == 0)
+ return -1 //Out of indices, no ambient light for you
+
+ // Find the first free index in the bitmap.
+ var/index = 1
+ while (!(ambient_group_free_bitmap & FLAG(index)) && index < AMBIENT_GROUP_MAX_BITS)
+ index += 1
+
+ ambient_group_free_bitmap &= ~FLAG(index)
+
+ return index
+/**
+ * Adds the space ambient group if it doesn't currently exist
+ *
+ */
+/datum/controller/subsystem/ambient_lighting/proc/add_space_ambient_group()
+ var/index = allocate_index() //It will always be 1, but we want to make sure bitmap is in a valid state
+
+ ASSERT(index == SPACE_AMBIENT_GROUP)
+
+ ambient_groups[index] = new /datum/ambient_group(SSskybox.background_color, config.starlight, index )
+
+/**
+ * Removes turf from ambient group if it is part of it. Removes group's ambient light and flag from turf
+ *
+ * **Parameters**:
+ * - `color` color - Initial color
+ * - `multiplier` float - Initial multiplier of light strength
+ *
+ * Returns index or -1 if no indices are left
+ */
+/datum/controller/subsystem/ambient_lighting/proc/create_ambient_group(color, multiplier)
+
+ if(ambient_groups[SPACE_AMBIENT_GROUP] == null) //Something (probably a planet) wants to add an ambient group, add space first
+ add_space_ambient_group()
+
+ // Find the first free index in the bitmap.
+ var/index = allocate_index()
+
+ if(index <= 0)
+ return index
+
+ ambient_groups[index] = new /datum/ambient_group(color, multiplier, index)
+
+ return index
+
+/**
+ * Removes turf from all ambient groups it is part of (if any)
+ *
+ * **Parameters**:
+ * - `target` turf - Turf to remove
+ */
+/datum/controller/subsystem/ambient_lighting/proc/clean_turf(turf/target)
+ if(target.ambient_bitflag != 0)
+ for(var/datum/ambient_group/A in ambient_groups)
+ if(target.ambient_bitflag & FLAG(A.global_index))
+ A.remove_turf(target)
+ if(!target.ambient_bitflag)
+ return //Return early if flag is already clear
+
+/datum/controller/subsystem/ambient_lighting/Initialize(start_timeofday)
+ //Create space ambient group if nothing created it until now.
+ if(ambient_groups[SPACE_AMBIENT_GROUP] == null)
+ add_space_ambient_group()
+
+ fire(FALSE, TRUE)
+ return ..()
+
+/// Go over turfs in queue, add them to space or planet ambient groups if valid, else remove them from all ambient groups
+/datum/controller/subsystem/ambient_lighting/fire(resumed = FALSE, no_mc_tick = FALSE)
+ var/list/curr = queued
+ var/starlight_enabled = config.starlight
+
+ var/needs_ambience
+ while (length(curr))
+ var/turf/target = curr[length(curr)]
+ LIST_DEC(curr)
+
+ if(target && target.is_outside())
+ needs_ambience = TURF_IS_DYNAMICALLY_LIT_UNSAFE(target)
+ if (!needs_ambience)
+ for (var/turf/T in RANGE_TURFS(target, 1))
+ if(TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
+ needs_ambience = TRUE
+ break
+
+ if (needs_ambience)
+ var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[target.z]"]
+ if (istype(E))
+ if(E.ambient_group_index > 0)
+ var/datum/ambient_group/A = ambient_groups[E.ambient_group_index]
+ A.add_turf(target)
+ else
+ if (starlight_enabled) //Assume we can light up exterior with space light generally
+ var/datum/ambient_group/A = ambient_groups[SPACE_AMBIENT_GROUP]
+ A.add_turf(target)
+ else if (TURF_IS_AMBIENT_LIT_UNSAFE(target))
+ //Remove from all groups
+ if(target.ambient_bitflag != 0)
+ for(var/datum/ambient_group/A in ambient_groups)
+ A.remove_turf(target)
+ if(!target.ambient_bitflag)
+ break
+
+ if (no_mc_tick)
+ CHECK_TICK
+ else if (MC_TICK_CHECK)
+ return
diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm
index 775bb83b47ba5..971adfeac50b7 100644
--- a/code/controllers/subsystems/lighting.dm
+++ b/code/controllers/subsystems/lighting.dm
@@ -1,112 +1,140 @@
-var/global/lighting_overlays_initialised = FALSE
-
SUBSYSTEM_DEF(lighting)
name = "Lighting"
- wait = 1
+ wait = LIGHTING_INTERVAL
+ priority = SS_PRIORITY_LIGHTING
init_order = SS_INIT_LIGHTING
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
- // Queues of update counts, waiting to be rolled into stats lists
- var/list/stats_queues = list(
- "Source" = list(),
- "Corner" = list(),
- "Overlay" = list()
- )
- // Stats lists
- var/list/stats_lists = list(
- "Source" = list(),
- "Corner" = list(),
- "Overlay" = list()
- )
- var/update_stats_every = 1 SECOND
- var/next_stats_update = 0
- var/stat_updates_to_keep = 5
+ var/total_lighting_overlays = 0
+ var/total_lighting_sources = 0
+ var/total_ambient_turfs = 0
+ var/total_lighting_corners = 0
- var/list/light_queue = list() // lighting sources queued for update.
+ /// lighting sources queued for update.
+ var/list/light_queue = list()
var/lq_idex = 1
- var/list/corner_queue = list() // lighting corners queued for update.
+ /// lighting corners queued for update.
+ var/list/corner_queue = list()
var/cq_idex = 1
- var/list/overlay_queue = list() // lighting overlays queued for update.
+ /// lighting overlays queued for update.
+ var/list/overlay_queue = list()
var/oq_idex = 1
+ // - Performance and analytics data
var/processed_lights = 0
var/processed_corners = 0
var/processed_overlays = 0
+ var/total_ss_updates = 0
+ var/total_instant_updates = 0
+
+#ifdef USE_INTELLIGENT_LIGHTING_UPDATES
+ var/force_queued = TRUE
+ var/force_override = FALSE // For admins.
+#endif
+
/datum/controller/subsystem/lighting/UpdateStat(time)
- if (PreventUpdateStat(time))
- return ..()
- ..({"\
- Queues: \
- Source [length(light_queue)] \
- Corner [length(corner_queue)] \
- Overlay [length(overlay_queue)]\n\
- Source Updates [length(stats_lists["Source"])]\n\
- Corner Updates [length(stats_lists["Corner"])]\n\
- Overlay Updates [length(stats_lists["Overlay"])]\
- "})
-
-
-/datum/controller/subsystem/lighting/Initialize(start_uptime)
- InitializeTurfs()
- lighting_overlays_initialised = TRUE
+ var/list/out = list(
+#ifdef USE_INTELLIGENT_LIGHTING_UPDATES
+ "IUR: [total_ss_updates ? round(total_instant_updates/(total_instant_updates+total_ss_updates)*100, 0.1) : "NaN"]%\n",
+#endif
+ "\tT:{L:[total_lighting_sources] C:[total_lighting_corners] O:[total_lighting_overlays] A:[total_ambient_turfs]}\n",
+ "\tP:{L:[length(light_queue) - (lq_idex - 1)]|C:[length(corner_queue) - (cq_idex - 1)]|O:[length(overlay_queue) - (oq_idex - 1)]}\n",
+ "\tL:{L:[processed_lights]|C:[processed_corners]|O:[processed_overlays]}\n"
+ )
+ ..(out.Join())
+
+#ifdef USE_INTELLIGENT_LIGHTING_UPDATES
+
+/hook/roundstart/proc/lighting_init_roundstart()
+ SSlighting.handle_roundstart()
+ return TRUE
+
+/datum/controller/subsystem/lighting/proc/handle_roundstart()
+ force_queued = FALSE
+ total_ss_updates = 0
+ total_instant_updates = 0
+
+#endif
+/// Generate overlays for all Zlevels and then fire normally
+/datum/controller/subsystem/lighting/Initialize(timeofday)
+ var/overlaycount = 0
+ var/starttime = REALTIMEOFDAY
+
+ // Generate overlays.
+ for (var/zlevel = 1 to world.maxz)
+ overlaycount += InitializeZlev(zlevel)
+
+ admin_notice(SPAN_DANGER("Created [overlaycount] lighting overlays in [(REALTIMEOFDAY - starttime)/10] seconds."), R_DEBUG)
+
+ starttime = REALTIMEOFDAY
+ // Tick once to clear most lights.
fire(FALSE, TRUE)
+ admin_notice(SPAN_DANGER("Processed [processed_lights] light sources."), R_DEBUG)
+ admin_notice(SPAN_DANGER("Processed [processed_corners] light corners."), R_DEBUG)
+ admin_notice(SPAN_DANGER("Processed [processed_overlays] light overlays."), R_DEBUG)
+ admin_notice(SPAN_DANGER("Lighting pre-bake completed in [(REALTIMEOFDAY - starttime)/10] seconds."), R_DEBUG)
+
+ log_ss("lighting", "NOv:[overlaycount] L:[processed_lights] C:[processed_corners] O:[processed_overlays]")
+
+ ..()
+
+/**
+ * Go over turfs thay may be dynamically lit and add a lighting overlay if they don't have one. Then do the same for turfs that may be ambient lit.
+ *
+ * **Parameters**:
+ * - `zlev` int - z-level index
+ */
+/datum/controller/subsystem/lighting/proc/InitializeZlev(zlev)
+ for (var/thing in Z_ALL_TURFS(zlev))
+ var/turf/T = thing
+ if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) && !T.lighting_overlay) // Can't assume that one hasn't already been created on bay/neb.
+ new /atom/movable/lighting_overlay(T)
+ . += 1
+ if(TURF_IS_AMBIENT_LIT_UNSAFE(T))
+ T.generate_missing_corners() // Forcibly generate corners.
-// It's safe to pass a list of non-turfs to this list - it'll only check turfs.
+ CHECK_TICK
+
+/// Initialize a set of turfs (for example as part of loading a map template) It's safe to pass a list of non-turfs to this list - it'll only check turfs.
/datum/controller/subsystem/lighting/proc/InitializeTurfs(list/targets)
for (var/turf/T in (targets || world))
- if (T.dynamic_lighting && T.loc:dynamic_lighting)
+ if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
T.lighting_build_overlay()
// If this isn't here, BYOND will set-background us.
CHECK_TICK
+/**
+ * Go over light queue and update corners as needed
+ * Go over light corner queue and update overlays as needed
+ * Go over overlay queue and update as needed
+ */
/datum/controller/subsystem/lighting/fire(resumed = FALSE, no_mc_tick = FALSE)
if (!resumed)
- stats_queues["Source"] += processed_lights
- stats_queues["Corner"] += processed_corners
- stats_queues["Overlay"] += processed_overlays
-
processed_lights = 0
processed_corners = 0
processed_overlays = 0
- if(next_stats_update <= world.time)
- next_stats_update = world.time + update_stats_every
- for(var/stat_name in stats_queues)
- var/stat_sum = 0
- var/list/stats_queue = stats_queues[stat_name]
- for(var/count in stats_queue)
- stat_sum += count
- stats_queue.Cut()
-
- var/list/stats_list = stats_lists[stat_name]
- stats_list.Insert(1, stat_sum)
- if(length(stats_list) > stat_updates_to_keep)
- stats_list.Cut(length(stats_list))
-
MC_SPLIT_TICK_INIT(3)
if (!no_mc_tick)
MC_SPLIT_TICK
- // Sources.
- while (lq_idex <= length(light_queue))
- var/datum/light_source/L = light_queue[lq_idex]
- lq_idex += 1
+ var/list/curr_lights = light_queue
+ var/list/curr_corners = corner_queue
+ var/list/curr_overlays = overlay_queue
- if(L.check() || L.destroyed || L.force_update)
- L.remove_lum()
- if(!L.destroyed)
- L.apply_lum()
+ while (lq_idex <= length(curr_lights))
+ var/datum/light_source/L = curr_lights[lq_idex++]
- else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
- L.smart_vis_update()
+ if (L.needs_update != LIGHTING_NO_UPDATE)
+ total_ss_updates += 1
+ L.update_corners()
- L.vis_update = FALSE
- L.force_update = FALSE
- L.needs_update = FALSE
+ L.needs_update = LIGHTING_NO_UPDATE
- processed_lights += 1
+ processed_lights++
if (no_mc_tick)
CHECK_TICK
@@ -114,22 +142,21 @@ SUBSYSTEM_DEF(lighting)
break
if (lq_idex > 1)
- light_queue.Cut(1, lq_idex)
+ curr_lights.Cut(1, lq_idex)
lq_idex = 1
if (!no_mc_tick)
MC_SPLIT_TICK
- // Corners.
- while (cq_idex <= length(corner_queue))
- var/datum/lighting_corner/C = corner_queue[cq_idex]
- cq_idex += 1
+ while (cq_idex <= length(curr_corners))
+ var/datum/lighting_corner/C = curr_corners[cq_idex++]
- C.update_overlays()
+ if (C.needs_update)
+ C.update_overlays()
- C.needs_update = FALSE
+ C.needs_update = FALSE
- processed_corners += 1
+ processed_corners++
if (no_mc_tick)
CHECK_TICK
@@ -137,27 +164,51 @@ SUBSYSTEM_DEF(lighting)
break
if (cq_idex > 1)
- corner_queue.Cut(1, cq_idex)
+ curr_corners.Cut(1, cq_idex)
cq_idex = 1
if (!no_mc_tick)
MC_SPLIT_TICK
- // Objects.
- while (oq_idex <= length(overlay_queue))
- var/atom/movable/lighting_overlay/O = overlay_queue[oq_idex]
- oq_idex += 1
+ while (oq_idex <= length(curr_overlays))
+ var/atom/movable/lighting_overlay/O = curr_overlays[oq_idex++]
- O.update_overlay()
- O.needs_update = 0
+ if (!QDELETED(O) && O.needs_update)
+ O.update_overlay()
+ O.needs_update = FALSE
- processed_overlays += 1
+ processed_overlays++
if (no_mc_tick)
CHECK_TICK
else if (MC_TICK_CHECK)
break
+ if (oq_idex > 1)
+ curr_overlays.Cut(1, oq_idex)
+ oq_idex = 1
+
+/datum/controller/subsystem/lighting/Recover()
+ total_lighting_corners = SSlighting.total_lighting_corners
+ total_lighting_overlays = SSlighting.total_lighting_overlays
+ total_lighting_sources = SSlighting.total_lighting_sources
+
+ light_queue = SSlighting.light_queue
+ corner_queue = SSlighting.corner_queue
+ overlay_queue = SSlighting.overlay_queue
+
+ lq_idex = SSlighting.lq_idex
+ cq_idex = SSlighting.cq_idex
+ oq_idex = SSlighting.oq_idex
+
+ if (lq_idex > 1)
+ light_queue.Cut(1, lq_idex)
+ lq_idex = 1
+
+ if (cq_idex > 1)
+ corner_queue.Cut(1, cq_idex)
+ cq_idex = 1
+
if (oq_idex > 1)
overlay_queue.Cut(1, oq_idex)
oq_idex = 1
diff --git a/code/controllers/subsystems/mobs.dm b/code/controllers/subsystems/mobs.dm
index 42fd7330a381a..7c6378b83a61e 100644
--- a/code/controllers/subsystems/mobs.dm
+++ b/code/controllers/subsystems/mobs.dm
@@ -61,8 +61,3 @@ if(MOB.is_processing == SSmobs) {\
else if (MOB.is_processing) {\
crash_with("Failed to stop processing mob. Being processed by [MOB.is_processing] instead.")\
}
-
-
-/mob/dview/Initialize()
- . = ..()
- STOP_PROCESSING_MOB(src)
diff --git a/code/controllers/subsystems/zcopy.dm b/code/controllers/subsystems/zcopy.dm
index 6c8bc6a8fe523..a5f21140f0832 100644
--- a/code/controllers/subsystems/zcopy.dm
+++ b/code/controllers/subsystems/zcopy.dm
@@ -1,5 +1,6 @@
-#define SHADOWER_DARKENING_FACTOR 0.6 // The multiplication factor for openturf shadower darkness. Lighting will be multiplied by this.
-#define SHADOWER_DARKENING_COLOR "#999999" // The above, but as an RGB string for lighting-less turfs.
+#define SHADOWER_DARKENING_FACTOR 0.8 // The multiplication factor for openturf shadower darkness. Lighting will be multiplied by this.
+#define SHADOWER_DARKENING_COLOR "#00000033" // The above, but as an RGB string for lighting-less turfs.
+//Bay can't do multiplicative lighting for zmimic currently so we change alpha, this does mean full lit turfs need a different colour. TODO: Take another look at zmimic render setup
SUBSYSTEM_DEF(zcopy)
name = "Z-Copy"
@@ -181,6 +182,9 @@ SUBSYSTEM_DEF(zcopy)
T.z_generation += 1
T.z_queued -= 1
+ if (T.above)
+ T.above.update_mimic()
+
if (no_mc_tick)
CHECK_TICK
else if (MC_TICK_CHECK)
@@ -268,7 +272,7 @@ SUBSYSTEM_DEF(zcopy)
var/atom/movable/openspace/turf_mimic/DC = T.below.mimic_above_copy
DC.appearance = T.below
DC.mouse_opacity = initial(DC.mouse_opacity)
- DC.plane = OPENTURF_MAX_PLANE
+ DC.plane = OPENTURF_MAX_PLANE - turf_depth - 1
else if (T.below.mimic_above_copy)
QDEL_NULL(T.below.mimic_above_copy)
@@ -284,7 +288,7 @@ SUBSYSTEM_DEF(zcopy)
// Special case: these are merged into the shadower to reduce memory usage.
if (object.type == /atom/movable/lighting_overlay)
- //T.shadower.copy_lighting(object)
+ T.shadower.copy_lighting(object)
continue
if (!object.bound_overlay) // Generate a new overlay if the atom doesn't already have one.
@@ -297,6 +301,7 @@ SUBSYSTEM_DEF(zcopy)
var/have_performed_fixup = FALSE
switch (object.type)
+ // Layering for recursive mimic needs to be inherited.
if (/atom/movable/openspace/mimic)
var/atom/movable/openspace/mimic/OOO = object
original_type = OOO.mimiced_type
diff --git a/code/datums/observation/sight_set.dm b/code/datums/observation/sight_set.dm
index 664ad33b88c80..c2db96c382d3c 100644
--- a/code/datums/observation/sight_set.dm
+++ b/code/datums/observation/sight_set.dm
@@ -18,8 +18,14 @@ GLOBAL_DATUM_INIT(sight_set_event, /singleton/observ/sight_set, new)
* Sight Set Handling *
*********************/
+/mob/var/see_black = FALSE
+
/mob/proc/set_sight(new_sight)
var/old_sight = sight
+ if(see_black)
+ new_sight |= SEE_BLACKNESS // Avoids pixel bleed from atoms overlapping completely dark turfs, but conflicts with other flags.
+ else
+ new_sight &= ~SEE_BLACKNESS
if(old_sight != new_sight)
sight = new_sight
GLOB.sight_set_event.raise_event(src, old_sight, new_sight)
diff --git a/code/datums/proximity_trigger/proximity_trigger.dm b/code/datums/proximity_trigger/proximity_trigger.dm
index af67ffe616097..a4ffa41bbf795 100644
--- a/code/datums/proximity_trigger/proximity_trigger.dm
+++ b/code/datums/proximity_trigger/proximity_trigger.dm
@@ -140,9 +140,10 @@ var/global/const/PROXIMITY_EXCLUDE_HOLDER_TURF = 1 // When acquiring turfs to mo
if(!center)
return
- for(var/T in dview(range_, center))
- if(T in turfs_in_range)
+ FOR_DVIEW(var/T, range_, center, 0)
+ if (T in turfs_in_range) // This is awful, but I don't want to refactor this to be assoc.
. += T
+ END_FOR_DVIEW
/datum/proximity_trigger/proc/acquire_relevant_turfs()
. = turf_selection.get_turfs(holder, range_)
diff --git a/code/datums/security_state.dm b/code/datums/security_state.dm
index 08669a6280070..65e5bc8ddc909 100644
--- a/code/datums/security_state.dm
+++ b/code/datums/security_state.dm
@@ -141,9 +141,8 @@
var/alarm_level = "off"
// These values are primarily for station alarms and status displays, and which light colors and overlays to use
- var/light_max_bright = 0.5
- var/light_inner_range = 0.1
- var/light_outer_range = 1
+ var/light_range
+ var/light_power
var/light_color_alarm
var/light_color_status_display
@@ -205,9 +204,8 @@
/singleton/security_level/default/code_green
name = "code green"
- light_max_bright = 0.25
- light_inner_range = 0.1
- light_outer_range = 1
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_GREEN
light_color_status_display = COLOR_GREEN
@@ -222,9 +220,8 @@
name = "code blue"
alarm_level = "on"
- light_max_bright = 0.5
- light_inner_range = 0.1
- light_outer_range = 2
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_BLUE
light_color_status_display = COLOR_BLUE
@@ -241,9 +238,8 @@
name = "code red"
alarm_level = "on"
- light_max_bright = 0.5
- light_inner_range = 0.1
- light_outer_range = 2
+ light_range = 4
+ light_power = 2
light_color_alarm = COLOR_RED
light_color_status_display = COLOR_RED
@@ -260,9 +256,8 @@
name = "code delta"
alarm_level = "on"
- light_max_bright = 0.75
- light_inner_range = 0.1
- light_outer_range = 3
+ light_range = 4
+ light_power = 2
light_color_alarm = COLOR_RED
light_color_status_display = COLOR_NAVY_BLUE
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5968e31fa6adc..12e0b991923bf 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -83,14 +83,14 @@
log_debug("Abstract atom [type] created!")
return INITIALIZE_HINT_QDEL
- if(light_max_bright && light_outer_range)
+ if(light_power && light_range)
update_light()
if(opacity)
updateVisibility(src)
var/turf/T = loc
if(istype(T))
- T.RecalculateOpacity()
+ T.recalc_atom_opacity()
if (health_max)
health_current = health_max
@@ -114,6 +114,7 @@
/atom/Destroy()
QDEL_NULL(reagents)
+ QDEL_NULL(light)
. = ..()
/**
@@ -422,6 +423,18 @@
return FALSE
dir = new_dir
GLOB.dir_set_event.raise_event(src, old_dir, dir)
+
+ //Lighting
+ if(light_source_solo)
+ if(light_source_solo.light_angle)
+ light_source_solo.source_atom.update_light()
+ else if(light_source_multi)
+ var/datum/light_source/L
+ for(var/thing in light_source_multi)
+ L = thing
+ if(L.light_angle)
+ L.source_atom.update_light()
+
return TRUE
/**
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 86cf810c8b69c..29c70a42c096c 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -217,8 +217,13 @@
updateVisibility(src)
// lighting
- if (light_sources) // Yes, I know you can for-null safely, but this is slightly faster. Hell knows why.
- for (var/datum/light_source/L in light_sources)
+ if (light_source_solo)
+ light_source_solo.source_atom.update_light()
+ else if (light_source_multi)
+ var/datum/light_source/L
+ var/thing
+ for (thing in light_source_multi)
+ L = thing
L.source_atom.update_light()
/atom/movable/Move(...)
@@ -233,8 +238,13 @@
updateVisibility(src)
// lighting
- if (light_sources) // Yes, I know you can for-null safely, this is slightly faster. Hell knows why.
- for (var/datum/light_source/L in light_sources)
+ if (light_source_solo)
+ light_source_solo.source_atom.update_light()
+ else if (light_source_multi)
+ var/datum/light_source/L
+ var/thing
+ for (thing in light_source_multi)
+ L = thing
L.source_atom.update_light()
//called when src is thrown into hit_atom
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 360a6bcd78296..cc96c3f22d01c 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -19,9 +19,8 @@
desc = "A floating crystal that hums with an unearthly energy."
icon = 'icons/obj/structures/pylon.dmi'
icon_state = "pylon"
- light_max_bright = 0.5
- light_inner_range = 1
- light_outer_range = 13
+ light_power = 0.5
+ light_range = 13
light_color = "#3e0000"
health_max = 20
health_min_damage = 4
@@ -73,7 +72,7 @@
var/spawnable = null
/obj/effect/gateway/active
- light_outer_range=5
+ light_range=5
light_color="#ff0000"
spawnable=list(
/mob/living/simple_animal/hostile/scarybat,
@@ -82,7 +81,6 @@
)
/obj/effect/gateway/active/cult
- light_outer_range=5
light_color="#ff0000"
spawnable=list(
/mob/living/simple_animal/hostile/scarybat/cult,
diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm
index 9a84d4566df41..fa2bfb1c41fe7 100644
--- a/code/game/gamemodes/cult/narsie.dm
+++ b/code/game/gamemodes/cult/narsie.dm
@@ -32,7 +32,7 @@ var/global/list/narsie_list = list()
// Pixel stuff centers Narsie.
pixel_x = -236
pixel_y = -256
- light_outer_range = 1
+ light_range = 1
light_color = "#3e0000"
current_size = 6
@@ -154,7 +154,7 @@ var/global/list/narsie_list = list()
T.icon_state = "cult-narsie"
T.set_opacity(0)
T.set_density(0)
- set_light(1)
+ set_light(1, 1)
/obj/singularity/narsie/large/consume(atom/A) //Has its own consume proc because it doesn't need energy and I don't want BoHs to explode it. --NEO
//NEW BEHAVIOUR
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index b5bd691adfb74..3d0589477743e 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -370,7 +370,7 @@
else if(dir == EAST)
pixel_x = -21
- set_light(0.25, 0.1, 1, 2, new_color)
+ set_light(2, 0.25, new_color)
/obj/machinery/alarm/receive_signal(datum/signal/signal)
if(!signal || signal.encryption)
@@ -964,12 +964,12 @@ FIRE ALARM
else
if(!detecting)
AddOverlays(get_cached_overlay("fire1"))
- set_light(0.25, 0.1, 1, 2, COLOR_RED)
+ set_light(2, 0.25, COLOR_RED)
else if(z in GLOB.using_map.contact_levels)
var/singleton/security_state/security_state = GET_SINGLETON(GLOB.using_map.security_state)
var/singleton/security_level/sl = security_state.current_security_level
- set_light(sl.light_max_bright, sl.light_inner_range, sl.light_outer_range, 2, sl.light_color_alarm)
+ set_light(sl.light_power, sl.light_range, sl.light_color_alarm)
AddOverlays(image(sl.icon, sl.overlay_alarm))
else
AddOverlays(get_cached_overlay("fire0"))
diff --git a/code/game/machinery/bluespace_drive.dm b/code/game/machinery/bluespace_drive.dm
index 1e84f0d607d94..c95f810717ead 100644
--- a/code/game/machinery/bluespace_drive.dm
+++ b/code/game/machinery/bluespace_drive.dm
@@ -38,7 +38,7 @@
. = ..()
drive_sound = GLOB.sound_player.PlayLoopingSound(src, "\ref[src]", 'sound/machines/BSD_idle.ogg', 50, 7)
AddParticles(/particles/torus/bluespace)
- set_light(1, 5, 15, 10, COLOR_CYAN)
+ set_light(15, 1, COLOR_CYAN)
update_icon()
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index f3251db715e88..6ac304b64da2c 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -17,9 +17,8 @@
var/icon_keyboard = "generic_key"
var/icon_screen = "generic"
- var/light_max_bright_on = 0.2
- var/light_inner_range_on = 0.1
- var/light_outer_range_on = 2
+ var/light_power_on = 1
+ var/light_range_on = 2
var/overlay_layer
atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE
clicksound = "keyboard"
@@ -109,7 +108,7 @@
*/
/obj/machinery/computer/proc/update_glow()
if (operable())
- set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color)
+ set_light(light_range_on, light_power_on, light_color)
return TRUE
else
set_light(0)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index cabbad0bbacc4..864a515e82ec2 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -705,21 +705,21 @@ About the new airlock wires panel:
if(AIRLOCK_CLOSED)
if(lights && locked)
new_overlays += overlay_image(bolts_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
- set_light(0.25, 0.1, 1, 2, COLOR_RED_LIGHT)
+ set_light(2, 0.75, COLOR_RED_LIGHT)
if(AIRLOCK_DENY)
if(lights)
new_overlays += overlay_image(deny_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
- set_light(0.25, 0.1, 1, 2, COLOR_RED_LIGHT)
+ set_light(2, 0.75, COLOR_RED_LIGHT)
if(AIRLOCK_EMAG)
new_overlays += overlay_image(emag_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
if(AIRLOCK_CLOSING)
if(lights)
new_overlays += overlay_image(lights_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
- set_light(0.25, 0.1, 1, 2, COLOR_LIME)
+ set_light(2, 0.75, COLOR_LIME)
if(AIRLOCK_OPENING)
if(lights)
new_overlays += overlay_image(lights_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
- set_light(0.25, 0.1, 1, 2, COLOR_LIME)
+ set_light(2, 0.75, COLOR_LIME)
if(MACHINE_IS_BROKEN(src))
new_overlays += overlay_image(sparks_broken_file, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
else if (get_damage_percentage() >= 25)
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 7369ae505838d..d89a8e1b00d1a 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -521,7 +521,7 @@
weld_overlay = welded_file
if(do_set_light)
- set_light(0.25, 0.1, 1, 2, COLOR_SUN)
+ set_light(2, 0.25, COLOR_SUN)
AddOverlays(panel_overlay)
AddOverlays(weld_overlay)
diff --git a/code/game/machinery/doors/simple.dm b/code/game/machinery/doors/simple.dm
index d9064599205d8..196c9b9b19a65 100644
--- a/code/game/machinery/doors/simple.dm
+++ b/code/game/machinery/doors/simple.dm
@@ -29,7 +29,7 @@
if(locked)
lock = new(src,locked)
if(material.luminescence)
- set_light(0.5, 1, material.luminescence, l_color = material.icon_colour)
+ set_light(material.luminescence, 0.5, l_color = material.icon_colour)
if(material.opacity < 0.5)
glass = TRUE
diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm
index 62a481a074d26..ce38f148a0522 100644
--- a/code/game/machinery/floodlight.dm
+++ b/code/game/machinery/floodlight.dm
@@ -17,9 +17,8 @@
machine_desc = "A portable, battery-powered LED flood lamp used to illuminate large areas."
//better laser, increased brightness & power consumption
- var/l_max_bright = 0.8 //brightness of light when on, can be negative
- var/l_inner_range = 0 //inner range of light when on, can be negative
- var/l_outer_range = 4.5 //outer range of light when on, can be negative
+ var/l_power = 2.5 //brightness of light when on, can be negative
+ var/l_range = 7 //outer range of light when on, can be negative
/obj/machinery/floodlight/on_update_icon()
icon_state = "flood[panel_open ? "o" : ""][panel_open && get_cell() ? "b" : ""]0[use_power == POWER_USE_ACTIVE]"
@@ -34,17 +33,17 @@
// If the cell is almost empty rarely "flicker" the light. Aesthetic only.
if(prob(30))
- set_light(l_max_bright / 2, l_inner_range, l_outer_range)
+ set_light(l_range, l_power / 2, angle = LIGHT_WIDE)
spawn(20)
if(use_power)
- set_light(l_max_bright, l_inner_range, l_outer_range)
+ set_light(l_range, l_power, angle = LIGHT_WIDE)
// Returns 0 on failure and 1 on success
/obj/machinery/floodlight/proc/turn_on(loud = 0)
if(!is_powered())
return 0
- set_light(l_max_bright, l_inner_range, l_outer_range)
+ set_light(l_range, l_power / 2, angle = LIGHT_WIDE)
update_use_power(POWER_USE_ACTIVE)
use_power_oneoff(active_power_usage)//so we drain cell if they keep trying to use it
update_icon()
@@ -77,9 +76,8 @@
/obj/machinery/floodlight/RefreshParts()//if they're insane enough to modify a floodlight, let them
..()
var/light_mod = clamp(total_component_rating_of_type(/obj/item/stock_parts/capacitor), 0, 10)
- l_max_bright = light_mod? light_mod*0.01 + initial(l_max_bright) : initial(l_max_bright)/2 //gives us between 0.8-0.9 with capacitor, or 0.4 without one
- l_inner_range = light_mod + initial(l_inner_range)
- l_outer_range = light_mod*1.5 + initial(l_outer_range)
+ l_power = light_mod? light_mod*0.01 + initial(l_power) : initial(l_power)/2 //gives us between 0.8-0.9 with capacitor, or 0.4 without one
+ l_range = light_mod*1.5 + initial(l_range)
change_power_consumption(initial(active_power_usage) * light_mod , POWER_USE_ACTIVE)
if(use_power)
- set_light(l_max_bright, l_inner_range, l_outer_range)
+ set_light(l_range, l_power, angle = LIGHT_WIDE)
diff --git a/code/game/machinery/floor_light.dm b/code/game/machinery/floor_light.dm
index e058d23f3e911..81939b750a7c6 100644
--- a/code/game/machinery/floor_light.dm
+++ b/code/game/machinery/floor_light.dm
@@ -14,9 +14,8 @@ var/global/list/floor_light_cache = list()
matter = list(MATERIAL_STEEL = 250, MATERIAL_GLASS = 250)
var/damaged
- var/default_light_max_bright = 0.75
- var/default_light_inner_range = 1
- var/default_light_outer_range = 3
+ var/default_light_power = 0.75
+ var/default_light_range = 3
var/default_light_colour = "#ffffff"
@@ -105,11 +104,11 @@ var/global/list/floor_light_cache = list()
/obj/machinery/floor_light/proc/update_brightness()
if((use_power == POWER_USE_ACTIVE) && operable())
- if(light_outer_range != default_light_outer_range || light_max_bright != default_light_max_bright || light_color != default_light_colour)
- set_light(default_light_max_bright, default_light_inner_range, default_light_outer_range, l_color = default_light_colour)
- change_power_consumption((light_outer_range + light_max_bright) * 20, POWER_USE_ACTIVE)
+ if(light_range != default_light_range || light_power != default_light_power || light_color != default_light_colour)
+ set_light(default_light_range, default_light_power, default_light_colour)
+ change_power_consumption((light_range + light_power) * 20, POWER_USE_ACTIVE)
else
- if(light_outer_range || light_max_bright)
+ if(light_range || light_power)
set_light(0)
/obj/machinery/floor_light/on_update_icon()
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 8e5cc24e5b90c..5f4d088ed140c 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -356,9 +356,9 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
hologram.SetName("[A.name] (Hologram)") //If someone decides to right click.
A.holo = src
masters[A] = hologram
- hologram.set_light(1, 0.1, 2) //hologram lighting
+ hologram.set_light(2, 0.1) //hologram lighting
hologram.color = color //painted holopad gives coloured holograms
- set_light(1, 0.1, 2) //pad lighting
+ set_light(2, 0.1) //pad lighting
icon_state = "[base_icon]1"
return 1
diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm
index 2a6c00e93ec22..a0920d6fab780 100644
--- a/code/game/machinery/holosign.dm
+++ b/code/game/machinery/holosign.dm
@@ -36,7 +36,7 @@
set_light(0)
else
icon_state = on_icon
- set_light(0.5, 0.5, 1, l_color = COLOR_CYAN_BLUE)
+ set_light(1, 0.5, COLOR_CYAN_BLUE)
/singleton/public_access/public_variable/holosign_on
expected_type = /obj/machinery/holosign
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index c121ac2efc611..0e48e0a77e2a2 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -41,7 +41,7 @@
icon_state = "light[on]"
overlay.icon_state = "light[on]-overlay"
AddOverlays(overlay)
- set_light(0.1, 0.1, 1, 2, on ? "#82ff4c" : "#f86060")
+ set_light(2, 0.25, on ? "#82ff4c" : "#f86060")
/obj/machinery/light_switch/examine(mob/user, distance)
. = ..()
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 889addcde312d..62c5f3cb24e9a 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -153,7 +153,7 @@ var/global/list/obj/machinery/newscaster/allCasters = list() //Global list that
var/hitstaken = 0 //Death at 3 hits from an item with force>=15
var/datum/feed_channel/viewing_channel = null
var/datum/feed_network/connected_group
- light_outer_range = 0
+ light_range = 0
anchored = TRUE
layer = ABOVE_WINDOW_LAYER
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index 7d0c25c78b187..36f789cc7fa83 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -50,7 +50,7 @@ var/global/list/obj/machinery/requests_console/allConsoles = list()
var/message = "";
var/recipient = ""; //the department which will be receiving the message
var/priority = -1 ; //Priority of the message being sent
- light_outer_range = 0
+ light_range = 0
var/datum/announcement/announcement = new
/obj/machinery/requests_console/on_update_icon()
diff --git a/code/game/machinery/rotating_alarm.dm b/code/game/machinery/rotating_alarm.dm
index 4dc1650968955..5d9e7b20a067e 100644
--- a/code/game/machinery/rotating_alarm.dm
+++ b/code/game/machinery/rotating_alarm.dm
@@ -96,7 +96,7 @@
/obj/machinery/rotating_alarm/proc/set_on()
vis_contents += spin_effect
- set_light(1, 0.5, 2, 0.3, alarm_light_color)
+ set_light(2, 0.5, alarm_light_color)
on = TRUE
low_alarm = FALSE
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index 4c9e6641b6bc5..71107f83a46b4 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -14,6 +14,8 @@
atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE
clicksound = "switch"
+ light_power = 0.5
+
/obj/machinery/space_heater/New()
..()
@@ -26,10 +28,10 @@
set_light(0)
else if(active > 0)
icon_state = "sheater-heat"
- set_light(0.7, 1, 2, 3, COLOR_SEDONA)
+ set_light(3, COLOR_SEDONA)
else if(active < 0)
icon_state = "sheater-cool"
- set_light(0.7, 1, 2, 3, COLOR_DEEP_SKY_BLUE)
+ set_light(3, l_color = COLOR_DEEP_SKY_BLUE)
else
icon_state = "sheater-standby"
set_light(0)
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index dd86c05886db2..c909f8d85fa88 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -191,7 +191,7 @@
var/image/alert = overlay_image(sl.icon, sl.overlay_status_display, plane = EFFECTS_ABOVE_LIGHTING_PLANE, layer = ABOVE_LIGHTING_LAYER)
- set_light(sl.light_max_bright, sl.light_inner_range, sl.light_outer_range, 2, sl.light_color_alarm)
+ set_light(sl.light_range, sl.light_power, sl.light_color_alarm)
AddOverlays(alert)
/obj/machinery/status_display/proc/set_picture(state)
@@ -200,13 +200,13 @@
picture_state = state
picture = image('icons/obj/machines/status_display.dmi', icon_state=picture_state)
AddOverlays(picture)
- set_light(0.5, 0.1, 1, 2, COLOR_WHITE)
+ set_light(2, 0.5, COLOR_WHITE)
/obj/machinery/status_display/proc/update_display(line1, line2)
var/new_text = {"
[line1]
[line2]
"}
if(maptext != new_text)
maptext = new_text
- set_light(0.5, 0.1, 1, 2, COLOR_WHITE)
+ set_light(2, 0.5, COLOR_WHITE)
/obj/machinery/status_display/proc/get_shuttle_timer()
var/timeleft = evacuation_controller.get_eta()
diff --git a/code/game/machinery/supplybeacon.dm b/code/game/machinery/supplybeacon.dm
index b4e90fdac91cc..806d04e3e4e3e 100644
--- a/code/game/machinery/supplybeacon.dm
+++ b/code/game/machinery/supplybeacon.dm
@@ -76,7 +76,7 @@
if(surplus() < 500)
if(user) to_chat(user, SPAN_NOTICE("The connected wire doesn't have enough current."))
return
- set_light(1, 0.5, 2, 2, "#00ccaa")
+ set_light(3, 3, "#00ccaa")
icon_state = "beacon_active"
update_use_power(POWER_USE_IDLE)
admin_attacker_log(user, "has activated \a [src] at [get_area(src)]")
diff --git a/code/game/machinery/teleporter/pad.dm b/code/game/machinery/teleporter/pad.dm
index c8044cbe88ec9..27ea156fc52df 100644
--- a/code/game/machinery/teleporter/pad.dm
+++ b/code/game/machinery/teleporter/pad.dm
@@ -81,7 +81,7 @@
I.plane = EFFECTS_ABOVE_LIGHTING_PLANE
I.layer = ABOVE_LIGHTING_LAYER
AddOverlays(I)
- set_light(0.4, 1.2, 4, 10)
+ set_light(4, 0.4)
if (interference && prob(20))
visible_message(SPAN_WARNING("The teleporter sparks ominously!"))
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index f703976b19e7c..bdaeadccc00ad 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -199,13 +199,13 @@
else if (enabled)
if (lethal)
icon_state = "control_kill"
- set_light(1, 0.5, 2, 2, "#990000")
+ set_light(1.5, 1,"#990000")
else
icon_state = "control_stun"
- set_light(1, 0.5, 2, 2, "#ff9900")
+ set_light(1.5, 1,"#ff9900")
else
icon_state = "control_standby"
- set_light(1, 0.5, 2, 2, "#003300")
+ set_light(1.5, 1,"#003300")
/obj/machinery/turretid/emp_act(severity)
if(enabled)
diff --git a/code/game/machinery/vending/_vending.dm b/code/game/machinery/vending/_vending.dm
index 77a8554ebda67..295352e7335aa 100644
--- a/code/game/machinery/vending/_vending.dm
+++ b/code/game/machinery/vending/_vending.dm
@@ -91,7 +91,6 @@
var/scan_id = TRUE
var/obj/item/material/coin/coin
var/light_max_bright_on = 0.2
- var/light_inner_range_on = 1
var/light_outer_range_on = 2
@@ -148,7 +147,7 @@
if (!is_powered() || MACHINE_IS_BROKEN(src))
set_light(0)
else
- set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color)
+ set_light(light_outer_range_on, light_max_bright_on, light_color)
/obj/machinery/vending/on_update_icon()
diff --git a/code/game/objects/auras/radiant_aura.dm b/code/game/objects/auras/radiant_aura.dm
index fb62c8646758d..9b5a4a68a68b9 100644
--- a/code/game/objects/auras/radiant_aura.dm
+++ b/code/game/objects/auras/radiant_aura.dm
@@ -7,7 +7,7 @@
/obj/aura/radiant_aura/added_to(mob/living/L)
..()
to_chat(L,SPAN_NOTICE("A bubble of light appears around you, exuding protection and warmth."))
- set_light(0.6, 1, 6, 2, "#e09d37")
+ set_light(6, 6, "#e09d37")
/obj/aura/radiant_aura/removed()
to_chat(user, SPAN_WARNING("Your protective aura dissipates, leaving you feeling cold and unsafe."))
diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm
index 33c4dc193b1c7..6e8b2043b2bba 100644
--- a/code/game/objects/effects/decals/Cleanable/misc.dm
+++ b/code/game/objects/effects/decals/Cleanable/misc.dm
@@ -44,7 +44,7 @@
name = "glowing goo"
desc = "Jeez. I hope that's not for lunch."
gender = PLURAL
- light_outer_range = 1
+ light_range = 1
icon = 'icons/effects/effects.dmi'
icon_state = "greenglow"
persistent = TRUE
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index b74dc451a7e9c..6ab22462b7b18 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -240,7 +240,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
icon_state = "sparks"
/obj/effect/effect/smoke/illumination/New(newloc, lifetime=10, range=null, power=null, color=null)
- set_light(power, 0.1, range, 2, color)
+ set_light(range, power, color)
time_to_live=lifetime
..()
diff --git a/code/game/objects/effects/fake_fire.dm b/code/game/objects/effects/fake_fire.dm
index ad6f2ded48d57..4dfabc3bdd78a 100644
--- a/code/game/objects/effects/fake_fire.dm
+++ b/code/game/objects/effects/fake_fire.dm
@@ -11,7 +11,7 @@
/obj/effect/fake_fire/New()
..()
- set_light(0.5, 1, 3, l_color = color)
+ set_light(3, 0.5, color)
START_PROCESSING(SSobj,src)
if(lifetime)
QDEL_IN(src,lifetime)
diff --git a/code/game/objects/effects/fire/fire.dm b/code/game/objects/effects/fire/fire.dm
index da455a9545c3e..1e5511b4fc228 100644
--- a/code/game/objects/effects/fire/fire.dm
+++ b/code/game/objects/effects/fire/fire.dm
@@ -197,16 +197,16 @@
switch(current_fire_state)
if(TURF_FIRE_STATE_SMALL)
icon_state = "small"
- set_light(0.5, 1, 1.5)
+ set_light(1.5, 0.5)
if(TURF_FIRE_STATE_MEDIUM)
icon_state = "medium"
- set_light(0.5, 1, 2,)
+ set_light(2, 0.5)
if(TURF_FIRE_STATE_LARGE)
icon_state = "big"
- set_light(0.5, 1.5, 2,)
+ set_light(2, 0.6)
if(TURF_FIRE_STATE_MAX)
icon_state = "max"
- set_light(0.7, 1.6, 3)
+ set_light(3, 0.7)
#undef TURF_FIRE_REQUIRED_TEMP
#undef TURF_FIRE_TEMP_BASE
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 1ec7f3cb3394f..b87544ada4656 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -19,11 +19,13 @@
action_button_name = "Toggle Flashlight"
var/on = FALSE
var/activation_sound = 'sound/effects/flashlight.ogg'
- var/flashlight_max_bright = 0.5 //brightness of light when on, must be no greater than 1.
- var/flashlight_inner_range = 1 //inner range of light when on, can be negative
- var/flashlight_outer_range = 3 //outer range of light when on, can be negative
+ var/flashlight_power = 1 //brightness of light when on
+ var/flashlight_range = 4 //outer range of light when on, can be negative
+ light_wedge = LIGHT_VERY_WIDE
var/flashlight_flags = EMPTY_BITFIELD // FLASHLIGHT_ bitflags
+ var/spawn_dir // a way for mappers to force which way a flashlight faces upon spawning
+
/obj/item/device/flashlight/Initialize()
. = ..()
@@ -61,11 +63,34 @@
return 1
/obj/item/device/flashlight/proc/set_flashlight()
+ if(light_wedge)
+ set_dir(pick(NORTH, SOUTH, EAST, WEST))
+ if(spawn_dir)
+ set_dir(spawn_dir)
+
if (on)
- set_light(flashlight_max_bright, flashlight_inner_range, flashlight_outer_range, 2, light_color)
+ set_light(flashlight_range, flashlight_power, light_color)
else
set_light(0)
+/obj/item/device/flashlight/examine(mob/user, distance)
+ . = ..()
+ if(light_wedge && isturf(loc))
+ to_chat(user, FONT_SMALL(SPAN_NOTICE("\The [src] is facing [dir2text(dir)].")))
+
+/obj/item/device/flashlight/dropped(mob/user)
+ . = ..()
+ if(light_wedge)
+ set_dir(user.dir)
+ update_light()
+
+/obj/item/device/flashlight/throw_at()
+ . = ..()
+ if(light_wedge)
+ var/new_dir = pick(NORTH, SOUTH, EAST, WEST)
+ set_dir(new_dir)
+ update_light()
+
/obj/item/device/flashlight/attack(mob/living/M as mob, mob/living/user as mob)
. = FALSE
if (istype(M) && on && user.zone_sel.selecting == BP_EYES)
@@ -138,8 +163,8 @@
desc = "An energy efficient flashlight."
icon_state = "biglight"
item_state = "biglight"
- flashlight_max_bright = 0.75
- flashlight_outer_range = 4
+ flashlight_power = 3
+ flashlight_range = 6
/obj/item/device/flashlight/flashdark
name = "flashdark"
@@ -147,9 +172,8 @@
icon_state = "flashdark"
item_state = "flashdark"
w_class = ITEM_SIZE_NORMAL
- flashlight_max_bright = -1
- flashlight_outer_range = 4
- flashlight_inner_range = 1
+ flashlight_power = -6
+ flashlight_range = 6
flashlight_flags = FLASHLIGHT_CANNOT_BLIND
/obj/item/device/flashlight/pen
@@ -160,9 +184,8 @@
obj_flags = OBJ_FLAG_CONDUCTIBLE
slot_flags = SLOT_EARS
w_class = ITEM_SIZE_TINY
- flashlight_max_bright = 0.25
- flashlight_inner_range = 0.1
- flashlight_outer_range = 2
+ light_wedge = LIGHT_OMNI
+ flashlight_range = 2
/obj/item/device/flashlight/maglight
name = "maglight"
@@ -174,8 +197,8 @@
attack_verb = list ("smacked", "thwacked", "thunked")
matter = list(MATERIAL_ALUMINIUM = 200, MATERIAL_GLASS = 50)
hitsound = "swing_hit"
- flashlight_max_bright = 0.5
- flashlight_outer_range = 5
+ light_wedge = LIGHT_NARROW
+ flashlight_range = 8
/******************************Lantern*******************************/
/obj/item/device/flashlight/lantern
@@ -189,7 +212,10 @@
obj_flags = OBJ_FLAG_CONDUCTIBLE
slot_flags = SLOT_BELT
matter = list(MATERIAL_STEEL = 200,MATERIAL_GLASS = 100)
- flashlight_outer_range = 5
+ flashlight_range = 3
+ light_wedge = LIGHT_OMNI
+ light_color = COLOR_ORANGE
+ flashlight_power = 1
/obj/item/device/flashlight/lantern/on_update_icon()
..()
@@ -207,9 +233,7 @@
item_state = ""
obj_flags = OBJ_FLAG_CONDUCTIBLE
w_class = ITEM_SIZE_TINY
- flashlight_max_bright = 0.25
- flashlight_inner_range = 0.1
- flashlight_outer_range = 2
+ flashlight_range = 2
flashlight_flags = FLASHLIGHT_CANNOT_BLIND
@@ -222,9 +246,8 @@
item_state = "lamp"
w_class = ITEM_SIZE_LARGE
obj_flags = OBJ_FLAG_CONDUCTIBLE
- flashlight_max_bright = 0.3
- flashlight_inner_range = 2
- flashlight_outer_range = 5
+ flashlight_range = 5
+ light_wedge = LIGHT_OMNI
on = 1
@@ -260,9 +283,9 @@
activation_sound = 'sound/effects/flare.ogg'
flashlight_flags = FLASHLIGHT_SINGLE_USE
- flashlight_max_bright = 0.8
- flashlight_inner_range = 0.1
- flashlight_outer_range = 5
+ flashlight_power = 3
+ flashlight_range = 5
+ light_wedge = LIGHT_OMNI
/obj/item/device/flashlight/flare/Initialize()
. = ..()
@@ -336,9 +359,9 @@
produce_heat = 0
activation_sound = 'sound/effects/glowstick.ogg'
- flashlight_max_bright = 0.6
- flashlight_inner_range = 0.1
- flashlight_outer_range = 3
+ flashlight_range = 4
+ flashlight_power = 1.5
+ light_wedge = LIGHT_OMNI
flashlight_flags = FLASHLIGHT_SINGLE_USE | FLASHLIGHT_CANNOT_BLIND
@@ -407,9 +430,9 @@
on = TRUE //Bio-luminesence has one setting, on.
flashlight_flags = FLASHLIGHT_ALWAYS_ON | FLASHLIGHT_CANNOT_BLIND
- flashlight_max_bright = 1
- flashlight_inner_range = 0.1
- flashlight_outer_range = 5
+ flashlight_power = 0.8
+ flashlight_range = 5
+ light_wedge = LIGHT_OMNI
/obj/item/device/flashlight/slime/New()
..()
@@ -426,9 +449,9 @@
w_class = ITEM_SIZE_LARGE
obj_flags = OBJ_FLAG_CONDUCTIBLE | OBJ_FLAG_ROTATABLE
- flashlight_max_bright = 0.8
- flashlight_inner_range = 1
- flashlight_outer_range = 5
+ flashlight_power = 1
+ flashlight_range = 7
+ light_wedge = LIGHT_WIDE
/obj/item/device/flashlight/lamp/floodlamp/green
icon_state = "greenfloodlamp"
@@ -440,7 +463,7 @@
icon_state = "lavalamp"
on = 0
action_button_name = "Toggle lamp"
- flashlight_outer_range = 3 //range of light when on
+ flashlight_range = 3 //range of light when on
matter = list(MATERIAL_ALUMINIUM = 250, MATERIAL_GLASS = 200)
flashlight_flags = FLASHLIGHT_CANNOT_BLIND
diff --git a/code/game/objects/items/devices/oxycandle.dm b/code/game/objects/items/devices/oxycandle.dm
index 72705d5b6373a..174df6eca7708 100644
--- a/code/game/objects/items/devices/oxycandle.dm
+++ b/code/game/objects/items/devices/oxycandle.dm
@@ -11,8 +11,8 @@
var/on = 0
var/activation_sound = 'sound/effects/flare.ogg'
light_color = "#e58775"
- light_outer_range = 2
- light_max_bright = 1
+ light_range = 2
+ light_power = 1
var/brightness_on = 1 // Moderate-low bright.
action_button_name = null
diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm
index ba96d722b9f4e..2afe8bf32716a 100644
--- a/code/game/objects/items/devices/powersink.dm
+++ b/code/game/objects/items/devices/powersink.dm
@@ -131,7 +131,7 @@
var/datum/powernet/PN = attached.powernet
var/drained = 0
if(PN)
- set_light(0.5, 0.1, 12)
+ set_light(12)
PN.trigger_warning()
// found a powernet, so drain up to max power from it
drained = PN.draw_power(drain_rate)
diff --git a/code/game/objects/items/devices/slide_projector.dm b/code/game/objects/items/devices/slide_projector.dm
index ab69838fd8e1d..9191355377619 100644
--- a/code/game/objects/items/devices/slide_projector.dm
+++ b/code/game/objects/items/devices/slide_projector.dm
@@ -93,7 +93,7 @@
projection = new projection_type(target)
projection.set_source(current_slide)
GLOB.moved_event.register(src, src, .proc/check_projections)
- set_light(0.1, 0.1, 1, 2, COLOR_WHITE) //Bit of light
+ set_light(1, 0.1, COLOR_WHITE) //Bit of light
update_icon()
/obj/item/storage/slide_projector/attack_self(mob/user)
@@ -155,7 +155,7 @@
/obj/effect/projection/Initialize()
. = ..()
- set_light(0.1, 0.1, 1, 2, COLOR_WHITE) //Makes turning off the lights not invalidate projection
+ set_light(1, 0.1, COLOR_WHITE) //Makes turning off the lights not invalidate projection
/obj/effect/projection/on_update_icon()
filters = filter(type="drop_shadow", color = COLOR_WHITE, size = 4, offset = 1,x = 0, y = 0)
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index c68602b4db467..9b64e41714689 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -889,7 +889,7 @@
attack_verb = list("attacked", "whacked", "jabbed", "poked", "marshalled")
/obj/item/marshalling_wand/Initialize()
- set_light(0.6, 0.5, 2, 2, "#ff0000")
+ set_light(1.5, 1.5, "#ff0000")
return ..()
/obj/item/marshalling_wand/attack_self(mob/living/user as mob)
diff --git a/code/game/objects/items/weapons/candle/candle.dm b/code/game/objects/items/weapons/candle/candle.dm
index d7f1c22b76b41..4b83b86b5e982 100644
--- a/code/game/objects/items/weapons/candle/candle.dm
+++ b/code/game/objects/items/weapons/candle/candle.dm
@@ -11,10 +11,8 @@
var/wax
var/last_lit
var/icon_set = "candle"
- var/candle_max_bright = 0.3
- var/candle_inner_range = 0.1
- var/candle_outer_range = 4
- var/candle_falloff = 2
+ var/candle_range = CANDLE_LUM
+ var/candle_power
/obj/item/flame/candle/Initialize()
wax = rand(27 MINUTES, 33 MINUTES) / SSobj.wait // Enough for 27-33 minutes. 30 minutes on average, adjusted for subsystem tickrate.
@@ -52,7 +50,7 @@
if(!lit)
lit = 1
visible_message(SPAN_NOTICE("\The [user] lights the [name]."))
- set_light(candle_max_bright, candle_inner_range, candle_outer_range, candle_falloff)
+ set_light(candle_range, candle_power)
START_PROCESSING(SSobj, src)
/obj/item/flame/candle/Process()
diff --git a/code/game/objects/items/weapons/candle/incense.dm b/code/game/objects/items/weapons/candle/incense.dm
index 6c7246377cbd1..75eb59076e8af 100644
--- a/code/game/objects/items/weapons/candle/incense.dm
+++ b/code/game/objects/items/weapons/candle/incense.dm
@@ -5,10 +5,7 @@
available_colours = null
icon_set = "incense"
- candle_max_bright = 0.1
- candle_inner_range = 0.1
- candle_outer_range = 1
- candle_falloff = 2
+ candle_range = 1
scent_types = list(/singleton/scent_type/rose,
/singleton/scent_type/citrus,
diff --git a/code/game/objects/items/weapons/ecigs.dm b/code/game/objects/items/weapons/ecigs.dm
index dd47f843c66ea..b44380dd2d7c1 100644
--- a/code/game/objects/items/weapons/ecigs.dm
+++ b/code/game/objects/items/weapons/ecigs.dm
@@ -131,7 +131,7 @@
if (active)
item_state = icon_on
icon_state = icon_on
- set_light(0.6, 0.5, brightness_on)
+ set_light(brightness_on)
else if (ec_cartridge)
set_light(0)
item_state = icon_off
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index e93d54d22dff2..f636b6dd3a8ae 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -140,7 +140,7 @@
playsound(loc, 'sound/items/welderdeactivate.ogg', 50, TRUE)
STOP_PROCESSING(SSobj,src)
if(lit)
- set_light(0.7, 1, 2.5, l_color = COLOR_ORANGE)
+ set_light(2.5, 0.7, l_color = COLOR_ORANGE)
else
set_light(0)
diff --git a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm
index d428534046f34..dc385553ee0d2 100644
--- a/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/anti_photon_grenade.dm
@@ -8,11 +8,11 @@
/obj/item/grenade/anti_photon/detonate(mob/living/user)
playsound(src.loc, 'sound/effects/phasein.ogg', 50, 1, 5)
- set_light(-1, 6, 10, 2, "#ffffff")
+ set_light(10, -10, "#ffffff")
addtimer(new Callback(src, .proc/finish), rand(20 SECONDS, 29 SECONDS))
/obj/item/grenade/anti_photon/proc/finish()
- set_light(1, 1, 10, 2, "#[num2hex(rand(64,255))][num2hex(rand(64,255))][num2hex(rand(64,255))]")
+ set_light(10, 10, "#[num2hex(rand(64,255))][num2hex(rand(64,255))][num2hex(rand(64,255))]")
playsound(loc, 'sound/effects/bang.ogg', 50, 1, 5)
sleep(1 SECOND)
qdel(src)
diff --git a/code/game/objects/items/weapons/grenades/light.dm b/code/game/objects/items/weapons/grenades/light.dm
index f6c947468e1a1..08b8568ab62b4 100644
--- a/code/game/objects/items/weapons/grenades/light.dm
+++ b/code/game/objects/items/weapons/grenades/light.dm
@@ -12,5 +12,5 @@
playsound(src, 'sound/effects/snap.ogg', 80, 1)
audible_message(SPAN_WARNING("\The [src] detonates with a sharp crack!"))
- set_light(1, 1, 12, 2, light_colour)
+ set_light(12, 1, light_colour)
QDEL_IN(src, lifetime)
diff --git a/code/game/objects/items/weapons/lighter.dm b/code/game/objects/items/weapons/lighter.dm
index ed78d113f49a1..8d2d56bc003c3 100644
--- a/code/game/objects/items/weapons/lighter.dm
+++ b/code/game/objects/items/weapons/lighter.dm
@@ -30,7 +30,7 @@
lit = 1
update_icon()
light_effects(user)
- set_light(0.6, 0.5, 2, l_color = COLOR_PALE_ORANGE)
+ set_light(2, l_color = COLOR_PALE_ORANGE)
START_PROCESSING(SSobj, src)
/obj/item/flame/lighter/proc/light_effects(mob/living/carbon/user)
@@ -95,7 +95,7 @@
if(ismob(loc) && prob(10) && reagents.get_reagent_amount(/datum/reagent/fuel) < 1)
to_chat(loc, SPAN_WARNING("\The [src]'s flame flickers."))
set_light(0)
- addtimer(new Callback(src, .atom/proc/set_light, 0.6, 0.5, 2), 4)
+ addtimer(new Callback(src, .atom/proc/set_light, 2), 4)
reagents.remove_reagent(/datum/reagent/fuel, 0.05)
else
extinguish()
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 5c37dc6390848..c5e640901247a 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -56,7 +56,7 @@
if (user)
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
to_chat(user, SPAN_NOTICE("\The [src] is now energised."))
- set_light(0.8, 1, 2, 4, lighting_color)
+ set_light(2, 0.8, lighting_color)
if (istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 5e12c02dd694b..659b31bc11eaf 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -185,7 +185,7 @@
/obj/item/shield/energy/on_update_icon()
icon_state = "eshield[active]"
if (active)
- set_light(0.6, 0.1, 2, 1, "#006aff")
+ set_light(1.5, 1.5, "#006aff")
else
set_light(0)
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 9dd976773a32a..7e688821c1e8a 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -63,7 +63,7 @@
icon_state = "[initial(name)]"
if(icon_state == "[initial(name)]_active")
- set_light(0.4, 0.1, 1, 2, "#ff6a00")
+ set_light(1.5, 2, "#ff6a00")
else
set_light(0)
@@ -241,7 +241,7 @@
/obj/item/melee/baton/robot/electrified_arm/on_update_icon()
if(status)
icon_state = "electrified_arm_active"
- set_light(0.4, 0.1, 1, 2, "#006aff")
+ set_light(1.5, 2, "#006aff")
else
icon_state = "electrified_arm"
set_light(0)
diff --git a/code/game/objects/items/weapons/tools/weldingtool.dm b/code/game/objects/items/weapons/tools/weldingtool.dm
index 48a66a1674c5e..4e3d3d0f39ef7 100644
--- a/code/game/objects/items/weapons/tools/weldingtool.dm
+++ b/code/game/objects/items/weapons/tools/weldingtool.dm
@@ -179,7 +179,7 @@
burn_fuel(amount)
if(M)
M.welding_eyecheck()//located in mob_helpers.dm
- set_light(0.7, 2, 5, l_color = COLOR_LIGHT_CYAN)
+ set_light(5, 0.7, COLOR_LIGHT_CYAN)
addtimer(new Callback(src, /atom/proc/update_icon), 5)
return 1
@@ -222,7 +222,7 @@
AddOverlays(image('icons/obj/tools/welder.dmi', "welder_[tank.icon_state]"))
if(welding)
AddOverlays(image('icons/obj/tools/welder.dmi', "welder_on"))
- set_light(0.6, 0.5, 2.5, l_color =COLOR_PALE_ORANGE)
+ set_light(2.5, 0.6, l_color =COLOR_PALE_ORANGE)
else
set_light(0)
item_state = welding ? "welder1" : "welder"
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 1c9484231b39c..919f6b743e8e1 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -244,7 +244,7 @@
/obj/structure/flora/pottedplant/unusual/Initialize()
. = ..()
- set_light(0.4, 0.1, 2, 2, "#007fff")
+ set_light(2, 0.4, "#007fff")
/obj/structure/flora/pottedplant/orientaltree
name = "potted oriental tree"
@@ -298,7 +298,7 @@
/obj/structure/flora/pottedplant/subterranean/Initialize()
. = ..()
- set_light(0.4, 0.1, 2, 2, "#ff6633")
+ set_light(2, 0.4, "#ff6633")
/obj/structure/flora/pottedplant/minitree
name = "potted tree"
diff --git a/code/game/objects/structures/fountain.dm b/code/game/objects/structures/fountain.dm
index 9e6285f326c7a..69df5092771b0 100644
--- a/code/game/objects/structures/fountain.dm
+++ b/code/game/objects/structures/fountain.dm
@@ -19,7 +19,7 @@
/obj/structure/fountain/strange/Initialize()
. = ..()
light_color = get_random_colour(lower = 190)
- set_light(0.6, 3, 5, 2, light_color)
+ set_light(5, 0.6, light_color)
/obj/structure/fountain/strange/attack_hand(mob/living/user)
diff --git a/code/game/objects/structures/seaweed.dm b/code/game/objects/structures/seaweed.dm
index d3bc8722ffc64..8853a7b5ce01a 100644
--- a/code/game/objects/structures/seaweed.dm
+++ b/code/game/objects/structures/seaweed.dm
@@ -20,11 +20,11 @@
/obj/structure/flora/seaweed/glow/Initialize()
. = ..()
- set_light(0.6, 0.1, 4, 3, "#00fff4")
+ set_light(4, 0.6, "#00fff4")
icon_state = "glowweed[rand(1,3)]"
/obj/effect/decal/cleanable/lichen
name = "lichen"
desc = "Damp and mossy plant life."
icon_state = "lichen"
- icon = 'icons/obj/structures/plants.dmi'
\ No newline at end of file
+ icon = 'icons/obj/structures/plants.dmi'
diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm
index 2c8ce0cf64573..0a0c8c7c5ac51 100644
--- a/code/game/turfs/flooring/flooring_premade.dm
+++ b/code/game/turfs/flooring/flooring_premade.dm
@@ -10,8 +10,8 @@
icon = 'icons/turf/flooring/circuit.dmi'
icon_state = "bcircuit"
initial_flooring = /singleton/flooring/reinforced/circuit
- light_outer_range = 2
- light_max_bright = 1
+ light_range = 2
+ light_power = 1
light_color = COLOR_BLUE
/turf/simulated/floor/greengrid
@@ -19,8 +19,8 @@
icon = 'icons/turf/flooring/circuit.dmi'
icon_state = "gcircuit"
initial_flooring = /singleton/flooring/reinforced/circuit/green
- light_outer_range = 2
- light_max_bright = 3
+ light_range = 2
+ light_power = 3
light_color = COLOR_GREEN
/turf/simulated/floor/redgrid
@@ -28,8 +28,8 @@
icon = 'icons/turf/flooring/circuit.dmi'
icon_state = "rcircuit"
initial_flooring = /singleton/flooring/reinforced/circuit/red
- light_outer_range = 2
- light_max_bright = 2
+ light_range = 2
+ light_power = 2
light_color = COLOR_RED
/turf/simulated/floor/selfestructgrid
@@ -37,8 +37,8 @@
icon = 'icons/turf/flooring/circuit.dmi'
icon_state = "rcircuit_off"
initial_flooring = /singleton/flooring/reinforced/circuit/selfdestruct
- light_outer_range = 2
- light_max_bright = 2
+ light_range = 2
+ light_power = 2
light_color = COLOR_BLACK
/turf/simulated/floor/wood
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index bfa606fd3f5b0..6a7401b9ea926 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -29,7 +29,7 @@
update_icon()
update_air()
sleep(15)
- set_light(0.4, 0.1, 1)
+ set_light(1, 0.4)
src.blocks_air = 1
set_opacity(1)
for(var/turf/simulated/turf in loc)
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 885c13f82d01a..016e0d2e26ad0 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -11,6 +11,7 @@
turf_flags = TURF_DISALLOW_BLOB
z_eventually_space = TRUE
+ var/starlit = FALSE
/turf/space/Initialize()
. = ..()
@@ -32,6 +33,7 @@
return INITIALIZE_HINT_LATELOAD // oh no! we need to switch to being a different kind of turf!
/turf/space/Destroy()
+ remove_starlight()
// Cleanup cached z_eventually_space values above us.
if (above)
var/turf/T = src
@@ -53,13 +55,26 @@
/turf/space/is_solid_structure()
return locate(/obj/structure/lattice, src) || locate(/obj/structure/catwalk, src) //counts as solid structure if it has a lattice or catwalk
+/turf/space/proc/remove_starlight()
+ if(starlit)
+ replace_ambient_light(SSskybox.background_color, null, config.starlight, 0)
+ starlit = FALSE
+
/turf/space/proc/update_starlight()
if(!config.starlight)
return
- if(locate(/turf/simulated) in orange(src,1)) //Let's make sure not to break everything if people use a crazy setting.
- set_light(min(0.1*config.starlight, 1), 1, 3, l_color = SSskybox.background_color)
- else
- set_light(0)
+
+ //We only need starlight on turfs adjacent to dynamically lit turfs, for example space near bulkhead
+ for (var/turf/T in RANGE_TURFS(src, 1))
+ if (!isloc(T.loc) || !TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
+ continue
+
+ add_ambient_light(SSskybox.background_color, config.starlight)
+ starlit = TRUE
+ return
+
+ if(TURF_IS_AMBIENT_LIT_UNSAFE(src))
+ remove_starlight()
/turf/space/attackby(obj/item/C as obj, mob/user as mob)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index ffd975cddea93..9aee9a3e69669 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -52,7 +52,14 @@
else
luminosity = 1
- RecalculateOpacity()
+ if (light_power && light_range)
+ update_light()
+
+ if (!mapload || (!istype(src, /turf/space) && is_outside()))
+ SSambient_lighting.queued += src
+
+ if (opacity)
+ has_opaque_atom = TRUE
if (mapload && permit_ao)
queue_ao()
@@ -431,3 +438,16 @@ var/global/const/enterloopsanity = 100
/turf/proc/IgniteTurf(power, fire_colour)
return
+
+//Maybe we want to make this stateful at some point
+/turf/proc/is_outside()
+
+ //For the purposes of light, dense turfs should not be considered to be outside
+ if(density)
+ return FALSE
+
+ var/area/A = get_area(src)
+ if(A.area_flags & AREA_FLAG_EXTERNAL)
+ return TRUE
+
+ //TODO: CitRP has some concept of outside based on turfs above. We don't really have any use cases right now, revisit this function if this changes
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index 2cb0c880a4431..14226552f07a8 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -35,13 +35,14 @@
var/old_hotspot = hotspot
var/old_turf_fire = null
var/old_opacity = opacity
- var/old_dynamic_lighting = dynamic_lighting
+ var/old_dynamic_lighting = TURF_IS_DYNAMICALLY_LIT_UNSAFE(src)
var/old_affecting_lights = affecting_lights
var/old_lighting_overlay = lighting_overlay
var/old_corners = corners
var/old_ao_neighbors = ao_neighbors
var/old_above = above
var/old_permit_ao = permit_ao
+ var/old_zflags = z_flags
if(isspaceturf(N) || isopenspace(N))
QDEL_NULL(turf_fire)
@@ -63,18 +64,16 @@
var/turf/simulated/S = src
if(S.zone) S.zone.rebuild()
+ if(ambient_bitflag) //Should remove everything about current bitflag, let it be recalculated by SS later
+ SSambient_lighting.clean_turf(src)
+
// Run the Destroy() chain.
qdel(src)
-
- var/old_opaque_counter = opaque_counter
var/turf/simulated/W = new N(src)
if (permit_ao)
regenerate_ao()
- W.opaque_counter = old_opaque_counter
- W.RecalculateOpacity()
-
if (keep_air)
W.air = old_air
@@ -101,18 +100,28 @@
. = W
W.ao_neighbors = old_ao_neighbors
- if(lighting_overlays_initialised)
+ // lighting stuff
+
+ if(SSlighting.initialized)
+ recalc_atom_opacity()
lighting_overlay = old_lighting_overlay
affecting_lights = old_affecting_lights
corners = old_corners
- if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting))
+ if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting || force_lighting_update)
reconsider_lights()
- if(dynamic_lighting != old_dynamic_lighting)
- if(dynamic_lighting)
+ updateVisibility(src)
+
+ if (dynamic_lighting != old_dynamic_lighting)
+ if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src))
lighting_build_overlay()
else
lighting_clear_overlay()
+ W.setup_local_ambient()
+ if(z_flags != old_zflags)
+ W.rebuild_zbleed()
+ // end of lighting stuff
+
for(var/turf/T in RANGE_TURFS(src, 1))
T.update_icon()
diff --git a/code/modules/ZAS/Fire.dm b/code/modules/ZAS/Fire.dm
index cfe59cf749212..3141430ade5fa 100644
--- a/code/modules/ZAS/Fire.dm
+++ b/code/modules/ZAS/Fire.dm
@@ -112,13 +112,13 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
if(firelevel > 6)
icon_state = "3"
- set_light(1, 2, 7)
+ set_light(7, 1)
else if(firelevel > 2.5)
icon_state = "2"
- set_light(0.7, 2, 5)
+ set_light(5, 0.7)
else
icon_state = "1"
- set_light(0.5, 1, 3)
+ set_light(3, 0.5)
for(var/mob/living/L in loc)
L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs!
@@ -168,7 +168,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
var/datum/gas_mixture/air_contents = loc.return_air()
color = fire_color(air_contents.temperature)
- set_light(0.5, 1, 3, l_color = color)
+ set_light(3, 0.5, l_color = color)
firelevel = fl
SSair.active_hotspots.Add(src)
diff --git a/code/modules/admin/buildmode/light_maker.dm b/code/modules/admin/buildmode/light_maker.dm
index 552624cb87838..6af18301838c7 100644
--- a/code/modules/admin/buildmode/light_maker.dm
+++ b/code/modules/admin/buildmode/light_maker.dm
@@ -2,8 +2,8 @@
name = "Light Maker"
icon_state = "buildmode8"
- var/light_outer_range = 3
- var/light_max_bright = 3
+ var/light_range = 3
+ var/light_power = 3
var/light_color = COLOR_WHITE
/datum/build_mode/light_maker/Help()
@@ -17,14 +17,14 @@
var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color", "Cancel")
switch(choice)
if("Range")
- var/input = input("New light range.", name, light_outer_range) as null|num
+ var/input = input("New light range.", name, light_range) as null|num
if(input)
- light_outer_range = input
+ light_range = input
if("Power")
- var/input = input("New light power, from 0.1 to 1 in decimal increments.", name, light_max_bright) as null|num
+ var/input = input("New light power, from 0.1 to 1 in decimal increments.", name, light_power) as null|num
if(input)
input = clamp(input, 0.1, 1)
- light_max_bright = input
+ light_power = input
if("Color")
var/input = input("New light color.", name, light_color) as null|color
if(input)
@@ -33,7 +33,7 @@
/datum/build_mode/light_maker/OnClick(atom/A, list/parameters)
if(parameters["left"])
if(A)
- A.set_light(light_max_bright, 0.1, light_outer_range, l_color = light_color)
+ A.set_light(light_range, light_power, l_color = light_color)
if(parameters["right"])
if(A)
A.set_light(0, 0, 0, l_color = COLOR_WHITE)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index b3a50edc990f1..19de2e0d3aa29 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -482,7 +482,7 @@
var/obj/effect/overmap/visitable/sector/exoplanet/new_planet = new exoplanet_type(null, world.maxx, world.maxy)
new_planet.features_budget = budget
new_planet.themes = list(new theme)
- new_planet.lightlevel = rand(5, 10)/10
+ new_planet.sun_brightness_modifier = rand(0.1, 0.6)
log_and_message_admins("is spawning [new_planet] at [new_planet.start_x],[new_planet.start_y], containing Z [english_list(new_planet.map_z)]")
new_planet.build_level()
diff --git a/code/modules/admin/view_variables/vv_set_handlers.dm b/code/modules/admin/view_variables/vv_set_handlers.dm
index 57e0faedab68f..8e68ebeb00ba8 100644
--- a/code/modules/admin/view_variables/vv_set_handlers.dm
+++ b/code/modules/admin/view_variables/vv_set_handlers.dm
@@ -118,7 +118,7 @@
/singleton/vv_set_handler/light_handler
handled_type = /atom
- handled_vars = list("light_max_bright","light_inner_range","light_outer_range","light_falloff_curve")
+ handled_vars = list("light_power","light_range")
/singleton/vv_set_handler/light_handler/handle_set_var(atom/A, variable, var_value, client)
var_value = text2num(var_value)
@@ -126,12 +126,10 @@
return
// More sanity checks
- var/new_max = variable == "light_max_bright" ? var_value : A.light_max_bright
- var/new_inner = variable == "light_inner_range" ? var_value : A.light_inner_range
- var/new_outer = variable == "light_outer_range" ? var_value : A.light_outer_range
- var/new_falloff = variable == "light_falloff_curve" ? var_value : A.light_falloff_curve
+ var/new_max = variable == "light_power" ? var_value : A.light_power
+ var/new_range = variable == "light_range" ? var_value : A.light_range
- A.set_light(new_max, new_inner, new_outer, new_falloff)
+ A.set_light(new_range, new_max)
/singleton/vv_set_handler/health_value_handler
handled_type = /atom
diff --git a/code/modules/ai/ai_holder_targeting.dm b/code/modules/ai/ai_holder_targeting.dm
index 1115e4dcae8e2..7fdf701698144 100644
--- a/code/modules/ai/ai_holder_targeting.dm
+++ b/code/modules/ai/ai_holder_targeting.dm
@@ -26,7 +26,7 @@
/// Step 1, find out what we can see.
/datum/ai_holder/proc/list_targets()
. = ohearers(vision_range, holder)
- . -= GLOB.dview_mob // Not the dview mob!
+ . -= global.dview_mob // Not the dview mob!
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /mob/living/exosuit, /obj/effect/blob))
diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm
index 268caaf4920e7..6a3e9977347e8 100644
--- a/code/modules/blob/blob.dm
+++ b/code/modules/blob/blob.dm
@@ -10,7 +10,7 @@
desc = "A pulsating mass of interwoven tendrils."
icon = 'icons/mob/blob.dmi'
icon_state = "blob"
- light_outer_range = 2
+ light_range = 2
light_color = BLOB_COLOR_PULS
density = TRUE
opacity = 1
diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm
index 6dfad07833ae1..3d2b1cab59232 100644
--- a/code/modules/clothing/_clothing.dm
+++ b/code/modules/clothing/_clothing.dm
@@ -456,7 +456,7 @@ BLIND // can't see anything
/obj/item/clothing/head/proc/update_flashlight(mob/user = null)
if(on && !light_applied)
- set_light(brightness_on, 1, 3)
+ set_light(3, brightness_on, angle = LIGHT_WIDE)
light_applied = 1
else if(!on && light_applied)
set_light(0)
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 549a244c00942..157030d0bc7d1 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -173,7 +173,6 @@
darkness_view = 5
action_button_name = "Toggle Goggles"
toggleable = TRUE
- see_invisible = SEE_INVISIBLE_NOLIGHTING
siemens_coefficient = 0.6
electric = TRUE
diff --git a/code/modules/clothing/spacesuits/rig/modules/ninja.dm b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
index fa8857967191f..5fb896c503db9 100644
--- a/code/modules/clothing/spacesuits/rig/modules/ninja.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
@@ -220,7 +220,7 @@
holder.visible_message(SPAN_DANGER("\The [src.holder] emits a shrill tone!"),SPAN_DANGER(" You hear a shrill tone!"))
sleep(blink_solid_time)
src.blink_mode = 0
- src.holder.set_light(0, 0, 0, 2, "#000000")
+ src.holder.set_light(2, 0, "#000000")
explosion(get_turf(src), explosion_radius, explosion_max_power)
if(holder && holder.wearer)
@@ -244,17 +244,17 @@
if(0)
return
if(1)
- src.holder.set_light(1, 1, 8.5, 2, "#ff0a00")
+ src.holder.set_light(8.5, 1, "#ff0a00")
sleep(6)
- src.holder.set_light(0, 0, 0, 2, "#000000")
+ src.holder.set_light(0)
spawn(6) .()
if(2)
- src.holder.set_light(1, 1, 8.5, 2, "#ff0a00")
+ src.holder.set_light(8.5, 1, "#ff0a00")
sleep(2)
- src.holder.set_light(0, 0, 0, 2, "#000000")
+ src.holder.set_light(0)
spawn(2) .()
if(3)
- src.holder.set_light(1, 1, 8.5, 2, "#ff0a00")
+ src.holder.set_light(8.5, 1, "#ff0a00")
/obj/item/rig_module/grenade_launcher/ninja
suit_overlay = null
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index efb52b798ca84..9eab5276cf639 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -33,7 +33,7 @@
action_button_name = "Toggle Helmet Light"
light_overlay = "helmet_light"
- brightness_on = 0.5
+ brightness_on = 1
on = 0
var/tinted = null //Set to non-null for toggleable tint helmets
diff --git a/code/modules/detectivework/tools/rag.dm b/code/modules/detectivework/tools/rag.dm
index 56383bbcfbccf..a95facf8eaae4 100644
--- a/code/modules/detectivework/tools/rag.dm
+++ b/code/modules/detectivework/tools/rag.dm
@@ -238,7 +238,7 @@
return
START_PROCESSING(SSobj, src)
- set_light(0.5, 0.1, 2, 2, "#e38f46")
+ set_light(2, 0.5, "#e38f46")
on_fire = 1
update_name()
update_icon()
diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm
index 1d828ffc8df6b..1b90195421e0c 100644
--- a/code/modules/detectivework/tools/uvlight.dm
+++ b/code/modules/detectivework/tools/uvlight.dm
@@ -21,7 +21,7 @@
/obj/item/device/uv_light/attack_self(mob/user)
on = !on
if(on)
- set_light(0.5, 0.1, range, 2, "#007fff")
+ set_light(range, 0.5, "#007fff")
START_PROCESSING(SSobj, src)
icon_state = "uv_on"
else
diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm
index 43509ea0cd995..f4982e39cdfaa 100644
--- a/code/modules/holodeck/HolodeckObjects.dm
+++ b/code/modules/holodeck/HolodeckObjects.dm
@@ -419,10 +419,9 @@
/mob/living/simple_animal/hostile/carp/holodeck/on_update_icon()
return
-
/mob/living/simple_animal/hostile/carp/holodeck/Initialize(mapload, ...)
. = ..()
- set_light(0.5, 0.1, 2) //hologram lighting
+ set_light(2, 0.5) //hologram lighting
/mob/living/simple_animal/hostile/carp/holodeck/proc/set_safety(safe)
diff --git a/code/modules/holomap/ship_holomap.dm b/code/modules/holomap/ship_holomap.dm
index a55b4f1cf64a0..0fc732082952d 100644
--- a/code/modules/holomap/ship_holomap.dm
+++ b/code/modules/holomap/ship_holomap.dm
@@ -160,7 +160,7 @@
set_light(0)
else
icon_state = "station_map"
- set_light(0.8, 0.1, 2, 2, "#1dbe17")
+ set_light(2, 0.8, "#1dbe17")
// Put the little "map" overlay down where it looks nice
if(small_station_map)
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index 70d4d9811f8bb..fdef5fce2ffb2 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -204,7 +204,7 @@
var/clr
if(get_trait(TRAIT_BIOLUM_COLOUR))
clr = get_trait(TRAIT_BIOLUM_COLOUR)
- splat.set_light(0.5, 0.1, 3, l_color = clr)
+ splat.set_light(3, 0.5, l_color = clr)
var/flesh_colour = get_trait(TRAIT_FLESH_COLOUR)
if(!flesh_colour) flesh_colour = get_trait(TRAIT_PRODUCT_COLOUR)
if(flesh_colour) splat.color = get_trait(TRAIT_PRODUCT_COLOUR)
@@ -787,7 +787,7 @@
var/clr
if(get_trait(TRAIT_BIOLUM_COLOUR))
clr = get_trait(TRAIT_BIOLUM_COLOUR)
- product.set_light(0.5, 0.1, 3, l_color = clr)
+ product.set_light(3, 0.5, l_color = clr)
//Handle spawning in living, mobile products (like dionaea).
if(istype(product,/mob/living))
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index 540bf2a8e8e4b..55cad3d73e222 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -157,7 +157,7 @@
// Apply colour and light from seed datum.
if(seed.get_trait(TRAIT_BIOLUM))
- set_light(0.5, 0.1, 3, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR))
+ set_light(3, 0.5, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR))
else
set_light(0)
diff --git a/code/modules/hydroponics/trays/tray_update_icons.dm b/code/modules/hydroponics/trays/tray_update_icons.dm
index 1344d374a5749..60fb1f53159ea 100644
--- a/code/modules/hydroponics/trays/tray_update_icons.dm
+++ b/code/modules/hydroponics/trays/tray_update_icons.dm
@@ -71,7 +71,7 @@
// Update bioluminescence.
if(seed && seed.get_trait(TRAIT_BIOLUM))
- set_light(0.5, 0.1, 3, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR))
+ set_light(3, 0.5, l_color = seed.get_trait(TRAIT_BIOLUM_COLOUR))
else
set_light(0)
diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm
index d8b1e3e639552..e4b03e969f841 100644
--- a/code/modules/integrated_electronics/subtypes/output.dm
+++ b/code/modules/integrated_electronics/subtypes/output.dm
@@ -83,7 +83,7 @@
/obj/item/integrated_circuit/output/light/proc/update_lighting()
if(light_toggled)
if(assembly)
- assembly.set_light(light_brightness, 1, 4, 2, light_rgb)
+ assembly.set_light(4, light_brightness, light_rgb)
else
if(assembly)
assembly.set_light(0)
diff --git a/code/modules/lighting/__lighting_docs.dm b/code/modules/lighting/__lighting_docs.dm
index 3816595f3c2d0..a742e1a98adb5 100644
--- a/code/modules/lighting/__lighting_docs.dm
+++ b/code/modules/lighting/__lighting_docs.dm
@@ -1,67 +1,46 @@
/*
-BS12 object based lighting system
-*/
+ -- O7 lighting system --
-/*
-Changes from tg DAL:
- - Lighting is done using objects instead of subareas.
- - Animated transitions. (newer tg DAL has this)
- - Full colours with mixing.
- - Support for lights on shuttles.
+ Documentation is present in most of the code files.
+ lighting_atom.dm -> procs/vars for tracking/managing lights attached to objects.
+ lighting_turf.dm -> procs/vars for managing lighting overlays bound to turfs, tracking lights affecting said turf, and getting information about the turf's light level.
+ lighting_corner.dm -> contains code for tracking per-corner lighting data.
+ lighting_source.dm -> contains actual light emitter datum & core lighting calculations. Directional lights and Z-lights are implemented here.
+ lighting_area.dm -> contains area vars/procs for managing an area's dynamic lighting state.
- - Code:
- - Instead of one flat luminosity var, light is represented by 3 atom vars:
- - light_range; diameter in tiles of the light, used for calculating falloff, Cannot be 1.
- - light_power; multiplier for the brightness of lights,
- - light_color; hex string representing the RGB colour of the light.
- - setLuminousity() is now set_light() and takes the three variables above.
- - Variables can be left as null to not update them.
- - set_opacity() is now set_opacity().
- - Areas have luminosity set to 1 permanently, no hard-lighting.
- - Objects inside other objects can have lights and they properly affect the turf. (flashlights)
- - area/master and area/list/related have been eviscerated since subareas aren't needed.
*/
/*
-Relevant vars/procs:
-
-atom: (lighting_atom.dm)
- - var/light_range; range in tiles of the light, used for calculating falloff
- - var/light_power; multiplier for the brightness of lights
- - var/light_color; hex string representing the RGB colour of the light
-
- - var/datum/light_source/light; light source datum for this atom, only present if light_range && light_power
- - var/list/light_sources; light sources in contents that are shining through this object, including this object
-
- - proc/set_light(l_max_bright, l_inner_range, l_outer_range, l_falloff_curve, l_color):
- - Sets light_range/power/color to non-null args and calls update_light()
- - proc/set_opacity(new_opacity):
- - Sets opacity to new_opacity.
- - If opacity has changed, call turf.reconsider_lights() to fix light occlusion
- - proc/update_light():
- - Updates the light var on this atom, deleting or creating as needed and calling .update()
-
-
-turf: (lighting_turf.dm)
- - var/list/affecting_lights; list of light sources that are shining onto this turf
-
- - proc/reconsider_lights():
- - Force all light sources shining onto this turf to update
-
- - proc/lighting_clear_overlays():
- - Delete (manual GC) all light overlays on this turf, used when changing turf to space
- - proc/lighting_build_overlays():
- - Create lighting overlays for this turf
-
-
-/atom/movable/lighting_overlay: (lighting_overlay.dm)
- - var/lum_r, var/lum_g, var/lum_b; lumcounts of each colour
- - var/needs_update; set on update_lumcount, checked by lighting process
-
- - var/xoffset, var/yoffset; (only present when using sub-tile overlays) fractional offset of this overlay in the tile
-
- - proc/update_lumcount(delta_r, delta_g, delta_b):
- - Change the lumcount vars and queue the overlay for update
- - proc/update_overlay()
- - Called by the lighting process to update the color of the overlay
-*/
\ No newline at end of file
+ Useful procs when using lights:
+
+/atom/proc/set_light(range, power, color, angle, no_update)
+ desc: Sets an atom's light emission. `set_light(FALSE)` will disable the light.
+ args:
+ range -> the range of the light. 1.4 is the lowest possible value here.
+ power -> the power (intensity) of the light. Generally should be 1 or lower. Optional.
+ color -> The hex string (#FFFFFF) color of the light. Optional.
+ angle -> The angle of the cone that the light should shine at (directional lighting). Behavior of lights over 180 degrees is undefined. Best to stick to using the LIGHT_ defines for this. Optional.
+ no_update -> if TRUE, the light will not be updated. Useful for when making several of these calls to the same object. Optional.
+
+/atom/proc/set_opacity(new_opacity)
+ desc: Sets an atom's opacity, updating affecting lights' visibility.
+ args:
+ new_opacity -> the new opacity value.
+
+/turf/proc/reconsider_lights()
+ desc: Cause all lights affecting this turf to recalculate visibility.
+ args: none
+
+/turf/proc/force_update_lights()
+ desc: Force all lights affecting this turf to regenerate. Slow, use reconsider_lights instead when possible.
+ args: none
+
+/turf/proc/get_avg_color()
+ desc: Gets the average color of this tile as a hexadecimal color string. Used by cameras.
+
+/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
+ desc: Gets the brightness of this tile. If not dynamically lit, always returns 0.5, otherwise returns the average brightness of all 4 corners, scaled between minlum and maxlum.
+ args:
+ minlum -> the low-bound of the scalar.
+ maxlum -> the high-bound of the scalar.
+*/
diff --git a/code/modules/lighting/_lighting_defs.dm b/code/modules/lighting/_lighting_defs.dm
new file mode 100644
index 0000000000000..f43ef762a6b3e
--- /dev/null
+++ b/code/modules/lighting/_lighting_defs.dm
@@ -0,0 +1,43 @@
+// This is the define used to calculate falloff.
+#define LUM_FALLOFF(Cx,Cy,Tx,Ty,HEIGHT) (1 - CLAMP01(sqrt(((Cx) - (Tx)) ** 2 + ((Cy) - (Ty)) ** 2 + HEIGHT) / max(1, actual_range)))
+
+// Macro that applies light to a new corner.
+// It is a macro in the interest of speed, yet not having to copy paste it.
+// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line.
+// As such this all gets counted as a single line.
+// The braces and semicolons are there to be able to do this on a single line.
+
+#define APPLY_CORNER(C,now,Tx,Ty,hdiff) \
+ . = LUM_FALLOFF(C.x, C.y, Tx, Ty, hdiff) * light_power; \
+ var/OLD = effect_str[C]; \
+ effect_str[C] = .; \
+ C.update_lumcount \
+ ( \
+ (. * lum_r) - (OLD * applied_lum_r), \
+ (. * lum_g) - (OLD * applied_lum_g), \
+ (. * lum_b) - (OLD * applied_lum_b), \
+ now \
+ );
+
+// I don't need to explain what this does, do I?
+#define REMOVE_CORNER(C,now) \
+ . = -effect_str[C]; \
+ C.update_lumcount \
+ ( \
+ . * applied_lum_r, \
+ . * applied_lum_g, \
+ . * applied_lum_b, \
+ now \
+ );
+
+// Converts two Z levels into a height value for LUM_FALLOFF or HEIGHT_FALLOFF.
+#define CALCULATE_CORNER_HEIGHT(ZA,ZB) (((max(ZA,ZB) - min(ZA,ZB)) + 1) * LIGHTING_HEIGHT * LIGHTING_Z_FACTOR)
+
+#define APPLY_CORNER_BY_HEIGHT(now) \
+ if (C.z != Sz) { \
+ corner_height = CALCULATE_CORNER_HEIGHT(C.z, Sz); \
+ } \
+ else { \
+ corner_height = LIGHTING_HEIGHT; \
+ } \
+ APPLY_CORNER(C, now, Sx, Sy, corner_height);
diff --git a/code/modules/lighting/darksight.dm b/code/modules/lighting/darksight.dm
new file mode 100644
index 0000000000000..a3fcd2747abeb
--- /dev/null
+++ b/code/modules/lighting/darksight.dm
@@ -0,0 +1,25 @@
+/obj/darksight
+ plane = LIGHTING_PLANE
+
+ icon = 'icons/mob/darksight.dmi'
+
+ screen_loc = "CENTER-7,CENTER-7"
+
+ blend_mode = BLEND_ADD
+ invisibility = INVISIBILITY_LIGHTING
+ alpha = 0 //By default make it transparent so mobs that don't update it also don't get it
+
+/obj/darksight/Initialize()
+ . = ..()
+ SetTransform((world.icon_size/DARKSIGHT_GRADIENT_SIZE) * 0.9)
+
+/obj/darksight/proc/sync(new_colour)
+ color = new_colour
+
+/mob
+ var/obj/darksight/darksight = null
+
+
+/mob/proc/change_light_colour(new_colour)
+ if(darksight)
+ darksight.sync(new_colour)
diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm
index 003d7bba6fef2..cdcd2c9c10a21 100644
--- a/code/modules/lighting/lighting_area.dm
+++ b/code/modules/lighting/lighting_area.dm
@@ -1,10 +1,27 @@
-/area/luminosity = TRUE
-/// Boolean. Whether or not the area should process dynamic lighting. Affects the value of `luminosity` during init and the lighting effects on turfs in the area.
+/area/luminosity = TRUE
/area/var/dynamic_lighting = TRUE
-/// String (One of `AREA_LIGHTING_*`). The light tone selection mode used for the area. See `code\__defines\lighting.dm` for possible values.
-/area/var/lighting_tone = AREA_LIGHTING_DEFAULT
+/area/var/lighting_tone = AREA_LIGHTING_DEFAULT
-/area/New()
- ..()
- if(dynamic_lighting)
+/area/Initialize()
+ . = ..()
+
+ if (dynamic_lighting)
luminosity = FALSE
+
+/area/proc/set_dynamic_lighting(new_dynamic_lighting = TRUE)
+ if (new_dynamic_lighting == dynamic_lighting)
+ return FALSE
+
+ dynamic_lighting = new_dynamic_lighting
+
+ if (new_dynamic_lighting)
+ for (var/turf/T in src)
+ if (T.dynamic_lighting)
+ T.lighting_build_overlay()
+
+ else
+ for (var/turf/T in src)
+ if (T.lighting_overlay)
+ T.lighting_clear_overlay()
+
+ return TRUE
diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm
index 52b63428bea91..d33781ed60799 100644
--- a/code/modules/lighting/lighting_atom.dm
+++ b/code/modules/lighting/lighting_atom.dm
@@ -1,98 +1,117 @@
-/// Float. Intensity of the light within the full brightness range. Value between 0 and 1. Do not modify directly. See `set_light()`.
-/atom/var/light_max_bright = 1.0
-/// Integer. Range, in tiles, the light is at full brightness. Do not modify directly. See `set_light()`.
-/atom/var/light_inner_range = 1
-/// Integer. Range, in tiles, where the light becomes darkness. Do not modify directly. See `set_light()`.
-/atom/var/light_outer_range = 0
-/// Integer. Adjusts curve for falloff gradient. Must be greater than 0. Do not modify directly. See `set_light()`.
-/atom/var/light_falloff_curve = 2
-/// String (Hexadecimal color code). The color of the light. Do not modify directly. See `set_light()`.
-/atom/var/light_color
+#define MINIMUM_USEFUL_LIGHT_RANGE 1.4
-/// The light source datum handling rendering of the light defined in the `light_*` vars on this atom. See `set_light()` and `update_light()`.
+ /// Intensity of the light.
+/atom/var/light_power = 1
+/// Range in tiles of the light.
+/atom/var/light_range = 0
+/// Hexadecimal RGB string representing the colour of the light.
+/atom/var/light_color
+/// The angle that the light's emission should be restricted to. null for omnidirectional.
+/atom/var/light_wedge
+/** These two vars let you override the default light offset detection (pixel_x/y).
+ * Useful for objects like light fixtures that aren't visually in the middle of the turf, but aren't offset either.
+ */
+/atom/var/light_offset_x
+/atom/var/light_offset_y
+/// Our light source. Don't fuck with this directly unless you have a good reason!
/atom/var/datum/light_source/light
-/// LAZYLIST of all light sources contained within the atom and its contents. Used to propagate updates whenever somehting, i.e. position, changes.
-/atom/var/list/light_sources
+/// Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list.
+/atom/var/list/light_source_multi
+/// Same as above - this is a shortcut to avoid allocating the above list if we can
+/atom/var/datum/light_source/light_source_solo
-// Nonsensical value for l_color default, so we can detect if it gets set to null.
+/// Nonsensical value for l_color default, so we can detect if it gets set to null.
#define NONSENSICAL_VALUE -99999
-#define DEFAULT_FALLOFF_CURVE (2)
/**
- * Sets the atom's light values and color. Calls `update_light()`.
+ * Sets the atom's light values and color. May call `update_light()`.
*
* **Parameters**:
- * - `l_max_bright` float (0 to 1) - Intensity of the light within the full brightness range. Value between 0 and 1. Applied to `light_max_bright`.
- * - `l_inner_range` integer - Range, in tiles, the light is at full brightness. Applied to `light_inner_range`.
- * - `l_outer_range` integer - Range, in tiles, where the light becomes darkness. Do not modify directly. Applied to `light_outer_range`.
- * - `l_falloff_curbe` integer (Default `NONSENSICAL_VALUE`) - Adjusts curve for falloff gradient. Must be greater than 0. Do not modify directly. Applied to `light_falloff_curve`.
- * - `l_color` color (Default `NONSENSICAL_VALUE`) - The color of the light. Applied to `light_color`.
+ * - `l_range` integer - Range in tiles of the light (Must be above `MINIMUM_USEFUL_LIGHT_RANGE`), light brightness will decay to 0 at this range. Applied to `light_range`. WARNING: Values over 32 are bound to cause lag
+ * - `l_power` float - The power (intensity) of the light. Generally should be 1 or lower but may be higher. Applied to `light_power`. Optional
+ * - `l_color` color (Default `NONSENSICAL_VALUE`) - The color of the light. Applied to `light_color`. Optional
+ * - `angle` integer (Default `NONSENSICAL_VALUE`) - The angle of the cone that the light should shine at (directional lighting). Behavior of lights over 180 degrees is undefined. Best to stick to using the LIGHT_ defines for this. Optional.
+ * - `no_update` boolean (Default `FALSE`) -if TRUE, `update_light()` will not be called. Useful for when making several of these calls to the same object. Optional.
*
- * Returns boolean. Whether or not the light was actually changed.
+ * Returns null
*/
-/atom/proc/set_light(l_max_bright, l_inner_range, l_outer_range, l_falloff_curve = NONSENSICAL_VALUE, l_color = NONSENSICAL_VALUE)
- . = 0 //make it less costly if nothing's changed
-
- if(l_max_bright != null && l_max_bright != light_max_bright)
- light_max_bright = l_max_bright
- . = 1
- if(l_outer_range != null && l_outer_range != light_outer_range)
- light_outer_range = l_outer_range
- . = 1
- if(l_inner_range != null && l_inner_range != light_inner_range)
- if(light_inner_range >= light_outer_range)
- light_inner_range = light_outer_range / 4
- else
- light_inner_range = l_inner_range
- . = 1
- if(l_falloff_curve != NONSENSICAL_VALUE)
- if(!l_falloff_curve || l_falloff_curve <= 0)
- light_falloff_curve = DEFAULT_FALLOFF_CURVE
- if(l_falloff_curve != light_falloff_curve)
- light_falloff_curve = l_falloff_curve
- . = 1
- if(l_color != NONSENSICAL_VALUE && l_color != light_color)
+/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, angle = NONSENSICAL_VALUE, no_update = FALSE)
+ if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
+ l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4
+ if (l_power != null)
+ light_power = l_power
+
+ if (l_range != null)
+ light_range = l_range
+
+ if (l_color != NONSENSICAL_VALUE)
light_color = l_color
- . = 1
- if(.) update_light()
+ if (angle != NONSENSICAL_VALUE)
+ light_wedge = angle
+
+ if (no_update)
+ return
+
+ update_light()
#undef NONSENSICAL_VALUE
-#undef DEFAULT_FALLOFF_CURVE
/**
- * Updates the atom's light source datum. This is automatically called by `set_light()`.
+ * Will update the light (duh).
+ *
+ * Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf...
*/
/atom/proc/update_light()
- set waitfor = FALSE
-
- if(!light_max_bright || !light_outer_range || light_max_bright > 1)
- if(light)
- light.destroy()
- light = null
- if(light_max_bright > 1)
- light_max_bright = 1
- CRASH("Attempted to call update_light() on atom [src] \ref[src] with a light_max_bright value greater than one")
+ if (QDELING(src))
+ return
+
+ if (!light_power || !light_range) // We won't emit light anyways, destroy the light source.
+ QDEL_NULL(light)
else
- if(!istype(loc, /atom/movable))
+ if (!istype(loc, /atom/movable)) // We choose what atom should be the top atom of the light here.
. = src
else
. = loc
- if(light)
+ if (light)
light.update(.)
else
light = new /datum/light_source(src, .)
-/atom/Destroy()
- if(light)
- light.destroy()
- light = null
- return ..()
-/atom/set_opacity()
+// Should always be used to change the opacity of an atom.
+// It notifies (potentially) affected light sources so they can update (if needed).
+/atom/set_opacity(new_opacity)
+ . = ..()
+ if (!.)
+ return
+
+ opacity = new_opacity
+ var/turf/T = loc
+ if (!isturf(T))
+ return
+
+ if (new_opacity == TRUE)
+ T.has_opaque_atom = TRUE
+ T.reconsider_lights()
+ #ifdef AO_USE_LIGHTING_OPACITY
+ T.regenerate_ao()
+ #endif
+ else
+ var/old_has_opaque_atom = T.has_opaque_atom
+ T.recalc_atom_opacity()
+ if (old_has_opaque_atom != T.has_opaque_atom)
+ T.reconsider_lights()
+
+/atom/movable/forceMove()
. = ..()
- if(.)
- var/turf/T = loc
- if(istype(T))
- T.RecalculateOpacity()
+
+ if (light_source_solo)
+ light_source_solo.source_atom.update_light()
+ else if (light_source_multi)
+ var/datum/light_source/L
+ var/thing
+ for (thing in light_source_multi)
+ L = thing
+ L.source_atom.update_light()
diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm
index 225b9d4a560eb..bd2ace158a9c0 100644
--- a/code/modules/lighting/lighting_corner.dm
+++ b/code/modules/lighting/lighting_corner.dm
@@ -1,4 +1,3 @@
-var/global/total_lighting_corners = 0
var/global/datum/lighting_corner/dummy/dummy_lighting_corner = new
// Because we can control each corner of every lighting overlay.
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
@@ -7,35 +6,75 @@ var/global/datum/lighting_corner/dummy/dummy_lighting_corner = new
// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list.
var/global/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)
+// This is the reverse of the above - the position in the array is a dir. Update this if the above changes.
+var/global/list/REVERSE_LIGHTING_CORNER_DIAGONAL = list(0, 0, 0, 0, 3, 4, 0, 0, 2, 1)
+
/datum/lighting_corner
- var/list/turf/masters = list()
- var/list/datum/light_source/affecting = list() // Light sources affecting us.
+ // t1 through t4 are our masters, in no particular order.
+ // They are split into vars like this in the interest of reducing memory usage.
+ // tX is the turf itself, tXi is the index of this corner in that turf's corners list.
+ var/turf/t1
+ var/t1i
+ var/turf/t2
+ var/t2i
+ var/turf/t3
+ var/t3i
+ var/turf/t4
+ var/t4i
+
+ var/list/datum/light_source/affecting // Light sources affecting us.
var/active = FALSE // TRUE if one of our masters has dynamic lighting.
- var/x = 0
- var/y = 0
- var/z = 0
+ var/x = 0
+ var/y = 0
+ var/z = 0
+
+ // Our own intensity, from lights directly shining on us.
+ var/self_r = 0
+ var/self_g = 0
+ var/self_b = 0
+
+ // The intensity we're inheriting from the turf below us, if we're a Z-turf.
+ var/below_r = 0
+ var/below_g = 0
+ var/below_b = 0
+
+ // Ambient turf lighting that's not inherited from a light source. These are updated as absolute values.
+ var/ambient_r = 0
+ var/ambient_g = 0
+ var/ambient_b = 0
- var/lum_r = 0
- var/lum_g = 0
- var/lum_b = 0
+ // The turf above us' ambient
+ var/above_ambient_r = 0
+ var/above_ambient_g = 0
+ var/above_ambient_b = 0
+
+ // The final intensity, all things considered.
+ var/apparent_r = 0
+ var/apparent_g = 0
+ var/apparent_b = 0
var/needs_update = FALSE
- var/cache_r = LIGHTING_SOFT_THRESHOLD
- var/cache_g = LIGHTING_SOFT_THRESHOLD
- var/cache_b = LIGHTING_SOFT_THRESHOLD
+ var/cache_r = 0
+ var/cache_g = 0
+ var/cache_b = 0
var/cache_mx = 0
+ /// Used for planet lighting. Probably needs a better system to prevent over-updating when not needed at some point.
var/update_gen = 0
-/datum/lighting_corner/New(turf/new_turf, diagonal)
- . = ..()
+/datum/lighting_corner/New(turf/new_turf, diagonal, oi)
+ SSlighting.total_lighting_corners += 1
- total_lighting_corners++
+ var/has_ambience = FALSE
- masters[new_turf] = turn(diagonal, 180)
+ t1 = new_turf
z = new_turf.z
+ t1i = oi
+
+ if (TURF_IS_AMBIENT_LIT_UNSAFE(new_turf))
+ has_ambience = TRUE
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one.
@@ -47,88 +86,320 @@ var/global/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST,
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
var/turf/T
- var/i
+
// Diagonal one is easy.
T = get_step(new_turf, diagonal)
if (T) // In case we're on the map's border.
if (!T.corners)
- T.corners = list(null, null, null, null)
+ T.corners = new(4)
- masters[T] = diagonal
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
- T.corners[i] = src
+ t2 = T
+ t2i = REVERSE_LIGHTING_CORNER_DIAGONAL[diagonal]
+ T.corners[t2i] = src
+ if (TURF_IS_AMBIENT_LIT_UNSAFE(T))
+ has_ambience = TRUE
// Now the horizontal one.
T = get_step(new_turf, horizontal)
if (T) // Ditto.
if (!T.corners)
- T.corners = list(null, null, null, null)
+ T.corners = new(4)
- masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
- T.corners[i] = src
+ t3 = T
+ t3i = REVERSE_LIGHTING_CORNER_DIAGONAL[((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)] // Get the dir based on coordinates.
+ T.corners[t3i] = src
+ if (TURF_IS_AMBIENT_LIT_UNSAFE(T))
+ has_ambience = TRUE
// And finally the vertical one.
T = get_step(new_turf, vertical)
if (T)
if (!T.corners)
- T.corners = list(null, null, null, null)
+ T.corners = new(4)
- masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates.
- i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180))
- T.corners[i] = src
+ t4 = T
+ t4i = REVERSE_LIGHTING_CORNER_DIAGONAL[((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)] // Get the dir based on coordinates.
+ T.corners[t4i] = src
+ if (TURF_IS_AMBIENT_LIT_UNSAFE(T))
+ has_ambience = TRUE
update_active()
+ if (has_ambience)
+ init_ambient()
+
+#define OVERLAY_PRESENT(T) (T && T.lighting_overlay)
/datum/lighting_corner/proc/update_active()
active = FALSE
- for (var/turf/T in masters)
- if (T.lighting_overlay)
- active = TRUE
+
+ if (OVERLAY_PRESENT(t1) || OVERLAY_PRESENT(t2) || OVERLAY_PRESENT(t3) || OVERLAY_PRESENT(t4))
+ active = TRUE
+
+#undef OVERLAY_PRESENT
+
+#define GET_ABOVE(T) (HasAbove(T:z) ? get_step(T, UP) : null)
+#define GET_BELOW(T) (HasBelow(T:z) ? get_step(T, DOWN) : null)
+
+#define UPDATE_APPARENT(T, CH) T.apparent_##CH = T.self_##CH + T.below_##CH + T.ambient_##CH + T.above_ambient_##CH
+
+/datum/lighting_corner/proc/init_ambient()
+ var/sum_r = 0
+ var/sum_g = 0
+ var/sum_b = 0
+
+ var/turf/T
+ for (var/i in 1 to 4)
+ // this is ugly as fuck, but it's still more legible than doing this with a macro
+ switch (i)
+ if (1) T = t1
+ if (2) T = t2
+ if (3) T = t3
+ if (4) T = t4
+
+ if (!T || !T.ambient_light)
+ continue
+
+ var/list/parts = rgb2num(T.ambient_light)
+
+ sum_r += (parts[1] / 255) * T.ambient_light_multiplier
+ sum_g += (parts[2] / 255) * T.ambient_light_multiplier
+ sum_b += (parts[3] / 255) * T.ambient_light_multiplier
+
+ sum_r /= 4
+ sum_g /= 4
+ sum_b /= 4
+
+ update_ambient_lumcount(sum_r, sum_g, sum_b)
// God that was a mess, now to do the rest of the corner code! Hooray!
-/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b)
- lum_r += delta_r
- lum_g += delta_g
- lum_b += delta_b
+/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b, now = FALSE)
+ if (!(delta_r + delta_g + delta_b))
+ return
+
+ self_r += delta_r
+ self_g += delta_g
+ self_b += delta_b
+
+ UPDATE_APPARENT(src, r)
+ UPDATE_APPARENT(src, g)
+ UPDATE_APPARENT(src, b)
+
+ var/turf/T
+ var/Ti
+ // Grab the first master that's a Z-turf, if one exists.
+ if ((T = t1?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t1i
+ else if ((T = t2?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t2i
+ else if ((T = t3?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t3i
+ else if ((T = t4?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t4i
+ else // Nothing above us that cares about below light.
+ T = null
+
+ if (TURF_IS_DYNAMICALLY_LIT(T))
+ if (!T.corners || !T.corners[Ti])
+ T.generate_missing_corners()
+ var/datum/lighting_corner/above = T.corners[Ti]
+ above.update_below_lumcount(delta_r, delta_g, delta_b, now)
+
+ // This needs to be down here instead of the above if so the lum values are properly updated.
+ if (needs_update)
+ return
- if (!needs_update)
+ if (now)
+ update_overlays(TRUE)
+ else
needs_update = TRUE
SSlighting.corner_queue += src
-/datum/lighting_corner/proc/update_overlays()
- // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually.
- var/lum_r = src.lum_r > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_r) : src.lum_r
- var/lum_g = src.lum_g > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_g) : src.lum_g
- var/lum_b = src.lum_b > 0 ? LIGHTING_MULT_FACTOR * sqrt(src.lum_b) : src.lum_b
+/datum/lighting_corner/proc/update_below_lumcount(delta_r, delta_g, delta_b, now = FALSE)
+ if (!(delta_r + delta_g + delta_b))
+ return
+
+ below_r += delta_r
+ below_g += delta_g
+ below_b += delta_b
+
+ UPDATE_APPARENT(src, r)
+ UPDATE_APPARENT(src, g)
+ UPDATE_APPARENT(src, b)
+
+ // This needs to be down here instead of the above if so the lum values are properly updated.
+ if (needs_update)
+ return
+
+ if (!now)
+ needs_update = TRUE
+ SSlighting.corner_queue += src
+ else
+ update_overlays(TRUE)
+
+//So, a turf with 4 corners needs to reset all 4 of those to 0, then we need to take turf below and tell its corners to rebuild
+// Probably better ways to do this
+/datum/lighting_corner/proc/clear_below_lumcount()
- var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1.
+ if(!(below_r || below_b || below_g))
+ return
+
+ below_r = 0
+ below_g = 0
+ below_b = 0
+
+ UPDATE_APPARENT(src, r)
+ UPDATE_APPARENT(src, g)
+ UPDATE_APPARENT(src, b)
+
+ if (needs_update)
+ return
+
+ needs_update = TRUE
+ SSlighting.corner_queue += src
+
+/datum/lighting_corner/proc/set_below_lumcount(_r, _g, _b)
+
+ below_r = _r
+ below_g = _g
+ below_b = _b
+
+ UPDATE_APPARENT(src, r)
+ UPDATE_APPARENT(src, g)
+ UPDATE_APPARENT(src, b)
+
+ if (needs_update)
+ return
+
+ needs_update = TRUE
+ SSlighting.corner_queue += src
+
+/datum/lighting_corner/proc/rebuild_above_below_lumcount()
+ //Destroy current state and rebuild it!
+ var/turf/T
+ var/Ti
+ // Grab the first master that's a Z-turf, if one exists.
+ if ((T = t1?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t1i
+ else if ((T = t2?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t2i
+ else if ((T = t3?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t3i
+ else if ((T = t4?.above) && (T.z_flags & ZM_ALLOW_LIGHTING))
+ Ti = t4i
+ else // Nothing above us that cares about below light.
+ T = null
+
+ if (TURF_IS_DYNAMICALLY_LIT(T))
+ if (!T.corners || !T.corners[Ti])
+ T.generate_missing_corners()
+ var/datum/lighting_corner/above = T.corners[Ti]
+ above.set_below_lumcount(self_r, self_g, self_b)
+
+/datum/lighting_corner/proc/update_ambient_lumcount(delta_r, delta_g, delta_b, skip_update = FALSE)
+ ambient_r += delta_r
+ ambient_g += delta_g
+ ambient_b += delta_b
+
+ UPDATE_APPARENT(src, r)
+ UPDATE_APPARENT(src, g)
+ UPDATE_APPARENT(src, b)
+
+ var/turf/T
+ var/Ti
+
+ if (t1)
+ T = t1
+ Ti = t1i
+ else if (t2)
+ T = t2
+ Ti = t2i
+ else if (t3)
+ T = t3
+ Ti = t3i
+ else if (t4)
+ T = t4
+ Ti = t4i
+ else
+ // This should be impossible to reach -- how do we exist without at least one master turf?
+ CRASH("Corner has no masters!")
+
+ var/datum/lighting_corner/below = src
+
+ var/turf/lasT
+
+ // We init before Z-Mimic, cannot rely on above/below.
+ while ((lasT = T) && (T = T.below || GET_BELOW(T)) && (lasT.z_flags & ZM_ALLOW_LIGHTING) && TURF_IS_DYNAMICALLY_LIT_UNSAFE(T))
+ T.ambient_has_indirect = TRUE
+
+ if (!T.corners || !T.corners[Ti])
+ T.generate_missing_corners()
+
+ ASSERT(length(T.corners))
+
+ below = T.corners[Ti]
+ below.above_ambient_r += delta_r
+ below.above_ambient_g += delta_g
+ below.above_ambient_b += delta_b
+
+ UPDATE_APPARENT(below, r)
+ UPDATE_APPARENT(below, g)
+ UPDATE_APPARENT(below, b)
+
+ if (!skip_update && !below.needs_update)
+ below.needs_update = TRUE
+ SSlighting.corner_queue += below
+
+ if (needs_update || skip_update)
+ return
+
+ // Always queue for this, not important enough to hit the synchronous path.
+ needs_update = TRUE
+ SSlighting.corner_queue += src
+
+#undef UPDATE_APPARENT
+
+/datum/lighting_corner/proc/update_overlays(now = FALSE)
+ var/lr = apparent_r
+ var/lg = apparent_g
+ var/lb = apparent_b
+
+ // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually.
+ var/mx = max(lr, lg, lb) // Scale it so 1 is the strongest lum, if it is above 1.
. = 1 // factor
if (mx > 1)
. = 1 / mx
- #if LIGHTING_SOFT_THRESHOLD != 0
- else if (mx < LIGHTING_SOFT_THRESHOLD)
- . = 0 // 0 means soft lighting.
-
- cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
- cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
- cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
- #else
- cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE)
- cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE)
- cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE)
- #endif
+ cache_r = round(lr * ., LIGHTING_ROUND_VALUE)
+ cache_g = round(lg * ., LIGHTING_ROUND_VALUE)
+ cache_b = round(lb * ., LIGHTING_ROUND_VALUE)
+
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
- for (var/TT in masters)
- var/turf/T = TT
- if (T.lighting_overlay)
- if (!T.lighting_overlay.needs_update)
- T.lighting_overlay.needs_update = TRUE
- SSlighting.overlay_queue += T.lighting_overlay
+ var/turf/T
+ for (var/i in 1 to 4)
+ // this is ugly as fuck, but it's still more legible than doing this with a macro
+ switch (i)
+ if (1) T = t1
+ if (2) T = t2
+ if (3) T = t3
+ if (4) T = t4
+
+ var/atom/movable/lighting_overlay/Ov
+ if (T && (Ov = T.lighting_overlay))
+ if (now)
+ Ov.update_overlay()
+ else if (!Ov.needs_update)
+ Ov.needs_update = TRUE
+ SSlighting.overlay_queue += Ov
+
+/datum/lighting_corner/Destroy(force = FALSE)
+ //PRINT_STACK_TRACE("Someone [force ? "force-" : ""]deleted a lighting corner.")
+ if (!force)
+ return QDEL_HINT_LETMELIVE
+ SSlighting.total_lighting_corners -= 1
+ return ..()
/datum/lighting_corner/dummy/New()
return
diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm
index ec09a9930ac94..55b3837145f77 100644
--- a/code/modules/lighting/lighting_overlay.dm
+++ b/code/modules/lighting/lighting_overlay.dm
@@ -1,71 +1,84 @@
-var/global/total_lighting_overlays = 0
/atom/movable/lighting_overlay
- name = ""
+ name = ""
+ anchored = TRUE
+ icon = LIGHTING_ICON
+ icon_state = LIGHTING_BASE_ICON_STATE
+ color = LIGHTING_BASE_MATRIX
mouse_opacity = 0
- simulated = FALSE
- anchored = TRUE
- icon = LIGHTING_ICON
- plane = LIGHTING_PLANE
- layer = LIGHTING_LAYER
- invisibility = INVISIBILITY_LIGHTING
- color = LIGHTING_BASE_MATRIX
- icon_state = "light1"
- blend_mode = BLEND_OVERLAY
-
- appearance_flags = DEFAULT_APPEARANCE_FLAGS
-
- var/lum_r = 0
- var/lum_g = 0
- var/lum_b = 0
+ layer = LIGHTING_LAYER
+ plane = LIGHTING_PLANE
+ invisibility = INVISIBILITY_LIGHTING
+ simulated = FALSE
+ blend_mode = BLEND_OVERLAY
var/needs_update = FALSE
-/atom/movable/lighting_overlay/Initialize(mapload, no_update)
- var/turf/turf = loc
- if (!turf.dynamic_lighting)
- atom_flags |= ATOM_FLAG_INITIALIZED
- return INITIALIZE_HINT_QDEL
+ #if WORLD_ICON_SIZE != 32
+ transform = matrix(WORLD_ICON_SIZE / 32, 0, (WORLD_ICON_SIZE - 32) / 2, 0, WORLD_ICON_SIZE / 32, (WORLD_ICON_SIZE - 32) / 2)
+ #endif
+
+/atom/movable/lighting_overlay/Initialize(mapload, update_now = FALSE)
. = ..()
- verbs.Cut()
- total_lighting_overlays++
- turf.lighting_overlay = src
- turf.luminosity = 0
- if (no_update)
- return
- update_overlay()
+ atom_flags |= ATOM_FLAG_INITIALIZED
+ SSlighting.total_lighting_overlays += 1
+
+ var/turf/T = loc // If this runtimes atleast we'll know what's creating overlays in things that aren't turfs.
+ T.lighting_overlay = src
+ T.luminosity = 0
+
+ if (T.corners && length(T.corners))
+ for (var/datum/lighting_corner/C in T.corners)
+ C.active = TRUE
+
+ if (update_now)
+ update_overlay()
+ needs_update = FALSE
+ else
+ needs_update = TRUE
+ SSlighting.overlay_queue += src
+
+/atom/movable/lighting_overlay/Destroy(force = FALSE)
+ if (!force)
+ return QDEL_HINT_LETMELIVE // STOP DELETING ME
+ SSlighting.total_lighting_overlays -= 1
+
+ var/turf/T = loc
+ if (istype(T))
+ T.lighting_overlay = null
+ T.luminosity = 1
+
+ return ..()
+
+// This is a macro PURELY so that the if below is actually readable.
+#define ALL_EQUAL ((rr == gr && gr == br && br == ar) && (rg == gg && gg == bg && bg == ag) && (rb == gb && gb == bb && bb == ab))
/atom/movable/lighting_overlay/proc/update_overlay()
- set waitfor = FALSE
var/turf/T = loc
+ if (!isturf(T)) // Erm...
+ if (loc)
+ warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc], [loc.type]) in update_overlay() and got deleted!")
- if(!istype(T))
- if(loc)
- log_debug("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!")
else
- log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!")
- qdel(src)
- return
- if(!T.dynamic_lighting)
- qdel(src)
- return
+ warning("A lighting overlay realised it was in nullspace in update_overlay() and got deleted!")
- // To the future coder who sees this and thinks
- // "Why didn't he just use a loop?"
- // Well my man, it's because the loop performed like shit.
- // And there's no way to improve it because
- // without a loop you can make the list all at once which is the fastest you're gonna get.
- // Oh it's also shorter line wise.
- // Including with these comments.
+ qdel(src, TRUE)
+ return
// See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
- // No I seriously cannot think of a more efficient method, fuck off Comic.
- var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner
- var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner
- var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner
- var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner
+ var/list/corners = T.corners
+ var/datum/lighting_corner/cr = dummy_lighting_corner
+ var/datum/lighting_corner/cg = dummy_lighting_corner
+ var/datum/lighting_corner/cb = dummy_lighting_corner
+ var/datum/lighting_corner/ca = dummy_lighting_corner
+ if (corners)
+ cr = corners[3] || dummy_lighting_corner
+ cg = corners[2] || dummy_lighting_corner
+ cb = corners[4] || dummy_lighting_corner
+ ca = corners[1] || dummy_lighting_corner
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
+ luminosity = max > 0
var/rr = cr.cache_r
var/rg = cr.cache_g
@@ -83,61 +96,70 @@ var/global/total_lighting_overlays = 0
var/ag = ca.cache_g
var/ab = ca.cache_b
- #if LIGHTING_SOFT_THRESHOLD != 0
- var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
- #else
- // Because of floating points, it won't even be a flat 0.
- // This number is mostly arbitrary.
- var/set_luminosity = max > 1e-6
- #endif
-
- if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8))
- //anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
- icon_state = "transparent"
+ if(rr + rg + rb + gr + gg + gb + br + bg + bb + ar + ag + ab >= 12)
+ icon_state = LIGHTING_TRANSPARENT_ICON_STATE
color = null
- else if(!set_luminosity)
- icon_state = LIGHTING_ICON_STATE_DARK
+ else if (!luminosity)
+ icon_state = LIGHTING_DARKNESS_ICON_STATE
+ color = null
+ else if (rr == LIGHTING_DEFAULT_TUBE_R && rg == LIGHTING_DEFAULT_TUBE_G && rb == LIGHTING_DEFAULT_TUBE_B && ALL_EQUAL)
+ icon_state = LIGHTING_STATION_ICON_STATE
color = null
else
- icon_state = null
- color = list(
- -rr, -rg, -rb, 00,
- -gr, -gg, -gb, 00,
- -br, -bg, -bb, 00,
- -ar, -ag, -ab, 00,
- 01, 01, 01, 01
- )
-
- luminosity = set_luminosity
- // if (T.above && T.above.shadower)
- // T.above.shadower.copy_lighting(src)
+ icon_state = LIGHTING_BASE_ICON_STATE
+ if (islist(color))
+ // Does this even save a list alloc?
+ var/list/c_list = color
+ c_list[CL_MATRIX_RR] = rr
+ c_list[CL_MATRIX_RG] = rg
+ c_list[CL_MATRIX_RB] = rb
+ c_list[CL_MATRIX_GR] = gr
+ c_list[CL_MATRIX_GG] = gg
+ c_list[CL_MATRIX_GB] = gb
+ c_list[CL_MATRIX_BR] = br
+ c_list[CL_MATRIX_BG] = bg
+ c_list[CL_MATRIX_BB] = bb
+ c_list[CL_MATRIX_AR] = ar
+ c_list[CL_MATRIX_AG] = ag
+ c_list[CL_MATRIX_AB] = ab
+ color = c_list
+ else
+ color = list(
+ rr, rg, rb, 0,
+ gr, gg, gb, 0,
+ br, bg, bb, 0,
+ ar, ag, ab, 0,
+ 0, 0, 0, 1
+ )
+
+ // If there's a Z-turf above us, update its shadower.
+ if (T.above)
+ if (T.above.shadower)
+ T.above.shadower.copy_lighting(src)
+ else
+ T.above.update_mimic()
+
+#undef ALL_EQUAL
// Variety of overrides so the overlays don't get affected by weird things.
-/atom/movable/lighting_overlay/ex_act()
+
+/atom/movable/lighting_overlay/ex_act(severity)
+ SHOULD_CALL_PARENT(FALSE)
return
-/atom/movable/lighting_overlay/singularity_pull()
+/atom/movable/lighting_overlay/singularity_act()
return
-/atom/movable/lighting_overlay/Destroy()
- total_lighting_overlays--
- SSlighting.overlay_queue -= src
+/atom/movable/lighting_overlay/singularity_pull()
+ return
- var/turf/T = loc
- if(istype(T))
- T.lighting_overlay = null
+/atom/movable/lighting_overlay/singuloCanEat()
+ return FALSE
- . = ..()
+/atom/movable/lighting_overlay/can_fall()
+ return FALSE
-/atom/movable/lighting_overlay/forceMove()
- //should never move
- //In theory... except when getting deleted :C
+// Override here to prevent things accidentally moving around overlays.
+/atom/movable/lighting_overlay/forceMove(atom/destination, harderforce = FALSE)
if(QDELING(src))
- return ..()
- return 0
-
-/atom/movable/lighting_overlay/Move()
- return 0
-
-/atom/movable/lighting_overlay/throw_at()
- return 0
+ . = ..()
diff --git a/code/modules/lighting/lighting_planemaster.dm b/code/modules/lighting/lighting_planemaster.dm
deleted file mode 100644
index 7d82972cbfc42..0000000000000
--- a/code/modules/lighting/lighting_planemaster.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-/obj/lighting_general
- plane = LIGHTING_PLANE
- screen_loc = "8,8"
-
- icon = LIGHTING_ICON
- icon_state = LIGHTING_ICON_STATE_DARK
-
- color = "#ffffff"
-
- blend_mode = BLEND_MULTIPLY
-
-/obj/lighting_general/Initialize()
- . = ..()
- SetTransform(scale = world.view * 2.2)
-
-/obj/lighting_general/proc/sync(new_colour)
- color = new_colour
-
-/mob
- var/obj/lighting_general/l_general
-
-
-/mob/proc/change_light_colour(new_colour)
- if(l_general)
- l_general.sync(new_colour)
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index 0f9cdeafa6d56..48fcd6b5ae284 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -1,17 +1,16 @@
-var/global/total_lighting_sources = 0
// This is where the fun begins.
// These are the main datums that emit light.
/datum/light_source
- var/atom/top_atom // The atom we're emitting light from(for example a mob if we're from a flashlight that's being held).
+ var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/source_atom // The atom that we belong to.
- var/turf/source_turf // The turf under the above.
- var/light_max_bright = 1 // intensity of the light within the full brightness range. Value between 0 and 1
- var/light_inner_range = 0 // range, in tiles, the light is at full brightness
- var/light_outer_range = 0 // range, in tiles, where the light becomes darkness
- var/light_falloff_curve // adjusts curve for falloff gradient
- var/light_color // The colour of the light, string, decomposed by parse_light_color()
+ var/turf/source_turf // The turf under the above.
+ var/turf/pixel_turf // The turf the top_atom _appears_ to be on
+ var/light_power // Intensity of the emitter light.
+ var/light_range // The range of the emitted light.
+ var/light_color // The colour of the light, string, decomposed by parse_light_color()
+ var/light_angle // The light's emission angle, in degrees.
// Variables for keeping track of the colour.
var/lum_r
@@ -23,310 +22,430 @@ var/global/total_lighting_sources = 0
var/applied_lum_g
var/applied_lum_b
+ // Variables used to keep track of the atom's angle.
+ var/limit_a_x // The first test point's X coord for the cone.
+ var/limit_a_y // The first test point's Y coord for the cone.
+ var/limit_b_x // The second test point's X coord for the cone.
+ var/limit_b_y // The second test point's Y coord for the cone.
+ var/cached_origin_x // The last known X coord of the origin.
+ var/cached_origin_y // The last known Y coord of the origin.
+ var/old_direction // The last known direction of the origin.
+ var/test_x_offset // How much the X coord should be offset due to direction.
+ var/test_y_offset // How much the Y coord should be offset due to direction.
+ var/facing_opaque = FALSE
+
var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
var/list/turf/affecting_turfs
var/applied = FALSE // Whether we have applied our light yet or not.
- var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became(in)visible to us.
- var/needs_update // Whether we are queued for an update.
- var/destroyed // Whether we are destroyed and need to stop emitting light.
- var/force_update
+ var/needs_update = LIGHTING_NO_UPDATE
+
+// This macro will only offset up to 1 tile, but anything with a greater offset is an outlier and probably should handle its own lighting offsets.
+// Anything pixelshifted 16px or more will be considered on the next tile.
+#define GET_APPROXIMATE_PIXEL_DIR(PX, PY) ((!(PX) ? 0 : (((PX) >= 16 ? EAST : ((PX) <= -16 ? WEST : 0)))) | (!(PY) ? 0 : ((PY) >= 16 ? NORTH : ((PY) <= -16 ? SOUTH : 0))))
+#define UPDATE_APPROXIMATE_PIXEL_TURF var/px = top_atom.light_offset_x || top_atom.pixel_x; var/py = top_atom.light_offset_y || top_atom.pixel_y; var/_dir = GET_APPROXIMATE_PIXEL_DIR(px, py); pixel_turf = _dir ? (get_step(source_turf, _dir) || source_turf) : source_turf
+
+// These macros are for dealing with the multi/solo split.
+#define ADD_SOURCE(TARGET) if (!TARGET.light_source_multi && !TARGET.light_source_solo) { TARGET.light_source_solo = src; } else if (TARGET.light_source_solo) { TARGET.light_source_multi = list(TARGET.light_source_solo, src); TARGET.light_source_solo = null; } else { TARGET.light_source_multi += src }
+#define REMOVE_SOURCE(TARGET) if (TARGET.light_source_solo == src) { TARGET.light_source_solo = null } else if (TARGET.light_source_multi) { TARGET.light_source_multi -= src; if (length(TARGET.light_source_multi) == 1) { TARGET.light_source_solo = TARGET.light_source_multi[1]; TARGET.light_source_multi = null; } }
/datum/light_source/New(atom/owner, atom/top)
- total_lighting_sources++
+ SSlighting.total_lighting_sources += 1
source_atom = owner // Set our new owner.
- if(!source_atom.light_sources)
- source_atom.light_sources = list()
- source_atom.light_sources += src // Add us to the lights of our owner.
- top_atom = top
- if(top_atom != source_atom)
- if(!top.light_sources)
- top.light_sources = list()
+ ADD_SOURCE(source_atom)
- top_atom.light_sources += src
+ top_atom = top
+ if (top_atom != source_atom)
+ ADD_SOURCE(top_atom)
source_turf = top_atom
- light_max_bright = source_atom.light_max_bright
- light_inner_range = source_atom.light_inner_range
- light_outer_range = source_atom.light_outer_range
- light_falloff_curve = source_atom.light_falloff_curve
+ UPDATE_APPROXIMATE_PIXEL_TURF
+ light_power = source_atom.light_power
+ light_range = source_atom.light_range
light_color = source_atom.light_color
+ light_angle = source_atom.light_wedge
parse_light_color()
- effect_str = list()
- affecting_turfs = list()
-
update()
-
- return ..()
-
-/* lighting debugging verb
-/mob/verb/self_light()
- set name = "set self light"
- set category = "Light"
- var/v1 = input(usr, "Enter max bright", "max bright", 1) as num|null
- var/v2 = input(usr, "Enter inner range", "inner range", 0.1) as num|null
- var/v3 = input(usr, "Enter outer range", "outer range", 4) as num|null
- var/v4 = input(usr, "Enter curve", "curve", 2) as num|null
- set_light(v1, v2, v3, v4, "#0066ff")
-*/
-
// Kill ourselves.
-/datum/light_source/proc/destroy()
- total_lighting_sources--
- destroyed = TRUE
- force_update()
- if(source_atom && source_atom.light_sources)
- source_atom.light_sources -= src
-
- if(top_atom && top_atom.light_sources)
- top_atom.light_sources -= src
-
-// Call it dirty, I don't care.
-// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates.
-// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a() macro that has no arguments :|.
-#define effect_update(BYOND) \
- if(!needs_update) \
- { \
- SSlighting.light_queue += src; \
- needs_update = TRUE; \
+/datum/light_source/Destroy(force)
+ SSlighting.total_lighting_sources -= 1
+
+ remove_lum()
+ if (source_atom)
+ REMOVE_SOURCE(source_atom)
+
+ if (top_atom)
+ REMOVE_SOURCE(top_atom)
+
+ . = ..()
+ if (!force)
+ return QDEL_HINT_IWILLGC
+
+#ifdef USE_INTELLIGENT_LIGHTING_UPDATES
+// Picks either scheduled or instant updates based on current server load.
+#define INTELLIGENT_UPDATE(level) \
+ var/_should_update = needs_update == LIGHTING_NO_UPDATE; \
+ if (needs_update < level) { \
+ needs_update = level; \
+ } \
+ if (_should_update) { \
+ if (world.tick_usage > (Master.current_ticklimit/2) || light_range > LIGHTING_MAXIMUM_INSTANT_RANGE || SSlighting.force_queued) { \
+ SSlighting.light_queue += src; \
+ } \
+ else { \
+ SSlighting.total_instant_updates += 1; \
+ update_corners(TRUE); \
+ needs_update = LIGHTING_NO_UPDATE; \
+ } \
}
+#else
+#define INTELLIGENT_UPDATE(level) \
+ if (needs_update == LIGHTING_NO_UPDATE) \
+ SSlighting.light_queue += src; \
+ if (needs_update < level) \
+ needs_update = level;
+#endif
// This proc will cause the light source to update the top atom, and add itself to the update queue.
/datum/light_source/proc/update(atom/new_top_atom)
// This top atom is different.
- if(new_top_atom && new_top_atom != top_atom)
+ if (new_top_atom && new_top_atom != top_atom)
if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom.
- top_atom.light_sources -= src
+ REMOVE_SOURCE(top_atom)
top_atom = new_top_atom
- if(top_atom != source_atom)
- if(!top_atom.light_sources)
- top_atom.light_sources = list()
+ if (top_atom != source_atom)
+ ADD_SOURCE(top_atom) // Add ourselves to the light sources of our new top atom.
- top_atom.light_sources += src // Add ourselves to the light sources of our new top atom.
-
- effect_update(null)
+ INTELLIGENT_UPDATE(LIGHTING_CHECK_UPDATE)
// Will force an update without checking if it's actually needed.
/datum/light_source/proc/force_update()
- force_update = 1
-
- effect_update(null)
+ INTELLIGENT_UPDATE(LIGHTING_FORCE_UPDATE)
// Will cause the light source to recalculate turfs that were removed or added to visibility only.
/datum/light_source/proc/vis_update()
- vis_update = 1
+ INTELLIGENT_UPDATE(LIGHTING_VIS_UPDATE)
- effect_update(null)
+// Decompile the hexadecimal colour into lumcounts of each perspective.
+/datum/light_source/proc/parse_light_color()
+ if (light_color)
+ var/list/parts = rgb2num(light_color)
+ ASSERT(length(parts) == 3)
+ lum_r = parts[1] / 255
+ lum_g = parts[2] / 255
+ lum_b = parts[3] / 255
+ else
+ lum_r = 1
+ lum_g = 1
+ lum_b = 1
-// Will check if we actually need to update, and update any variables that may need to be updated.
-/datum/light_source/proc/check()
- if(!source_atom || !light_outer_range || !light_max_bright)
- destroy()
- return 1
+#define POLAR_TO_CART_X(R,T) ((R) * cos(T))
+#define POLAR_TO_CART_Y(R,T) ((R) * sin(T))
+#define DETERMINANT(A_X,A_Y,B_X,B_Y) ((A_X)*(B_Y) - (A_Y)*(B_X))
+#define MINMAX(NUM) ((NUM) < 0 ? -round(-(NUM)) : round(NUM))
+#define ARBITRARY_NUMBER 10
+
+/datum/light_source/proc/regenerate_angle(ndir)
+ old_direction = ndir
+
+ var/turf/front = get_step(source_turf, old_direction)
+ facing_opaque = (front && front.has_opaque_atom)
+
+ cached_origin_x = test_x_offset = source_turf.x
+ cached_origin_y = test_y_offset = source_turf.y
+
+ if (facing_opaque)
+ return
+
+ var/limit_a_t
+ var/limit_b_t
+
+ var/angle = light_angle * 0.5
+ switch (old_direction)
+ if (NORTH)
+ limit_a_t = angle + 90
+ limit_b_t = -(angle) + 90
+ test_y_offset += 1
+
+ if (SOUTH)
+ limit_a_t = (angle) - 90
+ limit_b_t = -(angle) - 90
+ test_y_offset -= 1
+
+ if (EAST)
+ limit_a_t = angle
+ limit_b_t = -(angle)
+ test_x_offset += 1
+
+ if (WEST)
+ limit_a_t = angle + 180
+ limit_b_t = -(angle) - 180
+ test_x_offset -= 1
+
+ // Convert our angle + range into a vector.
+ limit_a_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_a_t)
+ limit_a_x = MINMAX(limit_a_x)
+ limit_a_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_a_t)
+ limit_a_y = MINMAX(limit_a_y)
+ limit_b_x = POLAR_TO_CART_X(light_range + ARBITRARY_NUMBER, limit_b_t)
+ limit_b_x = MINMAX(limit_b_x)
+ limit_b_y = POLAR_TO_CART_Y(light_range + ARBITRARY_NUMBER, limit_b_t)
+ limit_b_y = MINMAX(limit_b_y)
+
+#undef ARBITRARY_NUMBER
+#undef POLAR_TO_CART_X
+#undef POLAR_TO_CART_Y
+#undef MINMAX
+
+/datum/light_source/proc/remove_lum(now = FALSE)
+ applied = FALSE
- if(!top_atom)
- top_atom = source_atom
- . = 1
+ var/thing
+ for (thing in affecting_turfs)
+ var/turf/T = thing
+ LAZYREMOVE(T.affecting_lights, src)
- if(isturf(top_atom))
- if(source_turf != top_atom)
- source_turf = top_atom
- . = 1
- else if(top_atom.loc != source_turf)
- source_turf = top_atom.loc
- . = 1
+ affecting_turfs = null
- if(source_atom.light_max_bright != light_max_bright)
- light_max_bright = source_atom.light_max_bright
- . = 1
+ for (thing in effect_str)
+ var/datum/lighting_corner/C = thing
+ REMOVE_CORNER(C,now)
- if(source_atom.light_inner_range != light_inner_range)
- light_inner_range = source_atom.light_inner_range
- . = 1
+ LAZYREMOVE(C.affecting, src)
- if(source_atom.light_outer_range != light_outer_range)
- light_outer_range = source_atom.light_outer_range
- . = 1
+ effect_str = null
- if(source_atom.light_falloff_curve != light_falloff_curve)
- light_falloff_curve = source_atom.light_falloff_curve
- . = 1
+/datum/light_source/proc/recalc_corner(datum/lighting_corner/C, now = FALSE)
+ LAZYINITLIST(effect_str)
+ if (effect_str[C]) // Already have one.
+ REMOVE_CORNER(C,now)
+ effect_str[C] = 0
- if(light_max_bright && light_outer_range && !applied)
- . = 1
+ var/actual_range = light_range
- if(source_atom.light_color != light_color)
- light_color = source_atom.light_color
- parse_light_color()
- . = 1
+ var/Sx = pixel_turf.x
+ var/Sy = pixel_turf.y
+ var/Sz = pixel_turf.z
-// Decompile the hexadecimal colour into lumcounts of each perspective.
-/datum/light_source/proc/parse_light_color()
- if(light_color)
- lum_r = GetRedPart (light_color) / 255
- lum_g = GetGreenPart(light_color) / 255
- lum_b = GetBluePart (light_color) / 255
- else
- lum_r = 1
- lum_g = 1
- lum_b = 1
+ var/height = C.z == Sz ? LIGHTING_HEIGHT : CALCULATE_CORNER_HEIGHT(C.z, Sz)
+ APPLY_CORNER(C, now, Sx, Sy, height)
-// Macro that applies light to a new corner.
-// It is a macro in the interest of speed, yet not having to copy paste it.
-// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line.
-// As such this all gets counted as a single line.
-// The braces and semicolons are there to be able to do this on a single line.
-
-#define APPLY_CORNER(C) \
- . = LUM_FALLOFF(C, source_turf); \
- . *= (light_max_bright ** 2); \
- . *= light_max_bright < 0 ? -1:1;\
- effect_str[C] = .; \
- C.update_lumcount \
- ( \
- . * applied_lum_r, \
- . * applied_lum_g, \
- . * applied_lum_b \
- );
-
-// I don't need to explain what this does, do I?
-#define REMOVE_CORNER(C) \
- . = -effect_str[C]; \
- C.update_lumcount \
- ( \
- . * applied_lum_r, \
- . * applied_lum_g, \
- . * applied_lum_b \
- );
-
-// This is the define used to calculate falloff.
-// Assuming a brightness of 1 at range 1, formula should be (brightness = 1 / distance^2)
-// However, due to the weird range factor, brightness = (-(distance - full_dark_start) / (full_dark_start - full_light_end)) ^ light_max_bright
-
-#define LUM_FALLOFF(C, T)(CLAMP01(-((((C.x - T.x) ** 2 +(C.y - T.y) ** 2) ** 0.5 - light_outer_range) / max(light_outer_range - light_inner_range, 1))) ** light_falloff_curve)
-
-
-/datum/light_source/proc/apply_lum()
- var/static/update_gen = 1
- applied = 1
-
- // Keep track of the last applied lum values so that the lighting can be reversed
- applied_lum_r = lum_r
- applied_lum_g = lum_g
- applied_lum_b = lum_b
+ UNSETEMPTY(effect_str)
- FOR_DVIEW(var/turf/T, light_outer_range, source_turf, INVISIBILITY_LIGHTING)
- check_t:
- if (!T)
- continue
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
+/datum/light_source/proc/update_corners(now = FALSE)
+ var/update = FALSE
- for(var/datum/lighting_corner/C in T.get_corners())
- if(C.update_gen == update_gen)
- continue
+ if (QDELETED(source_atom))
+ qdel(src)
+ return
- C.update_gen = update_gen
- C.affecting += src
+ if (source_atom.light_power != light_power)
+ light_power = source_atom.light_power
+ update = TRUE
- if(!C.active)
- effect_str[C] = 0
- continue
+ if (source_atom.light_range != light_range)
+ light_range = source_atom.light_range
+ update = TRUE
- APPLY_CORNER(C)
+ if (!top_atom)
+ top_atom = source_atom
+ update = TRUE
- LAZYADD(T.affecting_lights, src)
- affecting_turfs += T
+ if (top_atom.loc != source_turf)
+ source_turf = top_atom.loc
+ UPDATE_APPROXIMATE_PIXEL_TURF
+ update = TRUE
- if (T.z_flags & ZM_ALLOW_LIGHTING)
- T = T.below
- goto check_t
+ if (!light_range || !light_power)
+ qdel(src)
+ return
- END_FOR_DVIEW
+ if (isturf(top_atom))
+ if (source_turf != top_atom)
+ source_turf = top_atom
+ UPDATE_APPROXIMATE_PIXEL_TURF
+ update = TRUE
+ else if (top_atom.loc != source_turf)
+ source_turf = top_atom.loc
+ UPDATE_APPROXIMATE_PIXEL_TURF
+ update = TRUE
- update_gen++
+ if (!source_turf)
+ return // Somehow we've got a light in nullspace, no-op.
-/datum/light_source/proc/remove_lum()
- applied = FALSE
+ if (light_range && light_power && !applied)
+ update = TRUE
- for(var/turf/T in affecting_turfs)
- LAZYREMOVE(T.affecting_lights, src)
+ if (source_atom.light_color != light_color)
+ light_color = source_atom.light_color
+ parse_light_color()
+ update = TRUE
+
+ else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
+ update = TRUE
+
+ if (source_atom.light_wedge != light_angle)
+ light_angle = source_atom.light_wedge
+ update = TRUE
+
+ if (light_angle)
+ var/ndir
+ if (istype(top_atom, /mob) && top_atom:facing_dir)
+ ndir = top_atom:facing_dir
+ else
+ ndir = top_atom.dir
+
+ if (old_direction != ndir) // If our direction has changed, we need to regenerate all the angle info.
+ regenerate_angle(ndir)
+ update = TRUE
+ else // Check if it was just a x/y translation, and update our vars without an regenerate_angle() call if it is.
+ var/co_updated = FALSE
+ if (source_turf.x != cached_origin_x)
+ test_x_offset += source_turf.x - cached_origin_x
+ cached_origin_x = source_turf.x
+
+ co_updated = TRUE
+
+ if (source_turf.y != cached_origin_y)
+ test_y_offset += source_turf.y - cached_origin_y
+ cached_origin_y = source_turf.y
+
+ co_updated = TRUE
+
+ if (co_updated)
+ // We might be facing a wall now.
+ var/turf/front = get_step(source_turf, old_direction)
+ var/new_fo = (front && front.has_opaque_atom)
+ if (new_fo != facing_opaque)
+ facing_opaque = new_fo
+ regenerate_angle(ndir)
+
+ update = TRUE
+
+ if (update)
+ needs_update = LIGHTING_CHECK_UPDATE
+ else if (needs_update == LIGHTING_CHECK_UPDATE)
+ return // No change.
- affecting_turfs.Cut()
+ var/list/datum/lighting_corner/corners = list()
+ var/list/turf/turfs = list()
+ var/thing
+ var/datum/lighting_corner/C
+ var/turf/T
+ var/list/Tcorners
+ var/Sx = pixel_turf.x // these are used by APPLY_CORNER_BY_HEIGHT
+ var/Sy = pixel_turf.y
+ var/Sz = pixel_turf.z
+ var/corner_height = LIGHTING_HEIGHT
+ var/actual_range = (light_angle && facing_opaque) ? light_range * LIGHTING_BLOCKED_FACTOR : light_range
+ var/test_x
+ var/test_y
+
+ var/should_do_wedge = light_angle && !facing_opaque
+
+ FOR_DVIEW(T, Ceilm(actual_range, 1), source_turf, 0) do
+ if (should_do_wedge) // Directional lighting coordinate filter.
+ test_x = T.x - test_x_offset
+ test_y = T.y - test_y_offset
+
+ // If the signs of these are the same, then the point is within the cone.
+ if ((DETERMINANT(limit_a_x, limit_a_y, test_x, test_y) > 0) || DETERMINANT(test_x, test_y, limit_b_x, limit_b_y) > 0)
+ continue
- for(var/datum/lighting_corner/C in effect_str)
- REMOVE_CORNER(C)
+ if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) || T.light_source_solo || T.light_source_multi)
+ Tcorners = T.corners
+ if (!T.lighting_corners_initialised)
+ T.lighting_corners_initialised = TRUE
- C.affecting -= src
+ if (!Tcorners)
+ T.corners = list(null, null, null, null)
+ Tcorners = T.corners
- effect_str.Cut()
+ for (var/i = 1 to 4)
+ if (Tcorners[i])
+ continue
-/datum/light_source/proc/recalc_corner(datum/lighting_corner/C)
- if(effect_str.Find(C)) // Already have one.
- REMOVE_CORNER(C)
+ Tcorners[i] = new /datum/lighting_corner(T, LIGHTING_CORNER_DIAGONAL[i], i)
- APPLY_CORNER(C)
+ if (!T.has_opaque_atom)
+ for (var/v in 1 to 4)
+ var/val = Tcorners[v]
+ if (val)
+ corners[val] = 0
-/datum/light_source/proc/smart_vis_update()
- var/list/datum/lighting_corner/corners = list()
- var/list/turf/turfs = list()
- FOR_DVIEW(var/turf/T, light_outer_range, source_turf, 0)
- if (!T)
- continue
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- corners |= T.get_corners()
- turfs += T
-
- var/turf/simulated/open/O = T
- if(istype(O) && O.below)
- // Consider the turf below us as well. (Z-lights)
- for(T = O.below; !isnull(T); T = update_the_turf(T,corners, turfs));
+ turfs += T
+
+ // Upwards lights are handled at the corner level, so only search down.
+ // This is a do-while associated with the FOR_DVIEW above.
+ while (T && (T.z_flags & ZM_ALLOW_LIGHTING) && (T = T.below))
END_FOR_DVIEW
+ LAZYINITLIST(affecting_turfs)
+
var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them.
affecting_turfs += L
- for(var/turf/T in L)
+ for (thing in L)
+ T = thing
LAZYADD(T.affecting_lights, src)
L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights.
affecting_turfs -= L
- for(var/turf/T in L)
+ for (thing in L)
+ T = thing
LAZYREMOVE(T.affecting_lights, src)
- for(var/datum/lighting_corner/C in corners - effect_str) // New corners
- C.affecting += src
- if(!C.active)
- effect_str[C] = 0
- continue
+ LAZYINITLIST(effect_str)
+ if (needs_update == LIGHTING_VIS_UPDATE)
+ for (thing in corners - effect_str)
+ C = thing
+ LAZYADD(C.affecting, src)
+ if (!C.active)
+ effect_str[C] = 0
+ continue
+
+ APPLY_CORNER_BY_HEIGHT(now)
+ else
+ L = corners - effect_str
+ for (thing in L)
+ C = thing
+ LAZYADD(C.affecting, src)
+ if (!C.active)
+ effect_str[C] = 0
+ continue
+
+ APPLY_CORNER_BY_HEIGHT(now)
+
+ for (thing in corners - L)
+ C = thing
+ if (!C.active)
+ effect_str[C] = 0
+ continue
- APPLY_CORNER(C)
+ APPLY_CORNER_BY_HEIGHT(now)
- for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners.
- REMOVE_CORNER(C)
- C.affecting -= src
- effect_str -= C
+ L = effect_str - corners
+ for (thing in L)
+ C = thing
+ REMOVE_CORNER(C, now)
+ LAZYREMOVE(C.affecting, src)
+ effect_str -= L
-/datum/light_source/proc/update_the_turf(turf/T, list/datum/lighting_corner/corners, list/turf/turfs)
- if(!T.lighting_corners_initialised)
- T.generate_missing_corners()
- corners |= T.get_corners()
- turfs += T
+ applied_lum_r = lum_r
+ applied_lum_g = lum_g
+ applied_lum_b = lum_b
- var/turf/simulated/open/O = T
- if(istype(O) && O.below)
- return O.below
- return null
+ UNSETEMPTY(effect_str)
+ UNSETEMPTY(affecting_turfs)
-#undef effect_update
-#undef LUM_FALLOFF
-#undef REMOVE_CORNER
-#undef APPLY_CORNER
+#undef INTELLIGENT_UPDATE
+#undef DETERMINANT
+#undef GET_APPROXIMATE_PIXEL_DIR
+#undef UPDATE_APPROXIMATE_PIXEL_TURF
diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm
index 8071ca8d4796f..eea95935de39e 100644
--- a/code/modules/lighting/lighting_turf.dm
+++ b/code/modules/lighting/lighting_turf.dm
@@ -1,113 +1,273 @@
-/// Does the turf use dynamic lighting?
-/turf/var/dynamic_lighting = TRUE
-/turf/luminosity = 1
+/turf
+ var/dynamic_lighting = TRUE
+ var/ambient_light // If non-null, a hex RGB light color that should be applied to this turf.
+ var/ambient_light_multiplier = 0.3 // The power of the above is multiplied by this. Setting too high may drown out normal lights on the same turf.
+ luminosity = 1
-/turf/var/lighting_corners_initialised = FALSE
+ var/lighting_corners_initialised = FALSE
-/// List of light sources affecting this turf.
-/turf/var/list/datum/light_source/affecting_lights
-/// Our lighting overlay.
-/turf/var/atom/movable/lighting_overlay/lighting_overlay
-/turf/var/list/datum/lighting_corner/corners
-/turf/var/opaque_counter
+ var/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
+ var/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
+ var/list/datum/lighting_corner/corners
-/turf/set_opacity(new_opacity)
+ var/ambient_has_indirect = FALSE // If this is TRUE, an above turf's ambient light is affecting this turf.
+
+ // Record-keeping, do not touch -- that means you, admins.
+ var/ambient_active = FALSE //! Do we have non-zero ambient light? Use [TURF_IS_AMBIENT_LIT] instead of reading this directly.
+ var/ambient_light_old_r = 0
+ var/ambient_light_old_g = 0
+ var/ambient_light_old_b = 0
+
+ var/ambient_bitflag = 0
+
+//Done on init if mapload, done post copying corners if changeturf
+/turf/proc/setup_local_ambient()
+ return
+
+/turf/Initialize(mapload, ...)
. = ..()
- if(opacity == new_opacity)
- return FALSE
+ if(mapload)
+ setup_local_ambient()
- opacity = new_opacity
- return RecalculateOpacity()
+/turf/proc/set_ambient_light(color, multiplier)
+ if (color == ambient_light && multiplier == ambient_light_multiplier)
+ return
-/turf/proc/RecalculateOpacity()
- var/old_opaque_counter = opaque_counter
+ ambient_light = color || ambient_light
+ ambient_light_multiplier = multiplier || ambient_light_multiplier
+ if (!ambient_light_multiplier)
+ ambient_light_multiplier = initial(ambient_light_multiplier)
- opaque_counter = opacity
- for(var/a in src)
- var/atom/A = a
- opaque_counter += A.opacity
+ update_ambient_light()
- // If the counter changed and was or became 0 then lift event/reconsider lights
- if(opaque_counter != old_opaque_counter && (!opaque_counter || !old_opaque_counter))
- GLOB.opacity_set_event.raise_event(src, !opaque_counter, !!opaque_counter)
- reconsider_lights()
- return TRUE
- return FALSE
+/turf/proc/replace_ambient_light(old_color, new_color, old_multiplier, new_multiplier = 0)
+ if (!TURF_IS_AMBIENT_LIT_UNSAFE(src))
+ add_ambient_light(new_color, new_multiplier)
+ return
+
+ ASSERT(old_multiplier) // omitting new_multiplier is allowed for removing light nondestructively
+
+ old_color ||= COLOR_WHITE
+ new_color ||= COLOR_WHITE
+
+ var/list/old_parts = rgb2num(old_color)
+ var/list/new_parts = rgb2num(new_color)
+
+ var/dr = (new_parts[1] / 255) * new_multiplier - (old_parts[1] / 255) * old_multiplier
+ var/dg = (new_parts[2] / 255) * new_multiplier - (old_parts[2] / 255) * old_multiplier
+ var/db = (new_parts[3] / 255) * new_multiplier - (old_parts[3] / 255) * old_multiplier
+
+ if (!dr && !dg && !db)
+ return
+
+ add_ambient_light_raw(dr, dg, db)
+
+/turf/proc/add_ambient_light(color, multiplier, update = TRUE)
+ if (!color)
+ return
+
+ multiplier ||= ambient_light_multiplier
+
+ var/list/ambient_parts = rgb2num(color)
+
+ var/ambient_r = (ambient_parts[1] / 255) * multiplier
+ var/ambient_g = (ambient_parts[2] / 255) * multiplier
+ var/ambient_b = (ambient_parts[3] / 255) * multiplier
+
+ add_ambient_light_raw(ambient_r, ambient_g, ambient_b, update)
+
+/turf/proc/add_ambient_light_raw(lr, lg, lb, update = TRUE)
+ if (!lr && !lg && !lb)
+ if (!ambient_light_old_r || !ambient_light_old_g || !ambient_light_old_b)
+ ambient_active = FALSE
+ SSlighting.total_ambient_turfs -= 1
+ return
+
+ if (!ambient_active)
+ SSlighting.total_ambient_turfs += 1
+ ambient_active = TRUE
+
+ // There are four corners per (lit) turf, we don't want to apply our light 4 times -- compensate by dividing by 4.
+ lr /= 4
+ lg /= 4
+ lb /= 4
+
+ lr = round(lr, LIGHTING_ROUND_VALUE)
+ lg = round(lg, LIGHTING_ROUND_VALUE)
+ lb = round(lb, LIGHTING_ROUND_VALUE)
+
+ ambient_light_old_r += lr
+ ambient_light_old_g += lg
+ ambient_light_old_b += lb
+
+ if (!corners || !lighting_corners_initialised)
+ generate_missing_corners()
+
+ // This list can contain nulls on things like space turfs -- they only have their neighbors' corners.
+ for (var/datum/lighting_corner/C in corners)
+ C.update_ambient_lumcount(lr, lg, lb, !update)
+
+/turf/proc/clear_ambient_light()
+ if (ambient_light == null)
+ return
+
+ ambient_light = null
+ update_ambient_light()
+
+/turf/proc/update_ambient_light(no_corner_update = FALSE)
+ // These are deltas.
+ var/ambient_r = 0
+ var/ambient_g = 0
+ var/ambient_b = 0
+
+ if (ambient_light)
+ var/list/parts = rgb2num(ambient_light)
+ ambient_r = ((parts[1] / 255) * ambient_light_multiplier) - ambient_light_old_r
+ ambient_g = ((parts[2] / 255) * ambient_light_multiplier) - ambient_light_old_g
+ ambient_b = ((parts[3] / 255) * ambient_light_multiplier) - ambient_light_old_b
+ else
+ ambient_r = -ambient_light_old_r
+ ambient_g = -ambient_light_old_g
+ ambient_b = -ambient_light_old_b
+
+ add_ambient_light_raw(ambient_r, ambient_g, ambient_b, !no_corner_update)
// Causes any affecting light sources to be queued for a visibility update, for example a door got opened.
/turf/proc/reconsider_lights()
- for(var/datum/light_source/L in affecting_lights)
+ var/datum/light_source/L
+ for (var/thing in affecting_lights)
+ L = thing
L.vis_update()
+// Forces a lighting update. Reconsider lights is preferred when possible.
+/turf/proc/force_update_lights()
+ var/datum/light_source/L
+ for (var/thing in affecting_lights)
+ L = thing
+ L.force_update()
+
/turf/proc/lighting_clear_overlay()
- if(lighting_overlay)
- qdel(lighting_overlay)
+ if (lighting_overlay)
+ if (lighting_overlay.loc != src)
+ stack_trace("Lighting overlay variable on turf [log_info_line(src)] is insane, lighting overlay actually located on [log_info_line(lighting_overlay.loc)]!")
+
+ qdel(lighting_overlay, TRUE)
+ lighting_overlay = null
- for(var/datum/lighting_corner/C in corners)
+ for (var/datum/lighting_corner/C in corners)
C.update_active()
// Builds a lighting overlay for us, but only if our area is dynamic.
-/turf/proc/lighting_build_overlay()
- if(lighting_overlay)
- return
+/turf/proc/lighting_build_overlay(now = FALSE)
+ if (lighting_overlay)
+ return //In Cit this wont happen, bay has a slightly different init so just returning is fine
+ //CRASH("Attempted to create lighting_overlay on tile that already had one.")
- var/area/A = loc
- if(A.dynamic_lighting && dynamic_lighting)
- if(!lighting_corners_initialised)
+ if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src))
+ if (!lighting_corners_initialised || !corners)
generate_missing_corners()
- new /atom/movable/lighting_overlay(src)
+ new /atom/movable/lighting_overlay(src, now)
- for(var/datum/lighting_corner/C in corners)
- if(!C.active) // We would activate the corner, calculate the lighting for it.
- for(var/L in C.affecting)
+ for (var/datum/lighting_corner/C in corners)
+ if (!C.active) // We would activate the corner, calculate the lighting for it.
+ for (var/L in C.affecting)
var/datum/light_source/S = L
- S.recalc_corner(C)
+ S.recalc_corner(C, TRUE)
C.active = TRUE
+// Returns the average color of this tile. Roughly corresponds to the color of a single old-style lighting overlay.
+/turf/proc/get_avg_color()
+ if (!lighting_overlay)
+ return null
+
+ var/lum_r
+ var/lum_g
+ var/lum_b
+
+ for (var/datum/lighting_corner/L in corners)
+ lum_r += L.apparent_r
+ lum_g += L.apparent_g
+ lum_b += L.apparent_b
+
+ lum_r = CLAMP01(lum_r / 4) * 255
+ lum_g = CLAMP01(lum_g / 4) * 255
+ lum_b = CLAMP01(lum_b / 4) * 255
+
+ return "#[num2hex(lum_r)][num2hex(lum_g)][num2hex(lum_b)]"
+
+#define SCALE(targ,min,max) (targ - min) / (max - min)
+
// Used to get a scaled lumcount.
/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
- if(!lighting_overlay)
- var/area/A = loc
- if(A.dynamic_lighting && dynamic_lighting)
- var/atom/movable/lighting_overlay/O = new /atom/movable/lighting_overlay(src)
- lighting_overlay = O
+ if (!lighting_overlay)
+ return 0.5
var/totallums = 0
- for(var/datum/lighting_corner/L in corners)
- totallums += max(L.lum_r, L.lum_g, L.lum_b)
+ for (var/datum/lighting_corner/L in corners)
+ totallums += L.apparent_r + L.apparent_b + L.apparent_g
- totallums /= 4 // 4 corners, max channel selected, return the average
+ totallums /= 12 // 4 corners, each with 3 channels, get the average.
- totallums =(totallums - minlum) /(maxlum - minlum)
+ totallums = SCALE(totallums, minlum, maxlum)
return CLAMP01(totallums)
-// If an opaque movable atom moves around we need to potentially update visibility.
-/turf/Entered(atom/movable/AM, atom/OldLoc)
- . = ..()
- if(AM?.opacity)
- RecalculateOpacity()
+#undef SCALE
+
+// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
+/turf/proc/recalc_atom_opacity()
+#ifdef AO_USE_LIGHTING_OPACITY
+ var/old = has_opaque_atom
+#endif
+
+ has_opaque_atom = FALSE
+ if (opacity)
+ has_opaque_atom = TRUE
+ else
+ for (var/thing in src) // Loop through every movable atom on our tile
+ var/atom/movable/A = thing
+ if (A.opacity)
+ has_opaque_atom = TRUE
+ break // No need to continue if we find something opaque.
+
+#ifdef AO_USE_LIGHTING_OPACITY
+ if (old != has_opaque_atom)
+ regenerate_ao()
+#endif
-/turf/Exited(atom/movable/AM, atom/newloc)
+/turf/Exited(atom/movable/Obj, atom/newloc)
. = ..()
- if(AM?.opacity)
- RecalculateOpacity()
-/turf/proc/get_corners()
- if(opaque_counter)
- return null // Since this proc gets used in a for loop, null won't be looped though.
+ if (!Obj)
+ return
+
+ if (Obj.opacity)
+ recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
+ reconsider_lights()
- return corners
+// This block isn't needed now, but it's here if supporting area dyn lighting changes is needed later.
+// /turf/change_area(area/old_area, area/new_area)
+// if (new_area.dynamic_lighting != old_area.dynamic_lighting)
+// if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(src))
+// lighting_build_overlay()
+// else
+// lighting_clear_overlay()
+
+// This is inlined in lighting_source.dm.
+// Update it too if you change this.
/turf/proc/generate_missing_corners()
+ if (!TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) && !light_source_solo && !light_source_multi && !(z_flags & ZM_ALLOW_LIGHTING) && !ambient_light && !ambient_has_indirect)
+ return
+
lighting_corners_initialised = TRUE
- if(!corners)
- corners = list(null, null, null, null)
+ if (!corners)
+ corners = new(4)
- for(var/i = 1 to 4)
- if(corners[i]) // Already have a corner on this direction.
+ for (var/i = 1 to 4)
+ if (corners[i]) // Already have a corner on this direction.
continue
- corners[i] = new /datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i])
+ corners[i] = new/datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i], i)
diff --git a/code/modules/mechs/equipment/engineering.dm b/code/modules/mechs/equipment/engineering.dm
index e2649221cef61..2e71a23d79db0 100644
--- a/code/modules/mechs/equipment/engineering.dm
+++ b/code/modules/mechs/equipment/engineering.dm
@@ -73,7 +73,7 @@
/obj/effect/mech_shield/Initialize()
. = ..()
- set_light(0.8, 0.1, 1, 2, COLOR_SABER_BLUE)
+ set_light(1, 0.8, COLOR_SABER_BLUE)
update_nearby_tiles(need_rebuild=1)
/obj/effect/mech_shield/Destroy()
diff --git a/code/modules/mechs/equipment/utility.dm b/code/modules/mechs/equipment/utility.dm
index 13ac4c7b41e25..312c0eca24110 100644
--- a/code/modules/mechs/equipment/utility.dm
+++ b/code/modules/mechs/equipment/utility.dm
@@ -274,9 +274,8 @@
var/on = 0
- var/l_max_bright = 0.9
- var/l_inner_range = 1
- var/l_outer_range = 6
+ var/l_power = 2
+ var/l_range = 6
origin_tech = list(TECH_MATERIAL = 1, TECH_ENGINEERING = 1)
/obj/item/mech_equipment/light/installed(mob/living/exosuit/_owner)
@@ -304,7 +303,7 @@
/obj/item/mech_equipment/light/on_update_icon()
if(on)
icon_state = "[initial(icon_state)]-on"
- set_light(l_max_bright, l_inner_range, l_outer_range)
+ set_light(l_range, l_power, angle = LIGHT_WIDE)
else
icon_state = "[initial(icon_state)]"
set_light(0, 0)
@@ -793,7 +792,7 @@
. = ..()
if (active)
icon_state = "mech_jet_on"
- set_light(1, 1, 1, l_color = COLOR_LIGHT_CYAN)
+ set_light(1, 1, l_color = COLOR_LIGHT_CYAN)
else
icon_state = "mech_jet_off"
set_light(0)
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index 4c0e2409c949a..1e4385d32b21c 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -241,7 +241,7 @@
addon.layer = ABOVE_LIGHTING_LAYER
addon.plane = EFFECTS_ABOVE_LIGHTING_PLANE
AddOverlays(addon)
- set_light(0.5, 0.5, 3)
+ set_light(3, 0.5)
else
pixel_x = rand(-randpixel, randpixel)
pixel_y = rand(-randpixel, randpixel)
diff --git a/code/modules/mob/dview.dm b/code/modules/mob/dview.dm
new file mode 100644
index 0000000000000..816c757082cce
--- /dev/null
+++ b/code/modules/mob/dview.dm
@@ -0,0 +1,27 @@
+//DVIEW is a hack that uses a mob with darksight in order to find lists of viewable stuff while ignoring darkness
+// Defines for dview are elsewhere.
+
+var/global/mob/dview/dview_mob = new
+
+/mob/dview
+ anchored = TRUE
+ density = FALSE
+ invisibility = INVISIBILITY_ABSTRACT
+ see_in_dark = 1e6
+ simulated = FALSE
+ virtual_mob = null
+
+/mob/dview/Destroy(force = FALSE)
+ SHOULD_CALL_PARENT(FALSE)
+ if (!force)
+ return QDEL_HINT_LETMELIVE
+
+ crash_with("Forced deletion of dview mob, this should not happen! : [log_info_line(src)]")
+
+ dview_mob = new
+ return QDEL_HINT_QUEUE
+
+/mob/dview/Initialize()
+ . = ..()
+ // We don't want to be in any mob lists; we're a dummy not a mob.
+ STOP_PROCESSING_MOB(src)
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index 6893de9bdcee0..c1a8d5373fc1d 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -374,7 +374,7 @@
if(stat)
return 0
on = 1
- set_light(0.5, 0.1, light_strength)
+ set_light(light_strength, 0.5)
update_icons()
resetTarget()
patrol_path = list()
diff --git a/code/modules/mob/living/carbon/alien/diona/nymph_life.dm b/code/modules/mob/living/carbon/alien/diona/nymph_life.dm
index f33a947b6f3b1..0404aa3482044 100644
--- a/code/modules/mob/living/carbon/alien/diona/nymph_life.dm
+++ b/code/modules/mob/living/carbon/alien/diona/nymph_life.dm
@@ -17,7 +17,7 @@
else
var/mult = clamp(radiation/200, 0.5, 1)
if(last_glow != mult)
- set_light(mult, 0.5, (5*mult), 2, "#55ff55")
+ set_light((5*mult), mult, "#55ff55")
last_glow = mult
set_nutrition(clamp(nutrition + floor(radiation/100) + light_amount, 0, 500))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 2e97b3286c5b0..7c1d7309a6e3a 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1114,6 +1114,40 @@
to_chat(src, SPAN_NOTICE("You look up."))
reset_view(z_eye)
return
+
+ var/turf/T= get_turf(src)
+
+ if(T.is_outside())// They're outside and hopefully on a planet.
+ var/obj/effect/overmap/visitable/sector/exoplanet/E = map_sectors["[T.z]"]
+ if (!istype(E))
+ to_chat(usr, SPAN_NOTICE("You see... things, it's hard to put into words what you're seeing specifically."))
+ return
+
+ //Weather hook here when it is a thing
+
+ // Sun-related output.
+ //Calculate time of day
+ var/time_of_day = E.sun_last_process % E.daycycle
+ var/afternoon = time_of_day > (E.daycycle / 2)
+ var/star_name = GLOB.using_map.system_name
+
+ var/sun_message = null
+ switch(E.sun_position)
+ if(0 to 0.4) // Night
+ sun_message = "It is night time, [star_name] is not visible."
+ if(0.4 to 0.5) // Twilight
+ sun_message = "The sky is in twilight, however [star_name] is not visible."
+ if(0.5 to 0.7) // Sunrise/set.
+ sun_message = "[star_name] is slowly [!afternoon ? "rising from" : "setting on"] the horizon."
+ if(0.7 to 0.9) // Morning/evening
+ sun_message = "[star_name]'s position implies it is currently [!afternoon ? "early" : "late"] in the day."
+ if(0.9 to 1.0) // Noon
+ sun_message = "It's high noon. [star_name] hangs directly above you."
+
+ to_chat(usr, SPAN_NOTICE(sun_message))
+ return
+
+
to_chat(src, SPAN_NOTICE("You can see \the [above ? above : "ceiling"]."))
else
to_chat(src, SPAN_NOTICE("You can't look up right now."))
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index b2dc3683bdaff..fe83411edc3a6 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -231,7 +231,7 @@
set_light(0)
else
if(species.appearance_flags & SPECIES_APPEARANCE_RADIATION_GLOWS)
- set_light(0.3, 0.1, max(1,min(20,radiation/20)), 2, species.get_flesh_colour(src))
+ set_light(max(1,min(20,radiation/20)), 0.3, species.get_flesh_colour(src))
// END DOGSHIT SNOWFLAKE
var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs
@@ -885,7 +885,7 @@
//0.1% chance of playing a scary sound to someone who's in complete darkness
if(isturf(loc) && rand(1,1000) == 1)
var/turf/T = loc
- if(T.get_lumcount() <= LIGHTING_SOFT_THRESHOLD)
+ if(T.get_lumcount() <= 0)
playsound_local(src,pick(GLOB.scarySounds),50, 1, -1)
var/area/A = get_area(src)
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 8151bd3f7e2f2..a1e459d93a871 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -193,8 +193,6 @@
reset_view(null)
/mob/living/proc/update_sight()
- set_sight(0)
- set_see_in_dark(0)
if(stat == DEAD || eyeobj)
update_dead_sight()
else
@@ -226,3 +224,52 @@
/mob/living/proc/handle_hud_icons_health()
return
+
+//Adaptative darksight
+//Ideally this would run instantly as mob updates are a bit too slow for this (noticeable when moving fast), but set_see_in_dark is called several timees.
+//For the time being it's instant and called whenever see in dark changes. Replace with a single call at end of updates once code is not spaghetti
+/mob/living/proc/handle_darksight()
+ if(!darksight)
+ return
+
+ //For testing purposes
+ var/darksightedness = min(see_in_dark/world.view,1.0) //A ratio of how good your darksight is, from 'nada' to 'really darn good'
+ var/current = darksight.alpha/255 //Our current adjustedness
+ var/adjusted_diameter = (0.5 + (see_in_dark - 1)) * 2
+ var/newScale = min((adjusted_diameter) * (world.icon_size/DARKSIGHT_GRADIENT_SIZE), 1)*0.9 //Scale the darksight gradient
+
+ var/brightness = 0.0 //We'll assume it's superdark if we can't find something else.
+
+
+ //Currently we're going to assume that only thing that matter is your turf
+ //This is not necessarily correct.
+ //We may want to blind people inside exosuits and such. At some point we could try moving lumcount to atom, default to turf and then we can make those override
+
+ var/turf/my_turf = get_turf(src)
+ if(isturf(my_turf))
+ brightness = my_turf.get_lumcount()
+
+ brightness = min((brightness + brightness*brightness), 1) //Increase apparent brightness so it's not that obvious. TODO: Make this a curve
+
+ var/darkness = 1-brightness //Silly, I know, but 'alpha' and 'darkness' go the same direction on a number line
+ newScale *= darkness // you see further in the dark, in fully lit areas you don't get a bonus
+ var/adjust_to = min(darkness,darksightedness)//Capped by how darksighted they are
+ var/distance = abs(current-adjust_to) //Used for how long to animate for
+ var/negative = current > adjust_to //Unfortunately due to a visual issue this must be instant if we go down 1 level of darksight
+
+ if((distance < 0.001) && (abs(darksight.transform.a - newScale) < 0.01)) return //We're already all set
+
+ if(negative)
+ distance = 0 //Make it instant
+
+ //TODO:.
+ //FIX VISION CODE! There is no correct place to update darksight as it keeps being reset and enabled several times a frame (even placing it on Life doesnt work because overrides set it in wrong function)
+ // Time = 0 means instant change, avoids some issues of animation resetting several times a frame
+ distance = 0
+
+ animate(darksight, alpha = (adjust_to*255), transform = matrix().Update(scale_x = newScale, scale_y = newScale), time = (distance*1 SECOND), flags = ANIMATION_LINEAR_TRANSFORM)
+
+//Need to update every time we set see in dark as it can be called at many different points and waiting for next frame causes visual artifacts
+/mob/living/set_see_in_dark(new_see_in_dark)
+ . = ..()
+ handle_darksight()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 85170b9e950a6..22927c7925d5f 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -256,7 +256,7 @@
/mob/living/proc/IgniteMob()
if(fire_stacks > 0 && !on_fire)
on_fire = 1
- set_light(0.6, 0.1, 4, l_color = COLOR_ORANGE)
+ set_light(4, 0.6, l_color = COLOR_ORANGE)
update_fire()
/mob/living/proc/ExtinguishMob()
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 88c994145126f..017f90e34b8d3 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -449,7 +449,7 @@ var/global/list/ai_verbs_default = list(
camera = A
..()
if(istype(A,/obj/machinery/camera))
- if(camera_light_on) A.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY)
+ if(camera_light_on) A.set_light(AI_CAMERA_LUMINOSITY, 0.5)
else A.set_light(0)
@@ -599,7 +599,7 @@ var/global/list/ai_verbs_default = list(
src.camera.set_light(0)
if(!camera.light_disabled)
src.camera = camera
- src.camera.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY)
+ src.camera.set_light(AI_CAMERA_LUMINOSITY, 0.5)
else
src.camera = null
else if(isnull(camera))
@@ -609,7 +609,7 @@ var/global/list/ai_verbs_default = list(
var/obj/machinery/camera/camera = near_range_camera(src.eyeobj)
if(camera && !camera.light_disabled)
src.camera = camera
- src.camera.set_light(0.5, 0.1, AI_CAMERA_LUMINOSITY)
+ src.camera.set_light(AI_CAMERA_LUMINOSITY, 0.5)
camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds.
@@ -709,13 +709,13 @@ var/global/list/ai_verbs_default = list(
icon = selected_sprite.icon
if(stat == DEAD)
icon_state = selected_sprite.dead_icon
- set_light(0.7, 0.1, 1, 2, selected_sprite.dead_light)
+ set_light(1, 0.7, selected_sprite.dead_light)
else if(!has_power())
icon_state = selected_sprite.nopower_icon
- set_light(0.4, 0.1, 1, 2, selected_sprite.nopower_light)
+ set_light(1, 0.4, selected_sprite.nopower_light)
else
icon_state = selected_sprite.alive_icon
- set_light(0.4, 0.1, 1, 2, selected_sprite.alive_light)
+ set_light(1, 0.4, selected_sprite.alive_light)
// Pass lying down or getting up to our pet human, if we're in a rig.
/mob/living/silicon/ai/lay_down()
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 7a5809f98aa20..7a976e2d8aac7 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -73,9 +73,8 @@ GLOBAL_LIST_INIT(possible_say_verbs, list(
var/translator_on = 0 // keeps track of the translator module
- var/flashlight_max_bright = 0.5 //brightness of light when on, must be no greater than 1.
- var/flashlight_inner_range = 1 //inner range of light when on, can be negative
- var/flashlight_outer_range = 3 //outer range of light when on, can be negative
+ var/flashlight_power = 0.5 //brightness of light when on, must be no greater than 1.
+ var/flashlight_range = 3 //outer range of light when on, can be negative
var/light_on = FALSE
hud_type = /datum/hud/pai
@@ -325,7 +324,7 @@ GLOBAL_LIST_INIT(possible_say_verbs, list(
/mob/living/silicon/pai/proc/toggle_integrated_light()
if(!light_on)
- set_light(flashlight_max_bright, flashlight_inner_range, flashlight_outer_range, 2)
+ set_light(flashlight_range, flashlight_power, 2)
to_chat(src, SPAN_NOTICE("You enable your integrated light."))
light_on = TRUE
else
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index f1aeb74cd0945..1c5da33484c4a 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -36,7 +36,7 @@ var/global/list/mob_hat_cache = list()
lawupdate = FALSE
density = TRUE
req_access = list(access_engine, access_robotics)
- integrated_light_max_bright = 0.5
+ integrated_light_power = 0.5
local_transmit = 1
possession_candidate = 1
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index a73a3eff911c9..3ba5e50d0ea5e 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -23,7 +23,7 @@
var/custom_sprite = FALSE
var/crisis //Admin-settable for combat module use.
var/crisis_override = FALSE
- var/integrated_light_max_bright = 0.75
+ var/integrated_light_power = 0.75
var/datum/wires/robot/wires
var/module_category = ROBOT_MODULE_TYPE_GROUNDED
var/dismantle_type = /obj/item/robot_parts/robot_suit
@@ -408,9 +408,9 @@
/mob/living/silicon/robot/proc/update_robot_light()
if(lights_on)
if(intenselight)
- set_light(1, 2, 6)
+ set_light(6, 1)
else
- set_light(0.75, 1, 4)
+ set_light(4, 0.75)
else
set_light(0)
diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm
index 73d169f1e8afb..7482a8aae5647 100644
--- a/code/modules/mob/living/silicon/robot/robot_items.dm
+++ b/code/modules/mob/living/silicon/robot/robot_items.dm
@@ -114,7 +114,7 @@
/obj/item/party_light/on_update_icon()
if (activated)
icon_state = "partylight-on"
- set_light(1, 1, 7)
+ set_light(7, 1)
else
icon_state = "partylight_off"
set_light(0)
diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm
index 7b8df30f8f80e..9f06592e52fc0 100644
--- a/code/modules/mob/living/simple_animal/constructs/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm
@@ -280,7 +280,7 @@
eye_glow.plane = EFFECTS_ABOVE_LIGHTING_PLANE
eye_glow.layer = EYE_GLOW_LAYER
AddOverlays(eye_glow)
- set_light(-2, 0.1, 1.5, l_color = "#ffffff")
+ set_light(1.5, -2, l_color = "#ffffff")
z_flags |= ZMM_MANGLE_PLANES
////////////////HUD//////////////////////
diff --git a/code/modules/mob/living/simple_animal/hostile/bluespace.dm b/code/modules/mob/living/simple_animal/hostile/bluespace.dm
index 0fb7387aa20b4..3b7a343c0e93c 100644
--- a/code/modules/mob/living/simple_animal/hostile/bluespace.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bluespace.dm
@@ -16,8 +16,8 @@
say_list = /datum/say_list/bluespace
natural_weapon = /obj/item/natural_weapon/bluespace
light_color = "#4da6ff"
- light_outer_range = 2
- light_max_bright = 1
+ light_range = 2
+ light_power = 1
bleed_colour = "#0000ff"
/mob/living/simple_animal/hostile/bluespace/Process_Spacemove()
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider/nurse.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider/nurse.dm
index f5ad5d0b47713..631de88335e2c 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider/nurse.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider/nurse.dm
@@ -209,7 +209,7 @@
/obj/effect/spider/stickyweb/dark/Initialize()
. = ..()
- set_light(-1, 0.5, 1, 1, l_color = "#ffffff")
+ set_light(1, -1, l_color = "#ffffff")
// The AI for nurse spiders. Wraps things in webs by 'attacking' them.
/datum/ai_holder/simple_animal/melee/nurse_spider
diff --git a/code/modules/mob/living/simple_animal/hostile/vagrant.dm b/code/modules/mob/living/simple_animal/hostile/vagrant.dm
index 0aad8485596ec..d0b94a707501d 100644
--- a/code/modules/mob/living/simple_animal/hostile/vagrant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/vagrant.dm
@@ -111,7 +111,7 @@
else //It's fight time
alpha = 255
icon_state = "vagrant_glowing"
- set_light(0.2, 0.1, 3)
+ set_light(3, 0.2)
move_to_delay = 2
/mob/living/simple_animal/hostile/vagrant/swarm/Initialize()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 2de61bafa0d8c..496e6e9c2a982 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -92,8 +92,8 @@
if(eyeobj)
eyeobj.possess(src)
- l_general = new()
- client.screen += l_general
+ darksight = new()
+ client.screen += darksight
CreateRenderers()
@@ -118,3 +118,10 @@
. = ..()
if(internals && internal)
internals.icon_state = "internal1"
+
+/mob/observer/ghost/Login()
+ . = ..()
+ if(darksight)
+ darksight.icon_state = "ghost"
+ darksight.alpha = 127
+ darksight.SetTransform(2) //Max darksight
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 05d4206efcb14..1bf481795d7c5 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -4,11 +4,10 @@
log_access("Logout: [key_name(src)]")
handle_admin_logout()
if(my_client)
- my_client.screen -= l_general
-
+ my_client.screen -= darksight
RemoveRenderers()
- QDEL_NULL(l_general)
+ QDEL_NULL(darksight)
hide_client_images()
..()
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index de518efca29bc..71907054b189e 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -86,7 +86,7 @@
AddOverlays(os.get_keyboard_overlay())
if(enabled)
- set_light(0.2, 0.1, light_strength)
+ set_light(light_strength, 0.2)
else
set_light(0)
diff --git a/code/modules/modular_computers/computers/subtypes/dev_console.dm b/code/modules/modular_computers/computers/subtypes/dev_console.dm
index 1cdd458090d66..93dc31bab52e8 100644
--- a/code/modules/modular_computers/computers/subtypes/dev_console.dm
+++ b/code/modules/modular_computers/computers/subtypes/dev_console.dm
@@ -48,7 +48,7 @@
var/datum/extension/interactive/ntos/os = get_extension(src, /datum/extension/interactive/ntos)
if(os)
if(os.on)
- set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color)
+ set_light(light_range_on, light_power_on, light_color)
else
set_light(0)
diff --git a/code/modules/multiz/zmimic/mimic_movable.dm b/code/modules/multiz/zmimic/mimic_movable.dm
index 81ed570387bc9..fe780df31e673 100644
--- a/code/modules/multiz/zmimic/mimic_movable.dm
+++ b/code/modules/multiz/zmimic/mimic_movable.dm
@@ -79,10 +79,11 @@
name = "openspace multiplier"
desc = "You shouldn't see this."
icon = 'icons/effects/lighting_overlay.dmi'
- icon_state = "dark"
+ icon_state = LIGHTING_TRANSPARENT_ICON_STATE
plane = OPENTURF_MAX_PLANE
layer = MIMICED_LIGHTING_LAYER
- color = "#0000004b"
+ color = SHADOWER_DARKENING_COLOR
+ //blend_mode = BLEND_MULTIPLY
/atom/movable/openspace/multiplier/Destroy()
var/turf/myturf = loc
@@ -96,38 +97,36 @@
layer = MIMICED_LIGHTING_LAYER
plane = OPENTURF_MAX_PLANE
invisibility = 0
- blend_mode = BLEND_MULTIPLY
- if (icon_state == null)
+
+ if (icon_state == LIGHTING_BASE_ICON_STATE)
+ blend_mode = BLEND_MULTIPLY
// We're using a color matrix, so just darken the colors across the board.
- // Bay stores lights as inverted so the lighting PM can invert it for darksight, but
- // we don't have a plane master, so invert it again.
var/list/c_list = color
- c_list[CL_MATRIX_RR] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_RG] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_RB] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_GR] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_GG] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_GB] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_BR] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_BG] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_BB] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_AR] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_AG] *= -SHADOWER_DARKENING_FACTOR
- c_list[CL_MATRIX_AB] *= -SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_RR] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_RG] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_RB] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_GR] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_GG] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_GB] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_BR] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_BG] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_BB] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_AR] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_AG] *= SHADOWER_DARKENING_FACTOR
+ c_list[CL_MATRIX_AB] *= SHADOWER_DARKENING_FACTOR
color = c_list
+
+ //Hackfix until I look into planes a bit more, we copy the plane of turf
+ var/turf/myturf = loc
+ if (istype(myturf))
+ plane = myturf.plane
else
- // Not a color matrix, so we just ignore the lighting values.
- icon_state = "dark" // this is actually just a white sprite, which is what this blending needs
- color = list(
- SHADOWER_DARKENING_FACTOR, 0, 0,
- 0, SHADOWER_DARKENING_FACTOR, 0,
- 0, 0, SHADOWER_DARKENING_FACTOR
- )
+ // Not a color matrix, so we can just use the color var ourselves.
+ color = (icon_state == LIGHTING_DARKNESS_ICON_STATE) ? COLOR_WHITE : SHADOWER_DARKENING_COLOR
var/turf/parent = loc
ASSERT(isturf(parent))
- if (LAZYLEN(parent.ao_overlays_mimic))
- AddOverlays(parent.ao_overlays_mimic)
+ UpdateOverlays()
if (bound_overlay)
update_above()
diff --git a/code/modules/multiz/zmimic/mimic_turf.dm b/code/modules/multiz/zmimic/mimic_turf.dm
index f708119d10c84..400170e114378 100644
--- a/code/modules/multiz/zmimic/mimic_turf.dm
+++ b/code/modules/multiz/zmimic/mimic_turf.dm
@@ -70,6 +70,23 @@
update_mimic(!mapload) // Only recursively update if the map isn't loading.
+ //Update lights if mapload, else if we're changing turf this will be overriden by corner copy step
+ if(mapload)
+ rebuild_zbleed()
+
+//Force reconsider zbleed
+/turf/proc/rebuild_zbleed()
+ //Only relevant if dynamically lit
+ var/turf/under = GetBelow(src)
+ if(TURF_IS_DYNAMICALLY_LIT_UNSAFE(src) && under)
+ //We need to force recalculation of corners regardless, clear first
+ if(corners && length(corners))
+ for (var/datum/lighting_corner/C in corners)
+ C.clear_below_lumcount()
+ if (under.corners && length(under.corners))
+ for (var/datum/lighting_corner/C in under.corners)
+ C.rebuild_above_below_lumcount()
+
/// Cleans up Z-mimic objects for this turf. You shouldn't call this directly 99% of the time.
/turf/proc/cleanup_zmimic()
SSzcopy.openspace_turfs -= 1
diff --git a/code/modules/overmap/exoplanets/_exoplanet.dm b/code/modules/overmap/exoplanets/_exoplanet.dm
index 4b22bddd8ce97..3deb2b495cbcc 100644
--- a/code/modules/overmap/exoplanets/_exoplanet.dm
+++ b/code/modules/overmap/exoplanets/_exoplanet.dm
@@ -15,11 +15,20 @@ GLOBAL_VAR(planet_repopulation_disabled)
var/list/breathgas = list() //list of gases animals/plants require to survive
var/badgas //id of gas that is toxic to life here
- var/lightlevel = 0 //This default makes turfs not generate light. Adjust to have exoplanents be lit.
- var/night = TRUE
- var/daycycle //How often do we change day and night
- var/daycolumn = 0 //Which column's light needs to be updated next?
- var/daycycle_column_delay = 10 SECONDS
+
+ //DAY/NIGHT CYCLE
+ var/daycycle_range = list(15 MINUTES, 30 MINUTES)
+ var/daycycle = 0//How often do we change day and night, at first list, to determine min and max day length
+ var/sun_process_interval = 1.5 MINUTES //How often we update planetary sunlight
+ var/sun_last_process = null // world.time
+
+ /// 0 means midnight, 1 means noon.
+ var/sun_position = 0
+ /// This a multiplier used to apply to the brightness of ambient lighting. 0.3 means 30% of the brightness of the sun.
+ var/sun_brightness_modifier = 0.5
+
+ /// Sun control
+ var/ambient_group_index = -1
var/maxx
var/maxy
@@ -181,22 +190,84 @@ GLOBAL_VAR(planet_repopulation_disabled)
daddy.group_multiplier = Z.air.group_multiplier
Z.air.equalize(daddy)
- if (daycycle)
- if (tick % round(daycycle / wait) == 0)
- night = !night
- daycolumn = 1
- if (daycolumn && tick % round(daycycle_column_delay / wait) == 0)
- update_daynight()
-
-/obj/effect/overmap/visitable/sector/exoplanet/proc/update_daynight()
- var/light = 0.1
- if (!night)
- light = lightlevel
- for (var/turf/simulated/floor/exoplanet/T in block(locate(daycolumn,1,min(map_z)),locate(daycolumn,maxy,max(map_z))))
- T.set_light(light, 0.1, 2)
- daycolumn++
- if (daycolumn > maxx)
- daycolumn = 0
+ if(sun_last_process <= (world.time - sun_process_interval))
+ update_sun()
+
+/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_daycycle()
+ daycycle = rand(daycycle_range[1], daycycle_range[2])
+ update_sun()
+
+// This changes the position of the sun on the planet.
+/obj/effect/overmap/visitable/sector/exoplanet/proc/update_sun()
+ if(sun_last_process == world.time) //For now, calling it several times in same frame is not valid. Add a parameter to ignore this if weather is added
+ return
+ sun_last_process = world.time
+
+ var/time_of_day = (world.time % daycycle) / daycycle //0 to 1 range.
+
+ var/distance_from_noon = abs(time_of_day - 0.5)
+ sun_position = distance_from_noon / 0.5 // -1 to 1 range
+ sun_position = abs(sun_position - 1)
+
+ var/low_brightness = null
+ var/high_brightness = null
+
+ var/low_color = null
+ var/high_color = null
+ var/min = 0
+ var/max = 0
+
+ //Now, each planet type may want to do its own thing for light, if so move most of this code into its own function and override it.
+ switch(sun_position)
+ if(0 to 0.40) // Night
+ low_brightness = 0.01
+ low_color = "#000066"
+
+ high_brightness = 0.2
+ high_color = "#66004d"
+ min = 0
+ max = 0.4
+
+ if(0.40 to 0.50) // Twilight
+ low_brightness = 0.2
+ low_color = "#66004d"
+
+ high_brightness = 0.5
+ high_color = "#cc3300"
+ min = 0.40
+ max = 0.50
+
+ if(0.50 to 0.70) // Sunrise/set
+ low_brightness = 0.5
+ low_color = "#cc3300"
+
+ high_brightness = 0.8
+ high_color = "#ff9933"
+ min = 0.50
+ max = 0.70
+
+ if(0.70 to 1.00) // Noon
+ low_brightness = 0.8
+ low_color = "#dddddd"
+
+ high_brightness = 1.0
+ high_color = "#ffffff"
+ min = 0.70
+ max = 1.0
+
+ //var/interpolate_weight = (abs(min - sun_position)) * 4 Cit interpolation, not sure
+ var/interpolate_weight = (sun_position - min) / (max - min)
+
+ var/new_brightness = (Interpolate(low_brightness, high_brightness, interpolate_weight) ) * sun_brightness_modifier
+
+ //We do a gradient instead of linear interpolation because linear interpolations of colours are unintuitive
+ var/new_color = UNLINT(gradient(low_color, high_color, space = COLORSPACE_HSV, index=interpolate_weight))
+
+ if(ambient_group_index > 0)
+ var/datum/ambient_group/A = SSambient_lighting.ambient_groups[ambient_group_index]
+ A.set_color(new_color, new_brightness)
+ else
+ ambient_group_index = SSambient_lighting.create_ambient_group(new_color, new_brightness)
/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_map()
var/list/grasscolors = plant_colors.Copy()
@@ -231,14 +302,6 @@ GLOBAL_VAR(planet_repopulation_disabled)
for (var/mob/living/simple_animal/A in animals)
adapt_animal(A)
-/obj/effect/overmap/visitable/sector/exoplanet/proc/generate_daycycle()
- if (lightlevel)
- night = FALSE //we start with a day if we have light.
-
- //When you set daycycle ensure that the minimum is larger than [maxx * daycycle_column_delay].
- //Otherwise the right side of the exoplanet can get stuck in a forever day.
- daycycle = rand(10 MINUTES, 40 MINUTES)
-
/obj/effect/landmark/exoplanet_spawn/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
diff --git a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm b/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
index c6323a782aa0c..9cfbfe94d4cb5 100644
--- a/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
+++ b/code/modules/overmap/exoplanets/planet_themes/radiation_bombing.dm
@@ -21,7 +21,7 @@
var/datum/radiation_source/S = new(T, radiation_power, FALSE)
S.range = 4
SSradiation.add_source(S)
- T.set_light(0.4, 1, 2, l_color = PIPE_COLOR_GREEN)
+ T.set_light(2, 0.4, l_color = PIPE_COLOR_GREEN)
for (var/turf/simulated/floor/exoplanet/crater in circlerangeturfs(T, 3))
if (prob(10))
new/obj/item/remains/xeno/charred(crater)
diff --git a/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm b/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm
index 841effa9c5963..964d752068cd0 100644
--- a/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm
+++ b/code/modules/overmap/exoplanets/planet_themes/ruined_city.dm
@@ -22,9 +22,6 @@
for (var/zlevel in E.map_z)
new /datum/random_map/city(null,1,1,zlevel,E.maxx,E.maxy,0,1,1, E.planetary_area)
- if (prob(50))
- E.lightlevel = rand(5,10)/10 //deserts are usually :lit:
-
if (prob(50))
var/datum/exoplanet_theme/robotic_guardians/T = new /datum/exoplanet_theme/robotic_guardians
E.themes += T
diff --git a/code/modules/overmap/exoplanets/planet_types/chlorine.dm b/code/modules/overmap/exoplanets/planet_types/chlorine.dm
index 4b15ab2077924..c641ccc76b428 100644
--- a/code/modules/overmap/exoplanets/planet_types/chlorine.dm
+++ b/code/modules/overmap/exoplanets/planet_types/chlorine.dm
@@ -14,17 +14,11 @@
flora_diversity = 5
fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/hostile/retaliate/beast/samak/alt, /mob/living/simple_animal/yithian, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/retaliate/jelly)
megafauna_types = list(/mob/living/simple_animal/hostile/retaliate/jelly/mega)
+ sun_brightness_modifier = 0.5 //The dense atmosphere makes it all dark
/obj/effect/overmap/visitable/sector/exoplanet/chlorine/get_atmosphere_color()
return "#e5f2bd"
-/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_map()
- if(prob(50))
- lightlevel = rand(7,10)/10 //It could be night.
- else
- lightlevel = 0.1
- ..()
-
/obj/effect/overmap/visitable/sector/exoplanet/chlorine/generate_atmosphere()
..()
if(atmosphere)
diff --git a/code/modules/overmap/exoplanets/planet_types/desert.dm b/code/modules/overmap/exoplanets/planet_types/desert.dm
index 22dbcbe9c6600..8571f108e1538 100644
--- a/code/modules/overmap/exoplanets/planet_types/desert.dm
+++ b/code/modules/overmap/exoplanets/planet_types/desert.dm
@@ -16,7 +16,7 @@
/obj/effect/overmap/visitable/sector/exoplanet/desert/generate_map()
if(prob(70))
- lightlevel = rand(5,10)/10 //deserts are usually :lit:
+ sun_brightness_modifier = rand(4,8)/10 //deserts are usually :lit:
..()
/obj/effect/overmap/visitable/sector/exoplanet/desert/generate_atmosphere()
diff --git a/code/modules/overmap/exoplanets/planet_types/grass.dm b/code/modules/overmap/exoplanets/planet_types/grass.dm
index a548a8089a8d4..0d35671999305 100644
--- a/code/modules/overmap/exoplanets/planet_types/grass.dm
+++ b/code/modules/overmap/exoplanets/planet_types/grass.dm
@@ -12,11 +12,6 @@
fauna_types = list(/mob/living/simple_animal/yithian, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/hostile/retaliate/jelly)
megafauna_types = list(/mob/living/simple_animal/hostile/retaliate/parrot/space/megafauna, /mob/living/simple_animal/hostile/retaliate/goose/dire)
-/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_map()
- if(prob(40))
- lightlevel = rand(1,7)/10 //give a chance of twilight jungle
- ..()
-
/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_atmosphere()
..()
if(atmosphere)
@@ -76,7 +71,7 @@
rock_colors = list(COLOR_ASTEROID_ROCK, COLOR_GRAY80, COLOR_BROWN)
plant_colors = list("#2f573e","#24574e","#6e9280","#9eab88","#868b58", "#84be7c", "RANDOM")
map_generators = list(/datum/random_map/noise/exoplanet/grass/terraformed)
- lightlevel = 0.5
+ sun_brightness_modifier = 0.8 //Fairly bright
has_trees = TRUE
flora_diversity = 8
fauna_types = list(/mob/living/simple_animal/passive/cat, /mob/living/simple_animal/passive/chicken, /mob/living/simple_animal/passive/mouse, /mob/living/simple_animal/passive/opossum, /mob/living/simple_animal/hostile/retaliate/goat, /mob/living/simple_animal/hostile/retaliate/goose, /mob/living/simple_animal/passive/cow)
@@ -100,10 +95,6 @@
atmosphere.temperature = T0C + rand(0, 50)
atmosphere.update_values()
-/obj/effect/overmap/visitable/sector/exoplanet/grass/generate_map()
- lightlevel = rand(0.7,0.9)/10
- ..()
-
/datum/random_map/noise/exoplanet/grass/terraformed
descriptor = "terraformed grass exoplanet"
flora_prob = 15
diff --git a/code/modules/overmap/exoplanets/planet_types/shrouded.dm b/code/modules/overmap/exoplanets/planet_types/shrouded.dm
index 7c1b939fbeb32..e91c5aaccf2c0 100644
--- a/code/modules/overmap/exoplanets/planet_types/shrouded.dm
+++ b/code/modules/overmap/exoplanets/planet_types/shrouded.dm
@@ -7,7 +7,7 @@
plant_colors = list("#3c5434", "#2f6655", "#0e703f", "#495139", "#394c66", "#1a3b77", "#3e3166", "#52457c", "#402d56", "#580d6d")
map_generators = list(/datum/random_map/noise/exoplanet/shrouded, /datum/random_map/noise/ore/poor)
ruin_tags_blacklist = RUIN_HABITAT
- lightlevel = -0.15
+ sun_brightness_modifier = -0.5
surface_color = "#3e3960"
water_color = "#2b2840"
has_trees = TRUE
diff --git a/code/modules/overmap/exoplanets/planet_types/volcanic.dm b/code/modules/overmap/exoplanets/planet_types/volcanic.dm
index a2adbb188812d..2de90133a7671 100644
--- a/code/modules/overmap/exoplanets/planet_types/volcanic.dm
+++ b/code/modules/overmap/exoplanets/planet_types/volcanic.dm
@@ -94,16 +94,18 @@
turf_flags = TURF_DISALLOW_BLOB
var/list/victims
+ ambient_light_multiplier = 1
+
+/turf/simulated/floor/exoplanet/lava/setup_local_ambient()
+ set_ambient_light(COLOR_ORANGE, 1)
+
/turf/simulated/floor/exoplanet/lava/on_update_icon()
return
-/turf/simulated/floor/exoplanet/lava/Initialize()
- . = ..()
- set_light(0.95, 0.5, 2, l_color = COLOR_ORANGE)
-
/turf/simulated/floor/exoplanet/lava/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
+ clear_ambient_light()
/turf/simulated/floor/exoplanet/lava/Entered(atom/movable/AM)
..()
diff --git a/code/modules/overmap/exoplanets/turfs.dm b/code/modules/overmap/exoplanets/turfs.dm
index 1e0b9401c808d..d0abaff9f9f4c 100644
--- a/code/modules/overmap/exoplanets/turfs.dm
+++ b/code/modules/overmap/exoplanets/turfs.dm
@@ -20,8 +20,7 @@
else
initial_gas = list()
temperature = T0C
- //Must be done here, as light data is not fully carried over by ChangeTurf (but overlays are).
- set_light(E.lightlevel, 0.1, 2)
+
if(E.planetary_area && istype(loc, world.area))
ChangeArea(src, E.planetary_area)
..()
@@ -216,6 +215,7 @@
dynamic_lighting = FALSE
icon = null
icon_state = null
+ permit_ao = FALSE
/turf/simulated/planet_edge/Initialize()
. = ..()
diff --git a/code/modules/overmap/ships/computers/helm.dm b/code/modules/overmap/ships/computers/helm.dm
index 3424e05539bdc..a0251cc7effa5 100644
--- a/code/modules/overmap/ships/computers/helm.dm
+++ b/code/modules/overmap/ships/computers/helm.dm
@@ -391,4 +391,4 @@ GLOBAL_LIST_EMPTY(overmap_helm_computers)
set_light(0)
else
icon_state = "tele_nav"
- set_light(light_max_bright_on, light_inner_range_on, light_outer_range_on, 2, light_color)
+ set_light(light_range_on, light_power_on, light_color)
diff --git a/code/modules/overmap/ships/engines/gas_thruster.dm b/code/modules/overmap/ships/engines/gas_thruster.dm
index 1e30a9d949c80..ad2c9a43d8966 100644
--- a/code/modules/overmap/ships/engines/gas_thruster.dm
+++ b/code/modules/overmap/ships/engines/gas_thruster.dm
@@ -206,7 +206,7 @@
/obj/effect/engine_exhaust/New(turf/nloc, ndir)
..(nloc)
nloc.hotspot_expose(1000,125)
- set_light(0.5, 1, 4)
+ set_light(4, 0.5)
set_dir(ndir)
spawn(20)
qdel(src)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index da4d04bc331df..e3d07abcb582f 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -345,7 +345,7 @@
if(update_state & (UPDATE_OPENED1|UPDATE_OPENED2|UPDATE_BROKE))
set_light(0)
else if(update_state & UPDATE_BLUESCREEN)
- set_light(0.8, 0.1, 1, 2, "#00ecff")
+ set_light(1, 0.8, "#00ecff")
else if(!MACHINE_IS_BROKEN(src) && !GET_FLAGS(stat, MACHINE_STAT_MAINT) && update_state & UPDATE_ALLGOOD)
var/color
switch(charging)
@@ -355,7 +355,7 @@
color = "#a8b0f8"
if(2)
color = "#82ff4c"
- set_light(0.8, 0.1, 1, l_color = color)
+ set_light(1, 0.8, l_color = color)
else
set_light(0)
diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm
index b280a56e904cf..ef4ba06c051ea 100644
--- a/code/modules/power/fusion/core/core_field.dm
+++ b/code/modules/power/fusion/core/core_field.dm
@@ -68,7 +68,7 @@
, filter(type="outline", size = 2, color = COLOR_RED)
, filter(type="bloom", size=3, offset = 0.5, alpha = 235))
- set_light(light_min_power, light_min_range / 10, light_min_range)
+ set_light(light_min_range, light_min_power)
last_range = light_min_range
last_power = light_min_power
@@ -147,7 +147,7 @@
alpha = 200
if (last_range != use_range || last_power != use_power || color != light_color)
- set_light(min(use_power, 1), use_range / 6, use_range) //cap first arg at 1 to avoid breaking lighting stuff.
+ set_light(use_range, min(use_power, 1)) //cap first arg at 1 to avoid breaking lighting stuff.
last_range = use_range
last_power = use_power
//Temperature based color
@@ -286,7 +286,7 @@
/obj/effect/fusion_em_field/proc/Rupture()
visible_message(SPAN_DANGER("\The [src] shudders like a dying animal before flaring to eye-searing brightness and rupturing!"))
- set_light(1, 0.1, 15, 2, "#ccccff")
+ set_light(15, 1, "#ccccff")
empulse(get_turf(src), ceil(plasma_temperature/1000), ceil(plasma_temperature/300))
sleep(5)
RadiateAll()
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 69663b349c9e1..10d7ea0bc8637 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -238,6 +238,16 @@
on = powered()
update_icon(FALSE)
+ switch (dir)
+ if(NORTH)
+ light_offset_y = WORLD_ICON_SIZE * 0.5
+ if(SOUTH)
+ light_offset_y = WORLD_ICON_SIZE * -0.5
+ if(EAST)
+ light_offset_x = WORLD_ICON_SIZE * 0.5
+ if(WEST)
+ light_offset_x = WORLD_ICON_SIZE * -0.5
+
/// Fetches the light's color based on area flags. Used for Init and for smartly installing new bulbs during runtime (See light replacers).
/obj/machinery/light/proc/get_color_from_area()
var/light_color = null
@@ -301,14 +311,14 @@
if(current_mode && (current_mode in lightbulb.lighting_modes))
changed = set_light(arglist(lightbulb.lighting_modes[current_mode]))
else
- changed = set_light(lightbulb.b_max_bright, lightbulb.b_inner_range, lightbulb.b_outer_range, lightbulb.b_curve, lightbulb.b_colour)
+ changed = set_light(lightbulb.b_range, lightbulb.b_power, lightbulb.b_colour)
if(trigger && changed && get_status() == LIGHT_OK)
switch_check()
else
update_use_power(POWER_USE_OFF)
set_light(0)
- change_power_consumption((light_outer_range * light_max_bright) * LIGHTING_POWER_FACTOR, POWER_USE_ACTIVE)
+ change_power_consumption((light_range * light_power) * LIGHTING_POWER_FACTOR, POWER_USE_ACTIVE)
/// Returns `lightbulb.status`.
/obj/machinery/light/proc/get_status()
@@ -639,21 +649,15 @@
var/broken_chance = 2
atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CAN_BE_PAINTED
- /// Lighting `max_bright` value when turned on.
- var/b_max_bright = 0.9
- /// Lighting `inner_range` value when turned on.
- var/b_inner_range = 1
- /// Lighting `outer_range` value when turned on
- var/b_outer_range = 5
- /// Lighting `curve` value when turned on.
- var/b_curve = 2
+ var/b_power = 0.7
+ var/b_range = 5
/// Lighting `colour` value when turned on.
var/b_colour = LIGHT_COLOUR_WARM
/**
* List of lists. Alternative lighting modes the bulb supports. Entry index should be the `LIGHTMODE_*` type supported, and the value should be a list of `l_*` lighting values to be applied when the mode is enabled.
*
- * Example: `LIGHTMODE_EMERGENCY = list(l_outer_range = 4, l_max_bright = 1, l_color = LIGHT_COLOUR_E_RED)`
+ * Example: `LIGHTMODE_EMERGENCY = list(l_range = 4, l_power = 1, l_color = LIGHT_COLOUR_E_RED)`
*/
var/list/lighting_modes = list()
@@ -691,9 +695,9 @@
item_state = "c_tube"
matter = list(MATERIAL_GLASS = 100, MATERIAL_ALUMINIUM = 20)
- b_outer_range = 5
+ b_range = 5
lighting_modes = list(
- LIGHTMODE_EMERGENCY = list(l_outer_range = 4, l_max_bright = 1, l_color = LIGHT_COLOUR_E_RED),
+ LIGHTMODE_EMERGENCY = list(l_range = 4, l_power = 1, l_color = LIGHT_COLOUR_E_RED),
)
sound_on = 'sound/machines/lightson.ogg'
@@ -719,10 +723,7 @@
/obj/item/light/tube/large
w_class = ITEM_SIZE_SMALL
name = "large light tube"
- b_max_bright = 0.95
- b_inner_range = 2
- b_outer_range = 8
- b_curve = 2.5
+ b_range = 8
/obj/item/light/tube/large/warm
name = "large light tube (warm)"
@@ -752,12 +753,10 @@
broken_chance = 3
matter = list(MATERIAL_GLASS = 100)
- b_max_bright = 0.6
- b_inner_range = 0.1
- b_outer_range = 4
- b_curve = 3
+ b_power = 0.7
+ b_range = 4
lighting_modes = list(
- LIGHTMODE_EMERGENCY = list(l_outer_range = 3, l_max_bright = 1, l_color = LIGHT_COLOUR_E_RED)
+ LIGHTMODE_EMERGENCY = list(l_range = 3, l_power = 1, l_color = LIGHT_COLOUR_E_RED)
)
/obj/item/light/bulb/warm
@@ -782,7 +781,7 @@
/obj/item/light/bulb/red/readylight
lighting_modes = list(
- LIGHTMODE_READY = list(l_outer_range = 5, l_max_bright = 1, l_color = LIGHT_COLOUR_READY)
+ LIGHTMODE_READY = list(l_range = 5, l_power = 1, l_color = LIGHT_COLOUR_READY)
)
/obj/item/light/throw_impact(atom/hit_atom)
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 4a665e65efe14..e327da37f9d70 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -447,7 +447,7 @@
I.blend_mode = BLEND_ADD
I.alpha = round(255*power_output/max_power_output)
AddOverlays(I)
- set_light(0.7, 0.1, rad_power + power_output - max_safe_output, 2, "#3b97ca")
+ set_light(rad_power + power_output - max_safe_output, 0.7, "#3b97ca")
else
set_light(0)
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index 506789e4ef7a1..679fcbb0feb8e 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -10,7 +10,7 @@
unacidable = TRUE
use_power = POWER_USE_OFF
uncreated_component_parts = null
- light_outer_range = 4
+ light_range = 4
movable_flags = MOVABLE_FLAG_PROXMOVE
var/obj/machinery/field_generator/FG1 = null
var/obj/machinery/field_generator/FG2 = null
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 4b9e7b6e9539e..d5481cb497a30 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -8,7 +8,7 @@
anchored = TRUE
density = TRUE
layer = SINGULARITY_LAYER
- light_outer_range = 6
+ light_range = 6
unacidable = TRUE
var/current_size = 1
diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm
index 63f271a6247d3..3c50c83c253b3 100644
--- a/code/modules/projectiles/effects.dm
+++ b/code/modules/projectiles/effects.dm
@@ -4,8 +4,8 @@
plane = EFFECTS_ABOVE_LIGHTING_PLANE
layer = BEAM_PROJECTILE_LAYER //Muzzle flashes would be above the lighting plane anyways.
//Standard compiletime light vars aren't working here, so we've made some of our own.
- light_outer_range = 2
- light_max_bright = 1
+ light_range = 2
+ light_power = 1
light_color = "#ff00dc"
mouse_opacity = 0
@@ -75,7 +75,7 @@
// Heavy laser beam
//----------------------------
/obj/effect/projectile/laser/heavy
- light_max_bright = 1
+ light_power = 1
/obj/effect/projectile/laser/heavy/tracer
icon_state = "beam_heavy"
@@ -90,7 +90,7 @@
// Pulse laser beam
//----------------------------
/obj/effect/projectile/laser/pulse
- light_max_bright = 1
+ light_power = 1
light_color = COLOR_DEEP_SKY_BLUE
/obj/effect/projectile/laser/pulse/tracer
@@ -107,7 +107,7 @@
// Skrell laser beam
//----------------------------
/obj/effect/projectile/laser/pulse/skrell
- light_max_bright = 1
+ light_power = 1
light_color = "#4c00ff"
/obj/effect/projectile/laser/pulse/skrell/tracer
@@ -124,7 +124,7 @@
//----------------------------
/obj/effect/projectile/pulse/muzzle
icon_state = "muzzle_pulse"
- light_max_bright = 1
+ light_power = 1
light_color = COLOR_DEEP_SKY_BLUE
//----------------------------
@@ -146,7 +146,7 @@
// Emitter beam
//----------------------------
/obj/effect/projectile/laser/emitter
- light_max_bright = 1
+ light_power = 1
light_color = "#00cc00"
/obj/effect/projectile/laser/emitter/tracer
@@ -178,8 +178,8 @@
//----------------------------
/obj/effect/projectile/bullet/muzzle
icon_state = "muzzle_bullet"
- light_outer_range = 5
- light_max_bright = 1
+ light_range = 5
+ light_power = 1
light_color = COLOR_MUZZLE_FLASH
//----------------------------
@@ -247,7 +247,7 @@
//----------------------------
/obj/effect/projectile/pointdefense
light_color = COLOR_GOLD
- light_max_bright = 1
+ light_power = 1
/obj/effect/projectile/pointdefense/tracer
icon_state = "beam_pointdef_d"
@@ -271,4 +271,4 @@
icon_state = "muzzle_incen"
/obj/effect/projectile/incen/impact
- icon_state = "impact_incen"
\ No newline at end of file
+ icon_state = "impact_incen"
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index e3694c1e7ba2e..249e3591e8c05 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -40,7 +40,7 @@
sparks.start()
new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows
- new /obj/effect/effect/smoke/illumination(T, 5, 4, 1, light_colour)
+ new /obj/effect/effect/smoke/illumination(T, 5, 4, 2, light_colour)
//blinds people like the flash round, but in a larger area and can also be used for temporary illumination
/obj/item/projectile/energy/flash/flare
@@ -60,7 +60,7 @@
/obj/item/projectile/energy/flash/flare/on_impact(atom/A)
light_colour = pick("#e58775", "#ffffff", "#faa159", "#e34e0e")
- set_light(1, 2, 6, 1, light_colour)
+ set_light(6, 1, light_colour)
..() //initial flash
//residual illumination
diff --git a/code/modules/psionics/equipment/cerebro_enhancers.dm b/code/modules/psionics/equipment/cerebro_enhancers.dm
index d018984511d28..3ab8a5c9fb92f 100644
--- a/code/modules/psionics/equipment/cerebro_enhancers.dm
+++ b/code/modules/psionics/equipment/cerebro_enhancers.dm
@@ -164,4 +164,4 @@
action_button_name = "Remove Psionic Amplifier"
H.update_action_buttons()
- set_light(0.5, 0.1, 3, 2, l_color = "#880000")
+ set_light(3, 0.5, l_color = "#880000")
diff --git a/code/modules/random_map/drop/droppod.dm b/code/modules/random_map/drop/droppod.dm
index bebfc40d4a308..8bf4cb500d3dd 100644
--- a/code/modules/random_map/drop/droppod.dm
+++ b/code/modules/random_map/drop/droppod.dm
@@ -123,7 +123,7 @@
/datum/random_map/droppod/proc/get_spawned_drop(turf/T)
var/obj/structure/bed/chair/C = new(T)
- C.set_light(0.5, 0.1, 3, 2, l_color = "#cc0000")
+ C.set_light(3, 0.5, l_color = "#cc0000")
var/mob/living/drop
// This proc expects a list of mobs to be passed to the spawner.
// Use the supply pod if you don't want to drop mobs.
diff --git a/code/modules/reagents/heat_sources/thermal_regulator.dm b/code/modules/reagents/heat_sources/thermal_regulator.dm
index 68c9af8bea044..41fcb821023b3 100644
--- a/code/modules/reagents/heat_sources/thermal_regulator.dm
+++ b/code/modules/reagents/heat_sources/thermal_regulator.dm
@@ -129,7 +129,7 @@
AddOverlays(emissive_appearance(icon, "[icon_state]_lights_cold"))
glow_icon.alpha = clamp(temperature - MINIMUM_GLOW_TEMPERATURE, MINIMUM_GLOW_VALUE, MAXIMUM_GLOW_VALUE)
LAZYADD(adding_overlays, glow_icon)
- set_light(0.2, 0.1, 1, l_color = COLOR_GREEN)
+ set_light(1, 0.2, l_color = COLOR_GREEN)
else
set_light(0)
else
diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm
index 5d695680b18b8..0ef2ef51f7d88 100644
--- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm
+++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm
@@ -119,7 +119,7 @@
if (rag)
var/underlay_image = image(icon='icons/obj/food/drinks.dmi', icon_state=rag.on_fire? "[rag_underlay]_lit" : rag_underlay)
underlays += underlay_image
- set_light(rag.light_max_bright, 0.1, rag.light_outer_range, 2, rag.light_color)
+ set_light(rag.light_range, rag.light_power, rag.light_color)
else
set_light(0)
diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm
index fc58040f63ca5..c21b9f949f458 100644
--- a/code/modules/research/message_server.dm
+++ b/code/modules/research/message_server.dm
@@ -105,7 +105,7 @@ var/global/list/obj/machinery/message_server/message_servers = list()
playsound(Console.loc, 'sound/machines/twobeep.ogg', 50, 1)
Console.audible_message("[icon2html(Console, viewers(get_turf(Console)))][SPAN_NOTICE("\The [Console] announces: 'Message received from [sender].'")]", hearing_distance = 5)
Console.message_log += "Message from [sender]
[authmsg]"
- Console.set_light(0.3, 0.1, 2)
+ Console.set_light(2, 0.5)
/obj/machinery/message_server/interface_interact(mob/user)
diff --git a/code/modules/shieldgen/shieldwallgen.dm b/code/modules/shieldgen/shieldwallgen.dm
index 3832a7c76b0f3..26cc56bde2575 100644
--- a/code/modules/shieldgen/shieldwallgen.dm
+++ b/code/modules/shieldgen/shieldwallgen.dm
@@ -261,7 +261,7 @@
anchored = TRUE
density = TRUE
unacidable = TRUE
- light_outer_range = 3
+ light_range = 3
var/needs_power = 0
var/active = 1
var/delay = 5
diff --git a/code/modules/shuttles/landmarks.dm b/code/modules/shuttles/landmarks.dm
index 1c2f74004f32f..05c45e096055d 100644
--- a/code/modules/shuttles/landmarks.dm
+++ b/code/modules/shuttles/landmarks.dm
@@ -221,7 +221,7 @@
AddOverlays(image)
pixel_x = rand(-6, 6)
pixel_y = rand(-6, 6)
- set_light(0.7, 0.1, 7, 2, "#85d1ff")
+ set_light(7, 0.7, "#85d1ff")
else
icon_state = initial(icon_state)
ClearOverlays()
diff --git a/code/modules/spells/aoe_turf/conjure/construct.dm b/code/modules/spells/aoe_turf/conjure/construct.dm
index 7cbafc56e200f..703b542954bfb 100644
--- a/code/modules/spells/aoe_turf/conjure/construct.dm
+++ b/code/modules/spells/aoe_turf/conjure/construct.dm
@@ -117,4 +117,4 @@
icon = 'icons/effects/effects.dmi'
icon_state = "m_shield_cult"
light_color = "#b40000"
- light_outer_range = 2
+ light_range = 2
diff --git a/code/modules/spells/racial_wizard.dm b/code/modules/spells/racial_wizard.dm
index d787c2123b45d..2e3008986150c 100644
--- a/code/modules/spells/racial_wizard.dm
+++ b/code/modules/spells/racial_wizard.dm
@@ -59,7 +59,7 @@
return
var/obj/O = new /obj(T)
- O.set_light(-10, 0.1, 10, 2, "#ffffff")
+ O.set_light(10, -10, "#ffffff")
spawn(duration)
qdel(O)
diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm
index 2e7fd46063330..0caebad6954c4 100644
--- a/code/modules/supermatter/supermatter.dm
+++ b/code/modules/supermatter/supermatter.dm
@@ -31,7 +31,7 @@
icon_state = "supermatter"
density = TRUE
anchored = FALSE
- light_outer_range = 4
+ light_range = 4
layer = ABOVE_HUMAN_LAYER
@@ -275,8 +275,8 @@
//Changes color and luminosity of the light to these values if they were not already set
/obj/machinery/power/supermatter/proc/shift_light(lum, clr)
- if(lum != light_outer_range || clr != light_color)
- set_light(1, 0.1, lum, l_color = clr)
+ if(lum != light_range || clr != light_color)
+ set_light(lum, 1, l_color = clr)
/obj/machinery/power/supermatter/proc/get_integrity()
var/integrity = damage / explosion_point
diff --git a/code/modules/xenoarcheaology/effects/hellportal/portals.dm b/code/modules/xenoarcheaology/effects/hellportal/portals.dm
index 92b29c9c9c799..c9f1cef06da13 100644
--- a/code/modules/xenoarcheaology/effects/hellportal/portals.dm
+++ b/code/modules/xenoarcheaology/effects/hellportal/portals.dm
@@ -1,7 +1,7 @@
/obj/effect/gateway/artifact
name = "reality tear"
desc = "A piercing pain strikes your mind as you peer into the tear, witnessing horrors and suffering beyond comprehension."
- light_outer_range=5
+ light_range=5
light_color="#ff0000"
spawnable = list(
/mob/living/simple_animal/hostile/meat/abomination = 5,
@@ -45,7 +45,7 @@
/obj/effect/gateway/artifact/big
name = "interdimensional gateway"
desc = "A huge hole in reality with a strange, pulsing heartbeat. Faint, agonized screams can be heard from inside it..."
- light_outer_range = 10
+ light_range = 10
///Ticks down every so often until portal vanishes.
var/health = 15
///How many mobs we've spawned.
diff --git a/config/example/config.txt b/config/example/config.txt
index 66e295bc4b9dd..4f22546e84923 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -327,8 +327,8 @@ EVENT_CUSTOM_START_MAJOR 80;100
## The delay in minutes before an observer that has returned to the main menu may rejoin the game.
#RESPAWN_MENU_DELAY 0
-## Strength of ambient star light. Set to 0 or less to turn off. A value of 1 is unlikely to have a noticeable effect in most lighting systems.
-STARLIGHT 0
+## Enables and disables starlight. This will make space turfs and some turfs considered to be in exterior areas to be lit based on the colour of the background parallax.
+STARLIGHT 1
## Defines which races are allowed to join as ERT, in singular form. If unset, defaults to only human. Casing matters, separate using ;
## Example races include: Human, Tajara, Skrell, Unathi
diff --git a/icons/effects/lighting_overlay.dmi b/icons/effects/lighting_overlay.dmi
index e5e4573b5845e..b2c14395dd2e7 100644
Binary files a/icons/effects/lighting_overlay.dmi and b/icons/effects/lighting_overlay.dmi differ
diff --git a/icons/effects/lighting_overlay.png b/icons/effects/lighting_overlay.png
deleted file mode 100644
index b317268b702d5..0000000000000
Binary files a/icons/effects/lighting_overlay.png and /dev/null differ
diff --git a/icons/mob/darksight.dmi b/icons/mob/darksight.dmi
new file mode 100644
index 0000000000000..5ef6261d414c6
Binary files /dev/null and b/icons/mob/darksight.dmi differ
diff --git a/maps/away/blueriver/blueriver.dm b/maps/away/blueriver/blueriver.dm
index 61e01002cc432..bb17447f1056a 100644
--- a/maps/away/blueriver/blueriver.dm
+++ b/maps/away/blueriver/blueriver.dm
@@ -142,7 +142,7 @@
/turf/simulated/floor/away/blueriver/alienfloor/Initialize()
.=..()
- set_light(0.7, 1, 5, l_color = "#0066ff")
+ set_light(5, 0.7, l_color = "#0066ff")
/turf/unsimulated/wall/away/blueriver/livingwall
name = "alien wall"
@@ -173,7 +173,7 @@
.=..()
icon_state = "bluespacecrystal[rand(1,3)]"
- set_light(0.7, 1, 5, l_color = "#0066ff")
+ set_light(5, 1, l_color = "#0066ff")
/turf/unsimulated/wall/supermatter/no_spread/Process()
return PROCESS_KILL
diff --git a/maps/away/magshield/magshield.dm b/maps/away/magshield/magshield.dm
index b51502d381102..5947485744ee9 100644
--- a/maps/away/magshield/magshield.dm
+++ b/maps/away/magshield/magshield.dm
@@ -49,8 +49,8 @@
icon_state = "maggen"
anchored = TRUE
density = TRUE
- light_outer_range = 3
- light_max_bright = 1
+ light_range = 3
+ light_power = 1
light_color = "#ffea61"
var/heavy_range = 10
var/lighter_range = 20
@@ -130,13 +130,13 @@
icon_state = "nav_light_green"
anchored = TRUE
density = TRUE
- light_outer_range = 10
- light_max_bright = 1
+ light_range = 10
+ light_power = 1
light_color = "#00ee00"
/obj/structure/magshield/nav_light/New()//try make flashing through the process
..()
- set_light(light_max_bright, light_outer_range / 6, light_outer_range, 2, light_color)
+ set_light(light_range, light_power, light_color)
/obj/structure/magshield/nav_light/red
desc = "Large and bright light regularly emitting red flashes."
diff --git a/maps/away/skrellscoutship/skrellscoutship_machines.dm b/maps/away/skrellscoutship/skrellscoutship_machines.dm
index e0413efe4ea9e..485a0e9a33338 100644
--- a/maps/away/skrellscoutship/skrellscoutship_machines.dm
+++ b/maps/away/skrellscoutship/skrellscoutship_machines.dm
@@ -41,7 +41,7 @@
if(on)
AddOverlays(field_image)
- set_light(0.8, 1, 6, l_color = COLOR_CYAN)
+ set_light(6, 0.8, l_color = COLOR_CYAN)
icon_state = "core1"
else
CutOverlays(field_image)
diff --git a/maps/event/placeholders/placeholders.dm b/maps/event/placeholders/placeholders.dm
index 106e6944f0cd4..6ec350ba50644 100644
--- a/maps/event/placeholders/placeholders.dm
+++ b/maps/event/placeholders/placeholders.dm
@@ -40,16 +40,16 @@ Middle-Click / Ctrl-Click - Jump a placeholder to a point and deselect it
if (isnull(option))
return
selected.color = option
-/* else if (option == "Sensor")
+ else if (option == "Sensor")
option = alert(user, "Sensor Range", null, "Off", "Short", "Far")
if (isnull(option))
return
else if (option == "Off")
selected.set_light(0)
else if (option == "Short")
- selected.set_light(1, 2, 3)
+ selected.set_light(3, 1)
else if (option == "Far")
- selected.set_light(1, 6, 7)*/
+ selected.set_light(7, 1)
else if (option == "Scan")
var/scantext = ""
option = input(user, "Placeholder Scan Description", null, scantext) as null | text
diff --git a/maps/random_ruins/exoplanet_ruins/icarus/icarus.dm b/maps/random_ruins/exoplanet_ruins/icarus/icarus.dm
index f556f1a546625..be9e05912afc9 100644
--- a/maps/random_ruins/exoplanet_ruins/icarus/icarus.dm
+++ b/maps/random_ruins/exoplanet_ruins/icarus/icarus.dm
@@ -38,7 +38,7 @@
S.update_rad_power(radiation_power)
SSradiation.add_source(S)
- loc.set_light(0.4, 1, req_range, l_color = COLOR_LIME) //The goo doesn't last, so this is another indicator
+ loc.set_light(req_range, 0.4, l_color = COLOR_LIME) //The goo doesn't last, so this is another indicator
/obj/effect/icarus_irradiate/Destroy()
. = ..()
diff --git a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm
index c6556b1e5d070..1a467c6476abf 100644
--- a/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm
+++ b/maps/random_ruins/exoplanet_ruins/monoliths/monoliths.dm
@@ -38,7 +38,7 @@
I.layer = ABOVE_LIGHTING_LAYER
I.plane = EFFECTS_ABOVE_LIGHTING_PLANE
AddOverlays(I)
- set_light(0.3, 0.1, 2, l_color = I.color)
+ set_light(2, 0.3, l_color = I.color)
var/turf/simulated/floor/exoplanet/T = get_turf(src)
if(istype(T))
diff --git a/maps/torch/torch_security_state.dm b/maps/torch/torch_security_state.dm
index 997a09050ba39..3d8ede4fd2279 100644
--- a/maps/torch/torch_security_state.dm
+++ b/maps/torch/torch_security_state.dm
@@ -29,9 +29,8 @@
icon = 'icons/misc/security_state.dmi'
alarm_level = "off"
- light_max_bright = 0.25
- light_inner_range = 0.1
- light_outer_range = 1
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_GREEN
light_color_status_display = COLOR_GREEN
@@ -49,9 +48,8 @@
name = "code violet"
alarm_level = "on"
- light_max_bright = 0.5
- light_inner_range = 1
- light_outer_range = 2
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_VIOLET
light_color_status_display = COLOR_VIOLET
@@ -68,9 +66,8 @@
name = "code orange"
alarm_level = "on"
- light_max_bright = 0.5
- light_inner_range = 1
- light_outer_range = 2
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_ORANGE
light_color_status_display = COLOR_ORANGE
overlay_alarm = "alarm_orange"
@@ -88,9 +85,8 @@
icon = 'icons/misc/security_state.dmi'
alarm_level = "on"
- light_max_bright = 0.5
- light_inner_range = 1
- light_outer_range = 2
+ light_range = 2
+ light_power = 1
light_color_alarm = COLOR_BLUE
light_color_status_display = COLOR_BLUE
overlay_alarm = "alarm_blue"
@@ -107,9 +103,8 @@
icon = 'icons/misc/security_state.dmi'
alarm_level = "on"
- light_max_bright = 0.75
- light_inner_range = 1
- light_outer_range = 3
+ light_range = 4
+ light_power = 2
light_color_alarm = COLOR_RED
light_color_status_display = COLOR_RED
overlay_alarm = "alarm_red"
@@ -135,9 +130,8 @@
icon = 'icons/misc/security_state.dmi'
alarm_level = "on"
- light_max_bright = 0.75
- light_inner_range = 0.1
- light_outer_range = 3
+ light_range = 4
+ light_power = 2
light_color_alarm = COLOR_RED
light_color_status_display = COLOR_NAVY_BLUE
diff --git a/maps/using.dm b/maps/using.dm
index 926908a4411b1..76dcb3d2e26c0 100644
--- a/maps/using.dm
+++ b/maps/using.dm
@@ -1,5 +1,15 @@
//Easily change which map to build by uncommenting ONE below.
+<<<<<<< ours
+<<<<<<< ours
//#include "example\map.dm"
//#include "torch\map.dm"
#include "sierra\map.dm"
+=======
+#include "example\map.dm"
+//#include "torch\map.dm"
+>>>>>>> theirs
+=======
+//#include "example\map.dm"
+#include "torch\map.dm"
+>>>>>>> theirs
diff --git a/test/check-paths.sh b/test/check-paths.sh
index a419f41432cac..203196b86495c 100755
--- a/test/check-paths.sh
+++ b/test/check-paths.sh
@@ -46,7 +46,7 @@ exactly 2 ">> uses" '(?)>>(?!>)' -P
exactly 0 "incorrect indentations" '^( {4,})' -P
exactly 24 "text2path uses" 'text2path'
exactly 4 "update_icon() override" '/update_icon\((.*)\)' -P
-exactly 5 "goto use" 'goto '
+exactly 4 "goto use" 'goto '
exactly 1 "NOOP match" 'NOOP'
exactly 342 "spawn uses" '^\s*spawn\s*\(\s*(-\s*)?\d*\s*\)' -P
exactly 0 "tag uses" '\stag = ' -P '**/*.dmm'
@@ -56,7 +56,7 @@ exactly 0 "emagged = 0/1" 'emagged\s*=\s*\d' -P
exactly 0 "simulated = 0/1" 'simulated\s*=\s*\d' -P
exactly 2 "var/ in proc arguments" '(^/[^/].+/.+?\(.*?)var/' -P
exactly 0 "tmp/ vars" 'var.*/tmp/' -P
-exactly 6 "uses of .len" '\.len\b' -P
+exactly 7 "uses of .len" '\.len\b' -P
exactly 388 "attackby() override" '\/attackby\((.*)\)' -P
exactly 15 "uses of examine()" '[.|\s]examine\(' -P # If this fails it's likely because you used '/atom/proc/examine(mob)' instead of '/proc/examinate(mob, atom)' - Exception: An examine()-proc may call other examine()-procs
exactly 7 "direct modifications of overlays list" '\boverlays((\s*[|^=+&-])|(\.(Cut)|(Add)|(Copy)|(Remove)|(Remove)))' -P