mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-25 13:07:46 +01:00
Goonlights
Ports Goon Lighting from /vg/station. Summary - This adds smooth edges to all lighting in order to increase the aesthetic appeal of the lighting system. It works by using a matrix to change the appearance of the lighting overlay sprite, which has been changed to be a base for the matrix to modify. Ported from /vg/station with the help of @PJB3005. This lighting system is a hybrid between Mloc's lighting rewrite and Tobba's Goonlights. Notable changes: - Darksight now matters on mobs. The lighting overlays are not alpha=255 when they are completely dark, meaning you can still see the floor- assuming you can view the turf at all, because it retains the luminousity setting. - This means Tajaran have 100% night vision again as they are intended to. Humans can see in a 3x3 square centered around themselves. - No, I'm not changing this, if it's even possible. This is how BYOND's lighting is meant to work. If you have any complaints about game balance, please feel free to make a pull request to change see_in_dark values, which will be seperately evaluated. - The lighting controller now runs at world.tick_lag, to emulate the realtime function of StonedMC. So far with my testing, this hasn't caused any noticable performance decreases- the lighting system is obviously more expensive than our previous iteration, however, it's not the next ZAS ;) Technical Details: - /atom/movable/lighting_overlay/proc/get_clamped_lum has been removed, succeeded by /turf/proc/get_lumcount. They behave identically. - Turf lighting is actually controlled by four "corner" datums, which feed information into the overlay. - The way opacity is factored into the system has changed. Anything that doesn't use set_opacity is not going to work to block light. - /area/lighting_use_dynamic has been renamed to /area/dynamic_lighting, for consistency with /turf/dynamic_lighting. - Lighting is no longer seperately initialized for away missions. It is handled in ChangeTurf() as it should be. Known & Unfixable issues: - There is a 5-10 second delay from starting the round to the lights turning on. Attribute it to "the powernet being spun up" if you would like to- but it's actually just how long it takes the lighting system to update every single turf on the map. - When you walk with a light on you, the light will actually jump ahead of you before you visually get to the tile. This is because of the movement gliding on mobs, realtime lighting actually goes faster than the glide takes to complete, so it appears that your lights are moving faster than you. Thank you krausy~ Animated Goonlights This adds an animate() call to the update_overlays() proc. This makes it so that any light changes will smoothly transition between the changes instead of instantly changing their appearance. Also fixes a few issues pointed out on Github. Change lighting animation (turns out the old one totally breaks if you toggle a light quickly, whoopsies) Kill LIGHTING_INSTANT_UPDATES isturf
This commit is contained in:
@@ -1,10 +1,43 @@
|
||||
#define LIGHTING_INTERVAL 5 // frequency, in 1/10ths of a second, of the lighting process
|
||||
|
||||
#define LIGHTING_FALLOFF 1 // type of falloff to use for lighting; 1 for circular, 2 for square
|
||||
#define LIGHTING_LAMBERTIAN 0 // use lambertian shading for light sources
|
||||
#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
|
||||
|
||||
#define LIGHTING_LAYER 10 // drawing layer for lighting overlays
|
||||
#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
|
||||
#define LIGHTING_ICON 'icons/effects/lighting_overlay.png' // icon used for lighting shading effects
|
||||
|
||||
#define LIGHTING_ROUND_VALUE (1 / 128) //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_SOFT_THRESHOLD 0.05 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays.
|
||||
|
||||
// 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 \
|
||||
) \
|
||||
|
||||
// Helpers so we can (more easily) control the colour matrices.
|
||||
#define CL_MATRIX_RR 1
|
||||
#define CL_MATRIX_RG 2
|
||||
#define CL_MATRIX_RB 3
|
||||
#define CL_MATRIX_RA 4
|
||||
#define CL_MATRIX_GR 5
|
||||
#define CL_MATRIX_GG 6
|
||||
#define CL_MATRIX_GB 7
|
||||
#define CL_MATRIX_GA 8
|
||||
#define CL_MATRIX_BR 9
|
||||
#define CL_MATRIX_BG 10
|
||||
#define CL_MATRIX_BB 11
|
||||
#define CL_MATRIX_BA 12
|
||||
#define CL_MATRIX_AR 13
|
||||
#define CL_MATRIX_AG 14
|
||||
#define CL_MATRIX_AB 15
|
||||
#define CL_MATRIX_AA 16
|
||||
#define CL_MATRIX_CR 17
|
||||
#define CL_MATRIX_CG 18
|
||||
#define CL_MATRIX_CB 19
|
||||
#define CL_MATRIX_CA 20
|
||||
@@ -412,6 +412,23 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/proc/GetRedPart(const/hexa)
|
||||
return hex2num(copytext(hexa, 2, 4))
|
||||
|
||||
/proc/GetGreenPart(const/hexa)
|
||||
return hex2num(copytext(hexa, 4, 6))
|
||||
|
||||
/proc/GetBluePart(const/hexa)
|
||||
return hex2num(copytext(hexa, 6, 8))
|
||||
|
||||
/proc/GetHexColors(const/hexa)
|
||||
return list(
|
||||
GetRedPart(hexa),
|
||||
GetGreenPart(hexa),
|
||||
GetBluePart(hexa),
|
||||
)
|
||||
|
||||
/proc/MinutesToTicks(var/minutes as num)
|
||||
return minutes * 60 * 10
|
||||
|
||||
|
||||
@@ -1,18 +1,91 @@
|
||||
var/global/datum/controller/process/lighting/lighting_controller
|
||||
// Solves problems with lighting updates lagging shit
|
||||
// Max constraints on number of updates per doWork():
|
||||
#define MAX_LIGHT_UPDATES_PER_WORK 100
|
||||
#define MAX_CORNER_UPDATES_PER_WORK 1000
|
||||
#define MAX_OVERLAY_UPDATES_PER_WORK 2000
|
||||
|
||||
/var/lighting_overlays_initialised = FALSE
|
||||
|
||||
/var/list/lighting_update_lights = list() // List of lighting sources queued for update.
|
||||
/var/list/lighting_update_corners = list() // List of lighting corners queued for update.
|
||||
/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update.
|
||||
|
||||
/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated.
|
||||
/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated.
|
||||
/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated.
|
||||
|
||||
|
||||
/datum/controller/process/lighting
|
||||
/datum/controller/process/lighting/setup()
|
||||
name = "lighting"
|
||||
schedule_interval = LIGHTING_INTERVAL
|
||||
start_delay = 1
|
||||
lighting_controller = src
|
||||
|
||||
create_lighting_overlays()
|
||||
schedule_interval = world.tick_lag // run as fast as you possibly can
|
||||
create_all_lighting_overlays()
|
||||
lighting_overlays_initialised = TRUE
|
||||
|
||||
// Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load.
|
||||
spawn(300)
|
||||
doWork()
|
||||
doWork(1)
|
||||
|
||||
/datum/controller/process/lighting/statProcess()
|
||||
..()
|
||||
stat(null, "[last_light_count] lights, [last_overlay_count] overlays")
|
||||
/datum/controller/process/lighting/doWork(roundstart)
|
||||
// Counters
|
||||
var/light_updates = 0
|
||||
var/corner_updates = 0
|
||||
var/overlay_updates = 0
|
||||
|
||||
// Lighting process code located in modules\lighting\lighting_process.dm
|
||||
lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated.
|
||||
lighting_update_lights = list()
|
||||
for(var/datum/light_source/L in lighting_update_lights_old)
|
||||
if(light_updates >= MAX_LIGHT_UPDATES_PER_WORK && !roundstart)
|
||||
lighting_update_lights += L
|
||||
continue // DON'T break, we're adding stuff back into the update queue.
|
||||
|
||||
if(L.check() || L.destroyed || L.force_update)
|
||||
L.remove_lum()
|
||||
if(!L.destroyed)
|
||||
L.apply_lum()
|
||||
|
||||
else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
|
||||
L.vis_update = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
|
||||
light_updates++
|
||||
|
||||
SCHECK
|
||||
|
||||
lighting_update_corners_old = lighting_update_corners //Same as above.
|
||||
lighting_update_corners = list()
|
||||
for(var/A in lighting_update_corners_old)
|
||||
if(corner_updates >= MAX_CORNER_UPDATES_PER_WORK && !roundstart)
|
||||
lighting_update_corners += A
|
||||
continue // DON'T break, we're adding stuff back into the update queue.
|
||||
|
||||
var/datum/lighting_corner/C = A
|
||||
|
||||
C.update_overlays()
|
||||
|
||||
C.needs_update = FALSE
|
||||
|
||||
corner_updates++
|
||||
|
||||
SCHECK
|
||||
|
||||
lighting_update_overlays_old = lighting_update_overlays //Same as above.
|
||||
lighting_update_overlays = list()
|
||||
|
||||
for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old)
|
||||
if(overlay_updates >= MAX_OVERLAY_UPDATES_PER_WORK && !roundstart)
|
||||
lighting_update_overlays += O
|
||||
continue // DON'T break, we're adding stuff back into the update queue.
|
||||
|
||||
O.update_overlay()
|
||||
O.needs_update = 0
|
||||
overlay_updates++
|
||||
SCHECK
|
||||
|
||||
#undef MAX_LIGHT_UPDATES_PER_WORK
|
||||
#undef MAX_CORNER_UPDATES_PER_WORK
|
||||
#undef MAX_OVERLAY_UPDATES_PER_WORK
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
|
||||
return
|
||||
|
||||
/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server"))
|
||||
/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server"))
|
||||
set category = "Debug"
|
||||
set name = "Debug Controller"
|
||||
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
|
||||
@@ -36,9 +36,6 @@
|
||||
if("Air")
|
||||
debug_variables(air_master)
|
||||
feedback_add_details("admin_verb","DAir")
|
||||
if("Lighting")
|
||||
debug_variables(lighting_controller)
|
||||
feedback_add_details("admin_verb","DLighting")
|
||||
if("Jobs")
|
||||
debug_variables(job_master)
|
||||
feedback_add_details("admin_verb","DJobs")
|
||||
|
||||
@@ -107,14 +107,14 @@ var/list/ghostteleportlocs = list()
|
||||
name = "\improper Admin Room"
|
||||
icon_state = "start"
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
|
||||
/area/adminconstruction
|
||||
name = "\improper Admin Testing Area"
|
||||
icon_state = "start"
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/space
|
||||
icon_state = "space"
|
||||
@@ -467,7 +467,7 @@ var/list/ghostteleportlocs = list()
|
||||
icon_state = "start"
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
has_gravity = 1
|
||||
|
||||
// === end remove
|
||||
@@ -483,7 +483,7 @@ var/list/ghostteleportlocs = list()
|
||||
name = "\improper Centcom"
|
||||
icon_state = "centcom"
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/centcom/control
|
||||
name = "\improper Centcom Control"
|
||||
@@ -564,7 +564,7 @@ var/list/ghostteleportlocs = list()
|
||||
name = "\improper Thunderdome"
|
||||
icon_state = "thunder"
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
|
||||
/area/tdome/arena_source
|
||||
@@ -649,7 +649,7 @@ var/list/ghostteleportlocs = list()
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/wizard_station
|
||||
name = "\improper Wizard's Den"
|
||||
@@ -672,7 +672,7 @@ var/list/ghostteleportlocs = list()
|
||||
name = "\improper Vox Base"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
no_teleportlocs = 1
|
||||
|
||||
/area/vox_station/transit
|
||||
@@ -1229,7 +1229,7 @@ var/list/ghostteleportlocs = list()
|
||||
/area/holodeck
|
||||
name = "\improper Holodeck"
|
||||
icon_state = "Holodeck"
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/holodeck/alphadeck
|
||||
name = "\improper Holodeck Alpha"
|
||||
@@ -1366,7 +1366,7 @@ var/list/ghostteleportlocs = list()
|
||||
|
||||
/area/solar
|
||||
requires_power = 0
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
auxport
|
||||
name = "\improper Fore Port Solar Array"
|
||||
@@ -2281,25 +2281,25 @@ area/security/podbay
|
||||
name = "\improper AI Sat Ext"
|
||||
icon_state = "storage"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/turret_protected/AIsatextFS
|
||||
name = "\improper AI Sat Ext"
|
||||
icon_state = "storage"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/turret_protected/AIsatextAS
|
||||
name = "\improper AI Sat Ext"
|
||||
icon_state = "storage"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/turret_protected/AIsatextAP
|
||||
name = "\improper AI Sat Ext"
|
||||
icon_state = "storage"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
|
||||
/area/turret_protected/NewAIMain
|
||||
name = "\improper AI Main New"
|
||||
@@ -2476,7 +2476,7 @@ area/security/podbay
|
||||
name = "Beach"
|
||||
icon_state = "beach"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
requires_power = 0
|
||||
ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg')
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
if(type == /area) // override defaults for space. TODO: make space areas of type /area/space rather than /area
|
||||
requires_power = 1
|
||||
always_unpowered = 1
|
||||
lighting_use_dynamic = 1
|
||||
dynamic_lighting = 1
|
||||
power_light = 0
|
||||
power_equip = 0
|
||||
power_environ = 0
|
||||
|
||||
@@ -32,7 +32,13 @@
|
||||
/atom/movable/Destroy()
|
||||
for(var/atom/movable/AM in contents)
|
||||
qdel(AM)
|
||||
var/turf/un_opaque
|
||||
if(opacity && isturf(loc))
|
||||
un_opaque = loc
|
||||
|
||||
loc = null
|
||||
if(un_opaque)
|
||||
un_opaque.recalc_atom_opacity()
|
||||
if(pulledby)
|
||||
if(pulledby.pulling == src)
|
||||
pulledby.pulling = null
|
||||
|
||||
@@ -57,12 +57,7 @@
|
||||
var/turf/simulated/T = get_turf(M)
|
||||
if(!istype(T))
|
||||
return
|
||||
var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T
|
||||
var/light_available
|
||||
if(L)
|
||||
light_available = L.get_clamped_lum()*10
|
||||
else
|
||||
light_available = 5
|
||||
var/light_available = T.get_lumcount() * 10
|
||||
if(light_available <= 2)
|
||||
M.alpha = round(M.alpha * 0.8)
|
||||
else
|
||||
|
||||
@@ -416,12 +416,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
owner.alpha = 255
|
||||
return
|
||||
var/turf/simulated/T = get_turf(owner)
|
||||
var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T
|
||||
var/light_available
|
||||
if(L)
|
||||
light_available = L.get_clamped_lum(0.5) * 10
|
||||
else
|
||||
light_available = 10
|
||||
var/light_available = T.get_lumcount(0.5) * 10
|
||||
|
||||
if(!istype(T))
|
||||
return 0
|
||||
@@ -429,6 +424,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(!iscloaking)
|
||||
owner.alpha = 255
|
||||
return 0
|
||||
|
||||
if(light_available <= 2)
|
||||
owner.alpha = round((255 * 0.15))
|
||||
return 1
|
||||
|
||||
@@ -479,8 +479,7 @@
|
||||
if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius)
|
||||
continue
|
||||
|
||||
var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T
|
||||
var/lightingcount = L.get_clamped_lum(0.5) * 10
|
||||
var/lightingcount = T.get_lumcount(0.5) * 10
|
||||
|
||||
// LIGHTING CHECK
|
||||
if(lightingcount > max_lum)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
..()
|
||||
|
||||
/obj/structure/curtain/proc/toggle()
|
||||
opacity = !opacity
|
||||
set_opacity(!opacity)
|
||||
if(opacity)
|
||||
icon_state = "closed"
|
||||
layer = SHOWER_CLOSED_LAYER
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
|
||||
Close()
|
||||
..()
|
||||
opacity = 0
|
||||
set_opacity(0)
|
||||
|
||||
/obj/structure/mineral_door/transparent/plasma
|
||||
mineralType = "plasma"
|
||||
@@ -228,7 +228,7 @@
|
||||
flick("[mineralType]opening",src)
|
||||
sleep(10)
|
||||
density = 0
|
||||
opacity = 0
|
||||
set_opacity(0)
|
||||
state = 1
|
||||
update_icon()
|
||||
isSwitchingStates = 0
|
||||
@@ -239,7 +239,7 @@
|
||||
flick("[mineralType]closing",src)
|
||||
sleep(10)
|
||||
density = 1
|
||||
opacity = 1
|
||||
set_opacity(1)
|
||||
state = 0
|
||||
update_icon()
|
||||
isSwitchingStates = 0
|
||||
@@ -265,7 +265,7 @@
|
||||
flick("[mineralType]opening",src)
|
||||
sleep(10)
|
||||
density = 0
|
||||
opacity = 0
|
||||
set_opacity(0)
|
||||
state = 1
|
||||
update_icon()
|
||||
isSwitchingStates = 0
|
||||
@@ -280,7 +280,7 @@
|
||||
flick("[mineralType]closing",src)
|
||||
sleep(10)
|
||||
density = 1
|
||||
opacity = 1
|
||||
set_opacity(1)
|
||||
state = 0
|
||||
update_icon()
|
||||
isSwitchingStates = 0
|
||||
|
||||
@@ -55,11 +55,10 @@
|
||||
//lighting check
|
||||
var/light_amount = 0
|
||||
var/turf/T = get_turf(src)
|
||||
var/atom/movable/lighting_overlay/LO = locate(/atom/movable/lighting_overlay) in T
|
||||
if(LO)
|
||||
light_amount = LO.get_clamped_lum(0.5)*10
|
||||
if(T)
|
||||
light_amount = T.get_lumcount(0.5) * 10
|
||||
else
|
||||
light_amount = 10
|
||||
light_amount = 10
|
||||
|
||||
if(light_amount > 2)
|
||||
to_chat(M, "<span class='warning'>It's too bright here to use [src.name]!</span>")
|
||||
|
||||
+14
-17
@@ -24,8 +24,6 @@
|
||||
|
||||
var/PathNode/PNode = null //associated PathNode in the A* algorithm
|
||||
|
||||
var/dynamic_lighting = 1
|
||||
|
||||
flags = 0
|
||||
|
||||
var/image/obscured //camerachunks
|
||||
@@ -161,10 +159,11 @@
|
||||
return src
|
||||
var/old_opacity = opacity
|
||||
var/old_dynamic_lighting = dynamic_lighting
|
||||
var/list/old_affecting_lights = affecting_lights
|
||||
var/old_affecting_lights = affecting_lights
|
||||
var/old_lighting_overlay = lighting_overlay
|
||||
var/old_blueprint_data = blueprint_data
|
||||
var/old_obscured = obscured
|
||||
var/old_corners = corners
|
||||
|
||||
BeforeChange()
|
||||
if(air_master)
|
||||
@@ -178,16 +177,19 @@
|
||||
for(var/turf/space/S in range(W,1))
|
||||
S.update_starlight()
|
||||
|
||||
lighting_overlay = old_lighting_overlay
|
||||
recalc_atom_opacity()
|
||||
|
||||
affecting_lights = old_affecting_lights
|
||||
if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting))
|
||||
reconsider_lights()
|
||||
if(dynamic_lighting != old_dynamic_lighting)
|
||||
if(dynamic_lighting)
|
||||
lighting_build_overlays()
|
||||
else
|
||||
lighting_clear_overlays()
|
||||
if(lighting_overlays_initialised)
|
||||
lighting_overlay = old_lighting_overlay
|
||||
affecting_lights = old_affecting_lights
|
||||
corners = old_corners
|
||||
if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting))
|
||||
reconsider_lights()
|
||||
if(dynamic_lighting != old_dynamic_lighting)
|
||||
if(dynamic_lighting)
|
||||
lighting_build_overlay()
|
||||
else
|
||||
lighting_clear_overlay()
|
||||
|
||||
obscured = old_obscured
|
||||
|
||||
@@ -384,11 +386,6 @@
|
||||
if(ticker)
|
||||
cameranet.updateVisibility(src)
|
||||
|
||||
/turf/proc/get_lumcount() //Gets the lighting level of a given turf.
|
||||
if(lighting_overlay)
|
||||
return lighting_overlay.get_clamped_lum()
|
||||
return 1
|
||||
|
||||
/turf/attackby(obj/item/C, mob/user, params)
|
||||
if(can_lay_cable() && istype(C, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = C
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
name = "\improper Clown Planet"
|
||||
icon_state = "honk"
|
||||
luminosity = 1
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
requires_power = 0
|
||||
report_alerts = 0
|
||||
|
||||
|
||||
/area/awaymission/clownplanet/miningtown
|
||||
name = "\improper Clown Planet - Bananium-o-Rama"
|
||||
icon_state = "away1"
|
||||
|
||||
@@ -13,13 +13,6 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
|
||||
air_master.setup_allturfs(turfs)
|
||||
log_debug("\tTook [stop_watch(subtimer)]s")
|
||||
|
||||
subtimer = start_watch()
|
||||
log_debug("Initializing lighting")
|
||||
for(var/turf/T in turfs)
|
||||
if(T.dynamic_lighting)
|
||||
T.lighting_build_overlays()
|
||||
log_debug("\tTook [stop_watch(subtimer)]s")
|
||||
|
||||
subtimer = start_watch()
|
||||
log_debug("Smoothing tiles")
|
||||
for(var/turf/T in smoothTurfs)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/area/awaymission/upperlevel
|
||||
name = "Open Space"
|
||||
color = "#888"
|
||||
lighting_use_dynamic = 0
|
||||
dynamic_lighting = 0
|
||||
requires_power = 0
|
||||
|
||||
// Used by /turf/unsimulated/floor/upperlevel as a reference for where the other floor is
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
/datum/light_source
|
||||
var/atom/top_atom
|
||||
var/atom/source_atom
|
||||
|
||||
var/turf/source_turf
|
||||
var/light_power
|
||||
var/light_range
|
||||
var/light_color // string, decomposed by parse_light_color()
|
||||
|
||||
var/lum_r
|
||||
var/lum_g
|
||||
var/lum_b
|
||||
|
||||
var/tmp/applied_lum_r
|
||||
var/tmp/applied_lum_g
|
||||
var/tmp/applied_lum_b
|
||||
|
||||
var/list/effect_str
|
||||
var/list/effect_turf
|
||||
|
||||
var/applied
|
||||
|
||||
var/vis_update //Whetever we should smartly recalculate visibility. and then only update tiles that became (in) visible to us
|
||||
var/needs_update
|
||||
var/destroyed
|
||||
var/force_update
|
||||
|
||||
/datum/light_source/New(atom/owner, atom/top)
|
||||
source_atom = owner
|
||||
if(!source_atom.light_sources) source_atom.light_sources = list()
|
||||
source_atom.light_sources += src
|
||||
top_atom = top
|
||||
if(top_atom != source_atom)
|
||||
if(!top.light_sources) top.light_sources = list()
|
||||
top_atom.light_sources += src
|
||||
|
||||
source_turf = top_atom
|
||||
light_power = source_atom.light_power
|
||||
light_range = source_atom.light_range
|
||||
light_color = source_atom.light_color
|
||||
|
||||
parse_light_color()
|
||||
|
||||
effect_str = list()
|
||||
effect_turf = list()
|
||||
|
||||
update()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/light_source/proc/destroy()
|
||||
destroyed = 1
|
||||
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
|
||||
|
||||
/datum/light_source/proc/update(atom/new_top_atom)
|
||||
if(new_top_atom && new_top_atom != top_atom)
|
||||
if(top_atom != source_atom) top_atom.light_sources -= src
|
||||
top_atom = new_top_atom
|
||||
if(top_atom != source_atom)
|
||||
if(!top_atom.light_sources) top_atom.light_sources = list()
|
||||
top_atom.light_sources += src
|
||||
|
||||
if(!needs_update) //Incase we're already updating either way.
|
||||
lighting_update_lights += src
|
||||
needs_update = 1
|
||||
|
||||
/datum/light_source/proc/force_update()
|
||||
force_update = 1
|
||||
if(!needs_update) //Incase we're already updating either way.
|
||||
needs_update = 1
|
||||
lighting_update_lights += src
|
||||
|
||||
/datum/light_source/proc/vis_update()
|
||||
if(!needs_update)
|
||||
needs_update = 1
|
||||
lighting_update_lights += src
|
||||
|
||||
vis_update = 1
|
||||
|
||||
/datum/light_source/proc/check()
|
||||
if(!source_atom || !light_range || !light_power)
|
||||
destroy()
|
||||
return 1
|
||||
|
||||
if(!top_atom)
|
||||
top_atom = source_atom
|
||||
. = 1
|
||||
|
||||
if(istype(top_atom, /turf))
|
||||
if(source_turf != top_atom)
|
||||
source_turf = top_atom
|
||||
. = 1
|
||||
else if(top_atom.loc != source_turf)
|
||||
source_turf = top_atom.loc
|
||||
. = 1
|
||||
|
||||
if(source_atom.light_power != light_power)
|
||||
light_power = source_atom.light_power
|
||||
. = 1
|
||||
|
||||
if(source_atom.light_range != light_range)
|
||||
light_range = source_atom.light_range
|
||||
. = 1
|
||||
|
||||
if(light_range && light_power && !applied)
|
||||
. = 1
|
||||
|
||||
if(source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
. = 1
|
||||
|
||||
/datum/light_source/proc/parse_light_color()
|
||||
if(light_color)
|
||||
lum_r = color2R(light_color) / 255
|
||||
lum_g = color2G(light_color) / 255
|
||||
lum_b = color2B(light_color) / 255
|
||||
else
|
||||
lum_r = 1
|
||||
lum_g = 1
|
||||
lum_b = 1
|
||||
|
||||
#if LIGHTING_FALLOFF == 1 //circular
|
||||
#define LUM_DISTANCE(swapvar, O, T) swapvar = (O.x - T.x)**2 + (O.y - T.y)**2 + LIGHTING_HEIGHT
|
||||
#if LIGHTING_LAMBERTIAN == 1
|
||||
#define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(sqrt(swapvar) / max(1,light_range))) * (1 / sqrt(swapvar + 1)))
|
||||
#else
|
||||
#define LUM_ATTENUATION(swapvar) swapvar = 1 - CLAMP01(sqrt(swapvar) / max(1,light_range))
|
||||
#endif
|
||||
#elif LIGHTING_FALLOFF == 2 //square
|
||||
#define LUM_DISTANCE(swapvar, O, T) swapvar = abs(O.x - T.x) + abs(O.y - T.y) + LIGHTING_HEIGHT
|
||||
#if LIGHTING_LAMBERTIAN == 1
|
||||
#define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(swapvar / max(1,light_range))) * (1 / sqrt(swapvar**2 + 1)))
|
||||
#else
|
||||
#define LUM_ATTENUATION(swapvar) swapvar = CLAMP01(swapvar / max(1,light_range))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LUM_FALLOFF(swapvar, O, T) \
|
||||
LUM_DISTANCE(swapvar, O, T); \
|
||||
LUM_ATTENUATION(swapvar);
|
||||
|
||||
/datum/light_source/proc/apply_lum()
|
||||
applied = 1
|
||||
|
||||
// Cache the applied lum counts.
|
||||
applied_lum_r = lum_r
|
||||
applied_lum_g = lum_g
|
||||
applied_lum_b = lum_b
|
||||
|
||||
if(istype(source_turf))
|
||||
FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
|
||||
if(T.lighting_overlay)
|
||||
var/strength
|
||||
LUM_FALLOFF(strength, T, source_turf)
|
||||
strength *= light_power
|
||||
|
||||
if(!strength) //Don't add turfs that aren't affected to the affected turfs.
|
||||
continue
|
||||
|
||||
strength = round(strength, LIGHTING_ROUND_VALUE) //Screw sinking points.
|
||||
|
||||
effect_str += strength
|
||||
|
||||
T.lighting_overlay.update_lumcount(
|
||||
lum_r * strength,
|
||||
lum_g * strength,
|
||||
lum_b * strength
|
||||
)
|
||||
|
||||
else
|
||||
effect_str += 0
|
||||
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
|
||||
T.affecting_lights += src
|
||||
effect_turf += T
|
||||
END_FOR_DVIEW
|
||||
|
||||
/datum/light_source/proc/remove_lum()
|
||||
applied = 0
|
||||
var/i = 1
|
||||
for(var/turf/T in effect_turf)
|
||||
if(T.affecting_lights)
|
||||
T.affecting_lights -= src
|
||||
|
||||
if(T.lighting_overlay)
|
||||
var/str = effect_str[i]
|
||||
T.lighting_overlay.update_lumcount(-str * applied_lum_r, -str * applied_lum_g, -str * applied_lum_b)
|
||||
|
||||
i++
|
||||
|
||||
effect_str.Cut()
|
||||
effect_turf.Cut()
|
||||
|
||||
/datum/light_source/proc/forget_turf(turf/T)
|
||||
var/idx = effect_turf.Find(T)
|
||||
effect_turf.Cut(idx, idx + 1)
|
||||
effect_str.Cut(idx, idx + 1)
|
||||
|
||||
//Smartly updates the lighting, only removes lum from and adds lum to turfs that actually got changed.
|
||||
//This is for lights that need to reconsider due to nearby opacity changes.
|
||||
//Stupid dumb copy pasta because BYOND and speed.
|
||||
/datum/light_source/proc/smart_vis_update()
|
||||
var/list/view[0]
|
||||
FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
|
||||
view += T //Filter out turfs.
|
||||
END_FOR_DVIEW
|
||||
//This is the part where we calculate new turfs (if any)
|
||||
var/list/new_turfs = view - effect_turf //This will result with all the tiles that are added.
|
||||
for(var/turf/T in new_turfs)
|
||||
if(T.lighting_overlay)
|
||||
LUM_FALLOFF(., T, source_turf)
|
||||
. *= light_power
|
||||
|
||||
if(!.) //Don't add turfs that aren't affected to the affected turfs.
|
||||
continue
|
||||
|
||||
. = round(., LIGHTING_ROUND_VALUE)
|
||||
|
||||
effect_str += .
|
||||
|
||||
T.lighting_overlay.update_lumcount(
|
||||
lum_r * .,
|
||||
lum_g * .,
|
||||
lum_b * .
|
||||
)
|
||||
|
||||
else
|
||||
effect_str += 0
|
||||
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
|
||||
T.affecting_lights += src
|
||||
effect_turf += T
|
||||
|
||||
var/list/old_turfs = effect_turf - view
|
||||
for(var/turf/T in old_turfs)
|
||||
//Insert not-so-huge copy paste from remove_lum().
|
||||
var/idx = effect_turf.Find(T) //Get the index, luckily Find() is cheap in small lists like this. (with small I mean under a couple thousand len)
|
||||
if(T.affecting_lights)
|
||||
T.affecting_lights -= src
|
||||
|
||||
if(T.lighting_overlay)
|
||||
var/str = effect_str[idx]
|
||||
T.lighting_overlay.update_lumcount(-str * lum_r, -str * lum_g, -str * lum_b)
|
||||
|
||||
effect_turf.Cut(idx, idx + 1)
|
||||
effect_str.Cut(idx, idx + 1)
|
||||
|
||||
#undef LUM_FALLOFF
|
||||
#undef LUM_DISTANCE
|
||||
#undef LUM_ATTENUATION
|
||||
@@ -0,0 +1,9 @@
|
||||
/area
|
||||
luminosity = TRUE
|
||||
var/dynamic_lighting = TRUE
|
||||
|
||||
/area/New()
|
||||
. = ..()
|
||||
|
||||
if(dynamic_lighting)
|
||||
luminosity = FALSE
|
||||
@@ -1,19 +1,30 @@
|
||||
/atom
|
||||
var/light_power = 1 // intensity of the light
|
||||
var/light_range = 0 // range in tiles of the light
|
||||
var/light_color // RGB string representing the colour of the light
|
||||
var/light_color // Hexadecimal RGB string representing the colour of the light
|
||||
|
||||
var/datum/light_source/light
|
||||
var/list/light_sources
|
||||
|
||||
/atom/proc/set_light(l_range, l_power, l_color)
|
||||
if(l_power != null) light_power = l_power
|
||||
if(l_range != null) light_range = l_range
|
||||
if(l_color != null) light_color = l_color
|
||||
// Nonsensical value for l_color default, so we can detect if it gets set to null.
|
||||
#define NONSENSICAL_VALUE -99999
|
||||
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE)
|
||||
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
|
||||
|
||||
update_light()
|
||||
|
||||
#undef NONSENSICAL_VALUE
|
||||
|
||||
/atom/proc/update_light()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!light_power || !light_range)
|
||||
if(light)
|
||||
light.destroy()
|
||||
@@ -31,9 +42,14 @@
|
||||
|
||||
/atom/New()
|
||||
. = ..()
|
||||
|
||||
if(light_power && light_range)
|
||||
update_light()
|
||||
|
||||
if(opacity && isturf(loc))
|
||||
var/turf/T = loc
|
||||
T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways.
|
||||
|
||||
/atom/Destroy()
|
||||
if(light)
|
||||
light.destroy()
|
||||
@@ -62,11 +78,22 @@
|
||||
new_loc.reconsider_lights()
|
||||
|
||||
/atom/proc/set_opacity(new_opacity)
|
||||
var/old_opacity = opacity
|
||||
if(new_opacity == opacity)
|
||||
return
|
||||
|
||||
opacity = new_opacity
|
||||
var/turf/T = loc
|
||||
if(old_opacity != new_opacity && istype(T))
|
||||
if(!isturf(T))
|
||||
return
|
||||
|
||||
if(new_opacity == TRUE)
|
||||
T.has_opaque_atom = TRUE
|
||||
T.reconsider_lights()
|
||||
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()
|
||||
|
||||
/obj/item/equipped()
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/var/list/datum/lighting_corner/all_lighting_corners = list()
|
||||
/var/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).
|
||||
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
|
||||
|
||||
// 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/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)
|
||||
|
||||
/datum/lighting_corner
|
||||
var/list/turf/masters = list()
|
||||
var/list/datum/light_source/affecting = list() // 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/lum_r = 0
|
||||
var/lum_g = 0
|
||||
var/lum_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_mx = 0
|
||||
|
||||
var/update_gen = 0
|
||||
|
||||
/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
|
||||
. = ..()
|
||||
|
||||
all_lighting_corners += src
|
||||
|
||||
masters[new_turf] = turn(diagonal, 180)
|
||||
z = new_turf.z
|
||||
|
||||
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.
|
||||
|
||||
x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5)
|
||||
y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5)
|
||||
|
||||
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
|
||||
// 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)
|
||||
|
||||
masters[T] = diagonal
|
||||
i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180))
|
||||
T.corners[i] = src
|
||||
|
||||
// Now the horizontal one.
|
||||
T = get_step(new_turf, horizontal)
|
||||
if (T) // Ditto.
|
||||
if (!T.corners)
|
||||
T.corners = list(null, null, null, null)
|
||||
|
||||
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
|
||||
|
||||
// And finally the vertical one.
|
||||
T = get_step(new_turf, vertical)
|
||||
if (T)
|
||||
if (!T.corners)
|
||||
T.corners = list(null, null, null, null)
|
||||
|
||||
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
|
||||
|
||||
update_active()
|
||||
|
||||
/datum/lighting_corner/proc/update_active()
|
||||
active = FALSE
|
||||
for (var/turf/T in masters)
|
||||
if (T.lighting_overlay)
|
||||
active = TRUE
|
||||
|
||||
// God that was a mess, now to do the rest of the corner code! Hooray!
|
||||
/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b)
|
||||
lum_r += delta_r
|
||||
lum_g += delta_g
|
||||
lum_b += delta_b
|
||||
|
||||
if (!needs_update)
|
||||
needs_update = TRUE
|
||||
lighting_update_corners += 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/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1.
|
||||
. = 1 // factor
|
||||
if (mx > 1)
|
||||
. = 1 / mx
|
||||
|
||||
else if (mx < LIGHTING_SOFT_THRESHOLD)
|
||||
. = 0 // 0 means soft lighting.
|
||||
|
||||
cache_r = lum_r * . || LIGHTING_SOFT_THRESHOLD
|
||||
cache_g = lum_g * . || LIGHTING_SOFT_THRESHOLD
|
||||
cache_b = lum_b * . || LIGHTING_SOFT_THRESHOLD
|
||||
cache_mx = mx
|
||||
|
||||
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
|
||||
lighting_update_overlays += T.lighting_overlay
|
||||
|
||||
|
||||
/datum/lighting_corner/dummy/New()
|
||||
return
|
||||
@@ -1,3 +1,4 @@
|
||||
var/list/all_lighting_overlays = list() // Global list of lighting overlays.
|
||||
/atom/movable/lighting_overlay
|
||||
name = ""
|
||||
mouse_opacity = 0
|
||||
@@ -6,90 +7,75 @@
|
||||
icon = LIGHTING_ICON
|
||||
layer = LIGHTING_LAYER
|
||||
invisibility = INVISIBILITY_LIGHTING
|
||||
color = "#000000"
|
||||
color = LIGHTING_BASE_MATRIX
|
||||
icon_state = "light1"
|
||||
auto_init = 0 // doesn't need special init
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
|
||||
var/lum_r
|
||||
var/lum_g
|
||||
var/lum_b
|
||||
var/lum_r = 0
|
||||
var/lum_g = 0
|
||||
var/lum_b = 0
|
||||
|
||||
var/needs_update
|
||||
var/needs_update = FALSE
|
||||
|
||||
/atom/movable/lighting_overlay/New()
|
||||
/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE)
|
||||
. = ..()
|
||||
verbs.Cut()
|
||||
global.all_lighting_overlays += src
|
||||
|
||||
var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays outside of turfs.
|
||||
T.lighting_overlay = src
|
||||
T.luminosity = 0
|
||||
|
||||
/atom/movable/lighting_overlay/proc/get_clamped_lum(var/minlum = 0, var/maxlum = 1)
|
||||
var/lum = max(lum_r, lum_g, lum_b)
|
||||
if(lum <= minlum)
|
||||
return 0
|
||||
else if(lum >= maxlum)
|
||||
return 1
|
||||
else
|
||||
return (lum - minlum) / (maxlum - minlum)
|
||||
|
||||
/atom/movable/lighting_overlay/proc/update_lumcount(delta_r, delta_g, delta_b)
|
||||
if(!delta_r && !delta_g && !delta_b) //Nothing is being changed all together.
|
||||
if(no_update)
|
||||
return
|
||||
|
||||
var/should_update = 0
|
||||
|
||||
if(!needs_update) //If this isn't true, we're already updating anyways.
|
||||
if(max(lum_r, lum_g, lum_b) < 1) //Any change that could happen WILL change appearance.
|
||||
should_update = 1
|
||||
|
||||
else if(max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b) < 1) //The change would bring us under 1 max lum, again, guaranteed to change appearance.
|
||||
should_update = 1
|
||||
|
||||
else //We need to make sure that the colour ratios won't change in this code block.
|
||||
var/mx1 = max(lum_r, lum_g, lum_b)
|
||||
var/mx2 = max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b)
|
||||
|
||||
if(lum_r / mx1 != (lum_r + delta_r) / mx2 || lum_g / mx1 != (lum_g + delta_g) / mx2 || lum_b / mx1 != (lum_b + delta_b) / mx2) //Stuff would change.
|
||||
should_update = 1
|
||||
|
||||
lum_r = max(lum_r + delta_r, 0) //Lum shouldn't drop below 1
|
||||
lum_g = max(lum_g + delta_g, 0)
|
||||
lum_b = max(lum_b + delta_b, 0)
|
||||
|
||||
if(!needs_update && should_update)
|
||||
needs_update = 1
|
||||
lighting_update_overlays += src
|
||||
update_overlay()
|
||||
|
||||
/atom/movable/lighting_overlay/proc/update_overlay()
|
||||
set waitfor = FALSE
|
||||
var/turf/T = loc
|
||||
|
||||
if(istype(T)) //Incase we're not on a turf, pool ourselves, something happened.
|
||||
if(lum_r == lum_g && lum_r == lum_b) //greyscale
|
||||
blend_mode = BLEND_OVERLAY
|
||||
if(lum_r <= 0)
|
||||
T.luminosity = 0
|
||||
color = "#000000"
|
||||
alpha = 255
|
||||
else
|
||||
T.luminosity = 1
|
||||
color = "#000000"
|
||||
alpha = (1 - min(lum_r, 1)) * 255
|
||||
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
|
||||
alpha = 255
|
||||
var/mx = max(lum_r, lum_g, lum_b)
|
||||
. = 1 // factor
|
||||
if(mx > 1)
|
||||
. = 1/mx
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
color = rgb(lum_r * 255 * ., lum_g * 255 * ., lum_b * 255 * .)
|
||||
if(color != "#000000")
|
||||
T.luminosity = 1
|
||||
else //No light, set the turf's luminosity to 0 to remove it from view()
|
||||
T.luminosity = 0
|
||||
else
|
||||
//warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : "null"]) in update_overlay() and got qdel'ed!") //fucking bullshit bugs means this spams when shuttles move, feel free to fix
|
||||
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!")
|
||||
log_debug("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// 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.
|
||||
|
||||
// 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/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
|
||||
|
||||
var/list/new_matrix = list(
|
||||
cr.cache_r, cr.cache_g, cr.cache_b, 0,
|
||||
cg.cache_r, cg.cache_g, cg.cache_b, 0,
|
||||
cb.cache_r, cb.cache_g, cb.cache_b, 0,
|
||||
ca.cache_r, ca.cache_g, ca.cache_b, 0,
|
||||
0, 0, 0, 1
|
||||
)
|
||||
var/lum = max > LIGHTING_SOFT_THRESHOLD
|
||||
|
||||
if(lum)
|
||||
luminosity = 1
|
||||
animate(src, color = new_matrix, time = 5)
|
||||
else
|
||||
animate(src, color = new_matrix, time = 5)
|
||||
animate(luminosity = 0, time = 0)
|
||||
|
||||
|
||||
|
||||
/atom/movable/lighting_overlay/singularity_act()
|
||||
return
|
||||
@@ -98,10 +84,13 @@
|
||||
return
|
||||
|
||||
/atom/movable/lighting_overlay/Destroy()
|
||||
lighting_update_overlays -= src
|
||||
global.all_lighting_overlays -= src
|
||||
global.lighting_update_overlays -= src
|
||||
global.lighting_update_overlays_old -= src
|
||||
|
||||
var/turf/T = loc
|
||||
if(istype(T))
|
||||
T.lighting_overlay = null
|
||||
T.luminosity = 1
|
||||
|
||||
return ..()
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/datum/controller/process/lighting
|
||||
var/last_light_count = 0
|
||||
var/last_overlay_count = 0
|
||||
|
||||
/datum/controller/process/lighting/doWork()
|
||||
var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from SCHECK don't cause things to be cut from the list without being updated.
|
||||
last_light_count = lighting_update_lights.len
|
||||
lighting_update_lights = null //Nulling it first because of http://www.byond.com/forum/?post=1854520
|
||||
lighting_update_lights = list()
|
||||
|
||||
for(var/datum/light_source/L in lighting_update_lights_old)
|
||||
if(L.destroyed || L.check() || L.force_update)
|
||||
L.remove_lum()
|
||||
if(!L.destroyed)
|
||||
L.apply_lum()
|
||||
|
||||
else if(L.vis_update) //We smartly update only tiles that became (in) visible to use.
|
||||
L.smart_vis_update()
|
||||
|
||||
L.vis_update = 0
|
||||
L.force_update = 0
|
||||
L.needs_update = 0
|
||||
|
||||
SCHECK
|
||||
|
||||
var/list/lighting_update_overlays_old = lighting_update_overlays //Same as above.
|
||||
last_overlay_count = lighting_update_overlays.len
|
||||
lighting_update_overlays = null //Same as above
|
||||
lighting_update_overlays = list()
|
||||
|
||||
for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old)
|
||||
O.update_overlay()
|
||||
O.needs_update = 0
|
||||
|
||||
SCHECK
|
||||
@@ -0,0 +1,16 @@
|
||||
/proc/create_all_lighting_overlays()
|
||||
for(var/zlevel = 1 to world.maxz)
|
||||
create_lighting_overlays_zlevel(zlevel)
|
||||
|
||||
/proc/create_lighting_overlays_zlevel(var/zlevel)
|
||||
ASSERT(zlevel)
|
||||
|
||||
for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
|
||||
if(!T.dynamic_lighting)
|
||||
continue
|
||||
|
||||
var/area/A = T.loc
|
||||
if(!A.dynamic_lighting)
|
||||
continue
|
||||
|
||||
new /atom/movable/lighting_overlay(T, TRUE)
|
||||
@@ -0,0 +1,283 @@
|
||||
// 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/source_atom // The atom that we belong to.
|
||||
|
||||
var/turf/source_turf // The turf under the above.
|
||||
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()
|
||||
|
||||
// Variables for keeping track of the colour.
|
||||
var/lum_r
|
||||
var/lum_g
|
||||
var/lum_b
|
||||
|
||||
// The lumcount values used to apply the light.
|
||||
var/tmp/applied_lum_r
|
||||
var/tmp/applied_lum_g
|
||||
var/tmp/applied_lum_b
|
||||
|
||||
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
|
||||
|
||||
/datum/light_source/New(var/atom/owner, var/atom/top)
|
||||
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()
|
||||
|
||||
top_atom.light_sources += src
|
||||
|
||||
source_turf = top_atom
|
||||
light_power = source_atom.light_power
|
||||
light_range = source_atom.light_range
|
||||
light_color = source_atom.light_color
|
||||
|
||||
parse_light_color()
|
||||
|
||||
effect_str = list()
|
||||
affecting_turfs = list()
|
||||
|
||||
update()
|
||||
|
||||
return ..()
|
||||
|
||||
// Kill ourselves.
|
||||
/datum/light_source/proc/destroy()
|
||||
destroyed = TRUE
|
||||
force_update()
|
||||
if(source_atom)
|
||||
source_atom.light_sources -= src
|
||||
|
||||
if(top_atom)
|
||||
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) \
|
||||
{ \
|
||||
lighting_update_lights += src; \
|
||||
needs_update = TRUE; \
|
||||
}
|
||||
|
||||
// This proc will cause the light source to update the top atom, and add itself to the update queue.
|
||||
/datum/light_source/proc/update(var/atom/new_top_atom)
|
||||
// This top atom is different.
|
||||
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
|
||||
|
||||
top_atom = new_top_atom
|
||||
|
||||
if(top_atom != source_atom)
|
||||
if(!top_atom.light_sources)
|
||||
top_atom.light_sources = list()
|
||||
|
||||
top_atom.light_sources += src // Add ourselves to the light sources of our new top atom.
|
||||
|
||||
effect_update(null)
|
||||
|
||||
// Will force an update without checking if it's actually needed.
|
||||
/datum/light_source/proc/force_update()
|
||||
force_update = 1
|
||||
|
||||
effect_update(null)
|
||||
|
||||
// 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
|
||||
|
||||
effect_update(null)
|
||||
|
||||
// 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_range || !light_power)
|
||||
destroy()
|
||||
return 1
|
||||
|
||||
if(!top_atom)
|
||||
top_atom = source_atom
|
||||
. = 1
|
||||
|
||||
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
|
||||
|
||||
if(source_atom.light_power != light_power)
|
||||
light_power = source_atom.light_power
|
||||
. = 1
|
||||
|
||||
if(source_atom.light_range != light_range)
|
||||
light_range = source_atom.light_range
|
||||
. = 1
|
||||
|
||||
if(light_range && light_power && !applied)
|
||||
. = 1
|
||||
|
||||
if(source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
. = 1
|
||||
|
||||
// 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
|
||||
|
||||
// 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_power; \
|
||||
\
|
||||
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.
|
||||
#define LUM_FALLOFF(C, T)(1 - CLAMP01(sqrt((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
|
||||
|
||||
/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
|
||||
|
||||
FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING)
|
||||
if(!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
|
||||
for(var/datum/lighting_corner/C in T.get_corners())
|
||||
if(C.update_gen == update_gen)
|
||||
continue
|
||||
|
||||
C.update_gen = update_gen
|
||||
C.affecting += src
|
||||
|
||||
if(!C.active)
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
|
||||
APPLY_CORNER(C)
|
||||
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
|
||||
T.affecting_lights += src
|
||||
affecting_turfs += T
|
||||
|
||||
update_gen++
|
||||
|
||||
/datum/light_source/proc/remove_lum()
|
||||
applied = FALSE
|
||||
|
||||
for(var/turf/T in affecting_turfs)
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
else
|
||||
T.affecting_lights -= src
|
||||
|
||||
affecting_turfs.Cut()
|
||||
|
||||
for(var/datum/lighting_corner/C in effect_str)
|
||||
REMOVE_CORNER(C)
|
||||
|
||||
C.affecting -= src
|
||||
|
||||
effect_str.Cut()
|
||||
|
||||
/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
|
||||
if(effect_str.Find(C)) // Already have one.
|
||||
REMOVE_CORNER(C)
|
||||
|
||||
APPLY_CORNER(C)
|
||||
|
||||
/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_range, source_turf, 0)
|
||||
if(!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
corners |= T.get_corners()
|
||||
turfs += T
|
||||
|
||||
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)
|
||||
if(!T.affecting_lights)
|
||||
T.affecting_lights = list(src)
|
||||
else
|
||||
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)
|
||||
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
|
||||
|
||||
APPLY_CORNER(C)
|
||||
|
||||
for(var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners.
|
||||
REMOVE_CORNER(C)
|
||||
C.affecting -= src
|
||||
effect_str -= C
|
||||
|
||||
#undef effect_update
|
||||
#undef LUM_FALLOFF
|
||||
#undef REMOVE_CORNER
|
||||
#undef APPLY_CORNER
|
||||
@@ -1,25 +0,0 @@
|
||||
/var/list/lighting_update_lights = list()
|
||||
/var/list/lighting_update_overlays = list()
|
||||
|
||||
/area/var/lighting_use_dynamic = 1
|
||||
|
||||
// duplicates lots of code, but this proc needs to be as fast as possible.
|
||||
/proc/create_lighting_overlays(zlevel = 0)
|
||||
var/area/A
|
||||
if(zlevel == 0) // populate all zlevels
|
||||
for(var/turf/T in world)
|
||||
if(T.dynamic_lighting)
|
||||
A = T.loc
|
||||
if(A.lighting_use_dynamic)
|
||||
var/atom/movable/lighting_overlay/O = new(T)
|
||||
T.lighting_overlay = O
|
||||
|
||||
else
|
||||
for(var/x = 1; x <= world.maxx; x++)
|
||||
for(var/y = 1; y <= world.maxy; y++)
|
||||
var/turf/T = locate(x, y, zlevel)
|
||||
if(T.dynamic_lighting)
|
||||
A = T.loc
|
||||
if(A.lighting_use_dynamic)
|
||||
var/atom/movable/lighting_overlay/O = new(T)
|
||||
T.lighting_overlay = O
|
||||
@@ -1,26 +1,102 @@
|
||||
/turf
|
||||
var/list/affecting_lights
|
||||
var/atom/movable/lighting_overlay/lighting_overlay
|
||||
var/dynamic_lighting = TRUE
|
||||
luminosity = 1
|
||||
|
||||
var/tmp/lighting_corners_initialised = FALSE
|
||||
|
||||
var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
|
||||
var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay.
|
||||
var/tmp/list/datum/lighting_corner/corners
|
||||
var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
|
||||
|
||||
/turf/New()
|
||||
. = ..()
|
||||
|
||||
if(opacity)
|
||||
has_opaque_atom = TRUE
|
||||
|
||||
// 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)
|
||||
L.vis_update()
|
||||
|
||||
/turf/proc/lighting_clear_overlays()
|
||||
/turf/proc/lighting_clear_overlay()
|
||||
if(lighting_overlay)
|
||||
qdel(lighting_overlay)
|
||||
|
||||
/turf/proc/lighting_build_overlays()
|
||||
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
|
||||
|
||||
var/area/A = loc
|
||||
if(A.lighting_use_dynamic)
|
||||
var/atom/movable/lighting_overlay/O = new(src)
|
||||
lighting_overlay = O
|
||||
// forcibly refresh lighting on this tile
|
||||
// must make light forget tile or it wil remain
|
||||
// convinced that it is already lighting it
|
||||
for(var/datum/light_source/L in affecting_lights)
|
||||
L.forget_turf(src)
|
||||
L.vis_update()
|
||||
if(A.dynamic_lighting)
|
||||
if(!lighting_corners_initialised)
|
||||
generate_missing_corners()
|
||||
|
||||
new /atom/movable/lighting_overlay(src)
|
||||
|
||||
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)
|
||||
|
||||
C.active = TRUE
|
||||
|
||||
// Used to get a scaled lumcount.
|
||||
/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
|
||||
if(!lighting_overlay)
|
||||
return 1
|
||||
|
||||
var/totallums = 0
|
||||
for(var/datum/lighting_corner/L in corners)
|
||||
totallums += max(L.lum_r, L.lum_g, L.lum_b)
|
||||
|
||||
totallums /= 4 // 4 corners, max channel selected, return the average
|
||||
|
||||
totallums =(totallums - minlum) /(maxlum - minlum)
|
||||
|
||||
return CLAMP01(totallums)
|
||||
|
||||
// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
|
||||
/turf/proc/recalc_atom_opacity()
|
||||
has_opaque_atom = FALSE
|
||||
for(var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...)
|
||||
if(A.opacity)
|
||||
has_opaque_atom = TRUE
|
||||
|
||||
// If an opaque movable atom moves around we need to potentially update visibility.
|
||||
/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc)
|
||||
. = ..()
|
||||
|
||||
if(Obj && Obj.opacity)
|
||||
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
|
||||
reconsider_lights()
|
||||
|
||||
/turf/Exited(var/atom/movable/Obj, var/atom/newloc)
|
||||
. = ..()
|
||||
|
||||
if(Obj && Obj.opacity)
|
||||
recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates.
|
||||
reconsider_lights()
|
||||
|
||||
/turf/proc/get_corners()
|
||||
if(has_opaque_atom)
|
||||
return null // Since this proc gets used in a for loop, null won't be looped though.
|
||||
|
||||
return corners
|
||||
|
||||
/turf/proc/generate_missing_corners()
|
||||
lighting_corners_initialised = TRUE
|
||||
if(!corners)
|
||||
corners = list(null, null, null, null)
|
||||
|
||||
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])
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#undef LIGHTING_INTERVAL
|
||||
|
||||
#undef LIGHTING_FALLOFF
|
||||
#undef LIGHTING_LAMBERTIAN
|
||||
#undef LIGHTING_HEIGHT
|
||||
|
||||
#undef LIGHTING_RESOLUTION
|
||||
#undef LIGHTING_LAYER
|
||||
#undef LIGHTING_ICON
|
||||
#undef LIGHTING_ICON
|
||||
|
||||
#undef LIGHTING_BASE_MATRIX
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
dir = possessed_item.dir
|
||||
color = possessed_item.color
|
||||
overlays = possessed_item.overlays
|
||||
opacity = possessed_item.opacity
|
||||
set_opacity(possessed_item.opacity)
|
||||
|
||||
visible_message("<span class='warning'>[src] rises into the air and begins to float!</span>") // Inform those around us that shit's gettin' spooky.
|
||||
animate_ghostly_presence(src, -1, 20, 1)
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
icon_state = "smatter"
|
||||
temperature = T20C+80
|
||||
density = 1
|
||||
opacity = 1
|
||||
set_opacity(1)
|
||||
blocks_air = 1
|
||||
|
||||
spawn(2)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 343 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
+5
-3
@@ -1414,12 +1414,14 @@
|
||||
#include "code\modules\library\computers\checkout.dm"
|
||||
#include "code\modules\library\computers\public.dm"
|
||||
#include "code\modules\lighting\__lighting_docs.dm"
|
||||
#include "code\modules\lighting\light_source.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_process.dm"
|
||||
#include "code\modules\lighting\lighting_system.dm"
|
||||
#include "code\modules\lighting\lighting_setup.dm"
|
||||
#include "code\modules\lighting\lighting_source.dm"
|
||||
#include "code\modules\lighting\lighting_turf.dm"
|
||||
#include "code\modules\lighting\~lighting_undefs.dm"
|
||||
#include "code\modules\logic\converter.dm"
|
||||
#include "code\modules\logic\dual_input.dm"
|
||||
#include "code\modules\logic\logic_base.dm"
|
||||
|
||||
Reference in New Issue
Block a user