Files
Matt Atlas 94d92803b4 Replaces our lighting system with CM's. (#21465)
Depends on #21458.

Ports https://github.com/cmss13-devs/cmss13/pull/4229, with the original
authors as:

- https://github.com/tgstation/TerraGov-Marine-Corps/pull/1964 for the
lighting controller (A-lexa)
- https://github.com/tgstation/TerraGov-Marine-Corps/pull/4747 and
https://github.com/tgstation/TerraGov-Marine-Corps/pull/7263 for the
lighting (TiviPlus)
- https://github.com/tgstation/tgstation/pull/54520 for the dir lighting
component
- https://github.com/tgstation/tgstation/pull/75018 for the out of
bounds fix in lighting
- https://github.com/tgstation/TerraGov-Marine-Corps/pull/6678 for the
emissives (TiviPlus)

The main driving reason behind this is that current lighting consumes
way too much processing power, especially for things like odysseys/away
sites where a billion light sources are processing/moving at once and
the game slows down to a crawl. Hopefully this improves the situation by
a good margin, but we will need some testmerging to confirm that.
<img width="1349" height="1349" alt="image"
src="https://github.com/user-attachments/assets/1059ba2b-c0c5-495a-9c76-2d75d0c42bf2"
/>
<img width="1349" height="1349" alt="image"
src="https://github.com/user-attachments/assets/9704b0f6-4cf6-4dfd-a6cb-5702ad07d677"
/>


- [x] Resolve todos
- [x] Look into open space fuckery (border objects)

---------

Co-authored-by: Matt Atlas <liermattia@gmail.com>
Co-authored-by: JohnWildkins <john.wildkins@gmail.com>
2025-11-04 21:27:42 +00:00

219 lines
7.8 KiB
Plaintext

// Returns the atom sitting on the turf.
// For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf.
/proc/get_atom_on_turf(var/atom/movable/M)
var/atom/mloc = M
while(mloc && mloc.loc && !istype(mloc.loc, /turf/))
mloc = mloc.loc
return mloc
/proc/iswall(turf/T)
return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall))
/proc/isfloor(turf/T)
if(locate(/obj/structure/lattice) in T)
return TRUE
else if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor))
return TRUE
return FALSE
//Edit by Nanako
//This proc is used in only two places, ive changed it to make more sense
//The old behaviour returned zero if there were any simulated atoms at all, even pipes and wires
//Now it just finds if the tile is blocked by anything solid.
/proc/turf_clear(turf/T)
if (T.density)
return 0
for(var/atom/A in T)
if(A.density)
return 0
return 1
/proc/get_random_turf_in_range(var/atom/origin, var/outer_range, var/inner_range, var/check_density, var/check_indoors)
origin = get_turf(origin)
if(!origin)
return
var/list/turfs = list()
for(var/turf/T in orange(outer_range, origin))
if(!(T.z in SSatlas.current_map.sealed_levels)) // Picking a turf outside the map edge isn't recommended
if(T.x >= world.maxx-TRANSITIONEDGE || T.x <= TRANSITIONEDGE)
continue
if(T.y >= world.maxy-TRANSITIONEDGE || T.y <= TRANSITIONEDGE)
continue
if(check_density && turf_contains_dense_objects(T))
continue
if(check_indoors)
var/area/A = get_area(T)
if(A.station_area)
continue
if(!inner_range || get_dist(origin, T) >= inner_range)
turfs += T
if(turfs.len)
return pick(turfs)
///Returns a turf based on text inputs, original turf and viewing client
/proc/parse_caught_click_modifiers(list/modifiers, turf/origin, client/viewing_client)
if(!modifiers)
return null
var/screen_loc = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",")
var/list/actual_view = getviewsize(viewing_client ? viewing_client.view : world.view)
var/click_turf_x = splittext(screen_loc[1], ":")
var/click_turf_y = splittext(screen_loc[2], ":")
var/click_turf_z = origin.z
var/click_turf_px = text2num(click_turf_x[2])
var/click_turf_py = text2num(click_turf_y[2])
click_turf_x = origin.x + text2num(click_turf_x[1]) - round(actual_view[1] / 2) - 1
click_turf_y = origin.y + text2num(click_turf_y[1]) - round(actual_view[2] / 2) - 1
var/turf/click_turf = locate(clamp(click_turf_x, 1, world.maxx), clamp(click_turf_y, 1, world.maxy), click_turf_z)
LAZYSET(modifiers, ICON_X, "[(click_turf_px - click_turf.pixel_x) + ((click_turf_x - click_turf.x) * ICON_SIZE_X)]")
LAZYSET(modifiers, ICON_Y, "[(click_turf_py - click_turf.pixel_y) + ((click_turf_y - click_turf.y) * ICON_SIZE_Y)]")
return click_turf
// This proc will check if a neighboring tile in the stated direction "dir" is dense or not
// Will return 1 if it is dense and zero if not
/proc/check_neighbor_density(turf/T, var/dir)
if (!T.loc)
CRASH("The Turf has no location!")
switch (dir)
if (NORTH)
return !turf_clear(get_turf(locate(T.x, T.y+1, T.z)))
if (NORTHEAST)
return !turf_clear(get_turf(locate(T.x+1, T.y+1, T.z)))
if (EAST)
return !turf_clear(get_turf(locate(T.x+1, T.y, T.z)))
if (SOUTHEAST)
return !turf_clear(get_turf(locate(T.x+1, T.y-1, T.z)))
if (SOUTH)
return !turf_clear(get_turf(locate(T.x, T.y-1, T.z)))
if (SOUTHWEST)
return !turf_clear(get_turf(locate(T.x-1, T.y-1, T.z)))
if (WEST)
return !turf_clear(get_turf(locate(T.x-1, T.y, T.z)))
if (NORTHWEST)
return !turf_clear(get_turf(locate(T.x-1, T.y+1, T.z)))
else return
// Picks a turf without a mob from the given list of turfs, if one exists.
// If no such turf exists, picks any random turf from the given list of turfs.
/proc/pick_mobless_turf_if_exists(var/list/start_turfs)
if(!start_turfs.len)
return null
var/list/available_turfs = list()
for(var/start_turf in start_turfs)
var/mob/M = locate() in start_turf
if(!M)
available_turfs += start_turf
if(!available_turfs.len)
available_turfs = start_turfs
return pick(available_turfs)
/proc/turf_contains_dense_objects(var/turf/T)
return T.contains_dense_objects()
/proc/not_turf_contains_dense_objects(var/turf/T)
return !turf_contains_dense_objects(T)
/proc/is_station_turf(var/turf/T)
return T && is_station_level(T.z)
/proc/is_below_sound_pressure(var/turf/T)
var/datum/gas_mixture/environment = T ? T.return_air() : null
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
return TRUE
return FALSE
/*
Turf manipulation
*/
//Returns an assoc list that describes how turfs would be changed if the
//turfs in turfs_src were translated by shifting the src_origin to the dst_origin
/proc/get_turf_translation(turf/src_origin, turf/dst_origin, list/turfs_src)
var/list/turf_map = list()
for(var/turf/source in turfs_src)
var/x_pos = (source.x - src_origin.x)
var/y_pos = (source.y - src_origin.y)
var/z_pos = (source.z - src_origin.z)
var/turf/target = locate(dst_origin.x + x_pos, dst_origin.y + y_pos, dst_origin.z + z_pos)
if(!target)
log_world("ERROR: Null turf in translation @ ([dst_origin.x + x_pos], [dst_origin.y + y_pos], [dst_origin.z + z_pos])")
turf_map[source] = target //if target is null, preserve that information in the turf map
return turf_map
/proc/translate_turfs(var/list/translation, var/area/base_area = null, var/turf/base_turf, var/ignore_background)
. = list()
for(var/turf/source in translation)
var/turf/target = translation[source]
if(target)
if(base_area)
target.change_area(target.loc, get_area(source))
. += transport_turf_contents(source, target, ignore_background)
source.change_area(source.loc, base_area)
else
. += transport_turf_contents(source, target, ignore_background)
//change the old turfs
for(var/turf/source in translation)
if(ignore_background && (source.turf_flags & TURF_FLAG_BACKGROUND))
continue
var/old_turf = base_turf || get_base_turf_by_area(source)
source.ChangeTurf(old_turf)
//Transports a turf from a source turf to a target turf, moving all of the turf's contents and making the target a copy of the source.
//If ignore_background is set to true, turfs with TURF_FLAG_BACKGROUND set will only translate anchored contents.
//Returns the new turf, or list(new turf, source) if a background turf was ignored and things may have been left behind.
/proc/transport_turf_contents(turf/source, turf/target, ignore_background)
var/turf/new_turf
var/is_background = ignore_background && (source.turf_flags & TURF_FLAG_BACKGROUND)
var/supported = FALSE // Whether or not there's an object in the turf which can support other objects.
if(is_background)
new_turf = target
else
new_turf = target.ChangeTurf(source.type, 1, 1)
new_turf.transport_properties_from(source)
for(var/obj/O in source)
if(O.obj_flags & OBJ_FLAG_NOFALL)
supported = TRUE
break
for(var/obj/O in source)
if(O.simulated && (!is_background || supported || O.obj_flags & OBJ_FLAG_MOVES_UNSUPPORTED))
O.forceMove(new_turf)
else if(istype(O,/obj/effect)) // This is used for non-game objects like spawnpoints, so ignore the background check.
var/obj/effect/E = O
if(E.movable_flags & MOVABLE_FLAG_EFFECTMOVE)
E.forceMove(new_turf)
for(var/mob/M in source)
if(is_background && !supported)
continue
if(isEye(M))
continue // If we need to check for more mobs, I'll add a variable
M.forceMove(new_turf)
if(is_background)
return list(new_turf, source)
return new_turf
/proc/air_sound(atom/source, var/required_pressure = SOUND_MINIMUM_PRESSURE)
var/turf/T = get_turf(source)
if(!istype(T)) return FALSE
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
if(pressure < required_pressure)
return FALSE
return TRUE