From db14882664b55607044bcd50e8eab31bd83f187f Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Thu, 17 Jun 2021 00:18:09 -0400 Subject: [PATCH] Port tg lighting system Also converts planet lighting to a new system Too hard to separate out from this PR --- code/__defines/_planes+layers.dm | 16 +- code/__defines/color.dm | 39 +- code/__defines/dcs/flags.dm | 5 +- code/__defines/dcs/signals.dm | 40 +- code/__defines/flags.dm | 6 + code/__defines/lighting.dm | 171 +++--- code/__defines/misc.dm | 1 + code/__defines/mobs.dm | 49 +- code/__defines/subsystems.dm | 4 +- code/__defines/turfs.dm | 4 +- code/_helpers/lighting.dm | 10 + code/_helpers/sorts/comparators.dm | 3 + code/_helpers/visual_filters.dm | 386 ++++++++++++- code/_onclick/hud/fullscreen.dm | 64 ++- code/_onclick/hud/screen_objects.dm | 7 + code/controllers/subsystems/lighting.dm | 210 +++---- code/controllers/subsystems/overlays.dm | 26 + code/controllers/subsystems/planets.dm | 58 +- code/controllers/verbs.dm | 1 + code/datums/components/_component.dm | 6 +- code/datums/components/overlay_lighting.dm | 511 ++++++++++++++++++ code/datums/elements/_element.dm | 38 +- code/datums/elements/light_blocking.dm | 36 ++ code/datums/mutable_appearance.dm | 9 +- code/game/area/areas.dm | 2 +- code/game/atoms.dm | 18 +- code/game/atoms_movable.dm | 53 +- .../endgame/supermatter_cascade/universe.dm | 4 +- code/game/machinery/computer/computer.dm | 40 +- code/game/machinery/doors/blast_door.dm | 23 +- code/game/machinery/doors/door.dm | 1 + code/game/machinery/doors/multi_tile.dm | 62 +-- code/game/machinery/fire_alarm.dm | 43 +- code/game/machinery/lightswitch.dm | 14 +- code/game/machinery/machinery.dm | 2 + code/game/machinery/portable_turret.dm | 1 + code/game/objects/effects/effect_system.dm | 1 + code/game/objects/effects/misc.dm | 39 +- code/game/objects/effects/overlays.dm | 42 ++ code/game/objects/items.dm | 15 +- code/game/objects/items/devices/flashlight.dm | 138 ++--- code/game/objects/structures.dm | 1 + .../structures/crates_lockers/__closets.dm | 1 + .../crates_lockers/closets/statue.dm | 3 +- code/game/objects/structures/fitness.dm | 1 + code/game/objects/structures/flora/trees.dm | 12 +- code/game/objects/structures/simple_doors.dm | 66 +-- code/game/objects/structures/window.dm | 13 +- code/game/turfs/turf.dm | 4 +- code/game/turfs/turf_changing.dm | 38 +- code/modules/client/preferences.dm | 10 +- code/modules/clothing/clothing.dm | 26 +- code/modules/clothing/clothing_icons.dm | 2 +- code/modules/clothing/head/hardhat.dm | 3 +- code/modules/clothing/head/helmet.dm | 2 +- code/modules/clothing/head/misc_special.dm | 2 +- .../clothing/spacesuits/rig/rig_pieces.dm | 2 +- .../modules/clothing/spacesuits/spacesuits.dm | 3 +- code/modules/clothing/spacesuits/void/void.dm | 23 +- code/modules/lighting/emissive_blocker.dm | 46 ++ code/modules/lighting/lighting_atom.dm | 262 ++++++--- code/modules/lighting/lighting_corner.dm | 189 ++++--- code/modules/lighting/lighting_fake_sun_vr.dm | 50 +- code/modules/lighting/lighting_overlay.dm | 178 +++--- code/modules/lighting/lighting_setup.dm | 26 +- code/modules/lighting/lighting_source.dm | 505 ++++++++++------- code/modules/lighting/lighting_turf.dm | 174 +++--- code/modules/lighting/~lighting_undefs.dm | 7 - code/modules/maps/tg/reader.dm | 1 - code/modules/mining/mine_items.dm | 2 +- code/modules/mining/mine_turfs.dm | 2 +- code/modules/mob/living/carbon/alien/alien.dm | 1 + .../mob/living/carbon/carbon_defines.dm | 1 + .../mob/living/carbon/human/human_species.dm | 1 + .../mob/living/carbon/human/update_icons.dm | 36 +- code/modules/mob/living/life.dm | 4 - code/modules/mob/living/living_defense.dm | 5 +- .../modules/mob/living/silicon/robot/robot.dm | 2 + code/modules/mob/mob_defines.dm | 1 + code/modules/mob/mob_planes.dm | 51 +- code/modules/mob/mob_planes_vr.dm | 3 +- .../mob/new_player/sprite_accessories.dm | 4 + .../mob/new_player/sprite_accessories_ear.dm | 1 + .../mob/new_player/sprite_accessories_tail.dm | 1 + .../mob/new_player/sprite_accessories_taur.dm | 1 + .../mob/new_player/sprite_accessories_wing.dm | 1 + .../computers/modular_computer/core.dm | 28 +- .../computers/modular_computer/variables.dm | 1 + code/modules/planet/planet.dm | 5 +- code/modules/planet/sun.dm | 53 ++ code/modules/planet/weather.dm | 14 + code/modules/power/apc.dm | 66 +-- code/modules/power/lighting.dm | 45 +- code/modules/projectiles/projectile.dm | 3 + icons/effects/light_overlays/light_128.dmi | Bin 0 -> 7040 bytes icons/effects/light_overlays/light_160.dmi | Bin 0 -> 9920 bytes icons/effects/light_overlays/light_192.dmi | Bin 0 -> 13534 bytes icons/effects/light_overlays/light_224.dmi | Bin 0 -> 17004 bytes icons/effects/light_overlays/light_256.dmi | Bin 0 -> 21365 bytes icons/effects/light_overlays/light_288.dmi | Bin 0 -> 26103 bytes icons/effects/light_overlays/light_32.dmi | Bin 0 -> 1140 bytes icons/effects/light_overlays/light_320.dmi | Bin 0 -> 30919 bytes icons/effects/light_overlays/light_352.dmi | Bin 0 -> 35566 bytes icons/effects/light_overlays/light_64.dmi | Bin 0 -> 2482 bytes icons/effects/light_overlays/light_96.dmi | Bin 0 -> 4643 bytes icons/effects/light_overlays/light_cone.dmi | Bin 0 -> 19272 bytes icons/effects/lighting_object.dmi | Bin 0 -> 7562 bytes icons/effects/lighting_overlay.dmi | Bin 7224 -> 0 bytes icons/mob/screen_gen.dmi | Bin 948 -> 956 bytes icons/obj/monitors.dmi | Bin 41079 -> 41127 bytes vorestation.dme | 6 + 111 files changed, 2890 insertions(+), 1296 deletions(-) create mode 100644 code/_helpers/lighting.dm create mode 100644 code/datums/components/overlay_lighting.dm create mode 100644 code/datums/elements/light_blocking.dm create mode 100644 code/modules/lighting/emissive_blocker.dm delete mode 100644 code/modules/lighting/~lighting_undefs.dm create mode 100644 code/modules/planet/sun.dm create mode 100644 icons/effects/light_overlays/light_128.dmi create mode 100644 icons/effects/light_overlays/light_160.dmi create mode 100644 icons/effects/light_overlays/light_192.dmi create mode 100644 icons/effects/light_overlays/light_224.dmi create mode 100644 icons/effects/light_overlays/light_256.dmi create mode 100644 icons/effects/light_overlays/light_288.dmi create mode 100644 icons/effects/light_overlays/light_32.dmi create mode 100644 icons/effects/light_overlays/light_320.dmi create mode 100644 icons/effects/light_overlays/light_352.dmi create mode 100644 icons/effects/light_overlays/light_64.dmi create mode 100644 icons/effects/light_overlays/light_96.dmi create mode 100644 icons/effects/light_overlays/light_cone.dmi create mode 100644 icons/effects/lighting_object.dmi delete mode 100644 icons/effects/lighting_overlay.dmi diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index 551e94183c1..c2dec3a247c 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -122,9 +122,21 @@ What is the naming convention for planes or layers? #define PLANE_ADMIN1 3 //Purely for shenanigans (below lighting) #define PLANE_PLANETLIGHTING 4 //Lighting on planets + #define PLANE_LIGHTING 5 //Where the lighting (and darkness) lives -#define PLANE_LIGHTING_ABOVE 6 //For glowy eyes etc. that shouldn't be affected by darkness -#define PLANE_RUNECHAT 7 + #define LIGHTING_RENDER_TARGET "LIGHT_PLANE" + +#define PLANE_O_LIGHTING_VISUAL 6 //For masking the lighting plane + #define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE" + +#define PLANE_LIGHTING_ABOVE 7 //For glowy eyes etc. that shouldn't be affected by darkness + #define LIGHTING_ABOVE_RENDER_TARGET "LIGHTING_ABOVE_PLANE" + +#define PLANE_EMISSIVE 8 //Glowing lights in otherwise dark areas using overlays/sprites + #define EMISSIVE_RENDER_TARGET "*EMISSIVE_PLANE" + #define EMISSIVE_LAYER_UNBLOCKABLE 9999 + +#define PLANE_RUNECHAT 9 #define PLANE_GHOSTS 10 //Spooooooooky ghooooooosts #define PLANE_AI_EYE 11 //The AI eye lives here diff --git a/code/__defines/color.dm b/code/__defines/color.dm index c3db40eefb3..af112ef4d63 100644 --- a/code/__defines/color.dm +++ b/code/__defines/color.dm @@ -92,6 +92,7 @@ #define COLOR_LIGHT_VIOLET "#e7bfff" #define COLOR_SAN_MARINO_BLUE "#4b75ab" #define COLOR_OLIVE "#52613b" //VOREStation Addition +#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A" #define PIPE_COLOR_GREY "#808080" #define PIPE_COLOR_RED "#ff0000" @@ -171,4 +172,40 @@ #define COLOR_WEBHOOK_DEFAULT 0x8bbbd5 // "#8bbbd5" #define COLOR_WEBHOOK_GOOD 0x2ECC71 // "#2ECC71" #define COLOR_WEBHOOK_POOR 0xE67E22 // "#E67E22" -#define COLOR_WEBHOOK_BAD 0xE74C3C // "#E74C3C" \ No newline at end of file +#define COLOR_WEBHOOK_BAD 0xE74C3C // "#E74C3C" + +//Some defines to generalise colours used in lighting. +//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated +#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130) +#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100) +#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250) + +#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175) +#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225) +#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255) +#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248) +#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225) +#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125) +#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50) +#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50) +#define LIGHT_COLOR_PURPLE "#952CF4" //Light Purple. rgb(149, 44, 244) +#define LIGHT_COLOR_LAVENDER "#9B51FF" //Less-saturated light purple. rgb(155, 81, 255) + +//These ones aren't a direct colour like the ones above, because nothing would fit +#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25) +#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24) +#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75) +#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75) +#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175) +#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250) + +//Lighting values used by the station lights +#define LIGHT_COLOR_FLUORESCENT_TUBE "#E0EFFF" +#define LIGHT_COLOR_FLUORESCENT_FLASHLIGHT "#CDDDFF" +#define LIGHT_COLOR_INCANDESCENT_TUBE "#fffed9" +#define LIGHT_COLOR_INCANDESCENT_BULB "#ffe7ce" +#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66" +#define LIGHT_COLOR_NIGHTSHIFT "#EFCC86" + +//Fake ambient occlusion filter +#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, offset=3, color="#04080F80") diff --git a/code/__defines/dcs/flags.dm b/code/__defines/dcs/flags.dm index 128c9f19387..84d332bd567 100644 --- a/code/__defines/dcs/flags.dm +++ b/code/__defines/dcs/flags.dm @@ -15,7 +15,10 @@ * Only elements created with the same arguments given after `id_arg_index` share an element instance * The arguments are the same when the text and number values are the same and all other values have the same ref */ -#define ELEMENT_BESPOKE (1 << 1) +#define ELEMENT_BESPOKE (1 << 1) +/// Causes all detach arguments to be passed to detach instead of only being used to identify the element +/// When this is used your Detach proc should have the same signature as your Attach proc +#define ELEMENT_COMPLEX_DETACH (1 << 2) // How multiple components of the exact same type are handled in the same datum /// old component is deleted (default) diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index c6edaa80e4a..a4b1a26b33e 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -162,6 +162,8 @@ #define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin" ///called when an atom stops orbiting another atom: (atom) #define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop" +///from base of atom/set_opacity(): (new_opacity) +#define COMSIG_ATOM_SET_OPACITY "atom_set_opacity" ///////////////// ///from base of atom/attack_ghost(): (mob/dead/observer/ghost) #define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost" @@ -737,4 +739,40 @@ #define COMSIG_TRIGGERED_ALARM "ssalarm_triggered" #define COMSIG_CANCELLED_ALARM "ssalarm_cancelled" -#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping" \ No newline at end of file +#define COMSIG_REAGENTS_CRAFTING_PING "reagents_crafting_ping" + +// Lighting: +///from base of [atom/proc/set_light]: (l_range, l_power, l_color, l_on) +#define COMSIG_ATOM_SET_LIGHT "atom_set_light" + /// Blocks [/atom/proc/set_light], [/atom/proc/set_light_power], [/atom/proc/set_light_range], [/atom/proc/set_light_color], [/atom/proc/set_light_on], and [/atom/proc/set_light_flags]. + #define COMPONENT_BLOCK_LIGHT_UPDATE (1<<0) +///Called right before the atom changes the value of light_power to a different one, from base [atom/proc/set_light_power]: (new_power) +#define COMSIG_ATOM_SET_LIGHT_POWER "atom_set_light_power" +///Called right after the atom changes the value of light_power to a different one, from base of [/atom/proc/set_light_power]: (old_power) +#define COMSIG_ATOM_UPDATE_LIGHT_POWER "atom_update_light_power" +///Called right before the atom changes the value of light_range to a different one, from base [atom/proc/set_light_range]: (new_range) +#define COMSIG_ATOM_SET_LIGHT_RANGE "atom_set_light_range" +///Called right after the atom changes the value of light_range to a different one, from base of [/atom/proc/set_light_range]: (old_range) +#define COMSIG_ATOM_UPDATE_LIGHT_RANGE "atom_update_light_range" +///Called right before the atom changes the value of light_color to a different one, from base [atom/proc/set_light_color]: (new_color) +#define COMSIG_ATOM_SET_LIGHT_COLOR "atom_set_light_color" +///Called right after the atom changes the value of light_color to a different one, from base of [/atom/proc/set_light_color]: (old_color) +#define COMSIG_ATOM_UPDATE_LIGHT_COLOR "atom_update_light_color" +///Called right before the atom changes the value of light_on to a different one, from base [atom/proc/set_light_on]: (new_value) +#define COMSIG_ATOM_SET_LIGHT_ON "atom_set_light_on" +///Called right after the atom changes the value of light_on to a different one, from base of [/atom/proc/set_light_on]: (old_value) +#define COMSIG_ATOM_UPDATE_LIGHT_ON "atom_update_light_on" +///Called right before the atom changes the value of light_flags to a different one, from base [atom/proc/set_light_flags]: (new_flags) +#define COMSIG_ATOM_SET_LIGHT_FLAGS "atom_set_light_flags" +///Called right after the atom changes the value of light_flags to a different one, from base of [/atom/proc/set_light_flags]: (old_flags) +#define COMSIG_ATOM_UPDATE_LIGHT_FLAGS "atom_update_light_flags" + +// /datum/element/light_eater +///from base of [/datum/element/light_eater/proc/table_buffet]: (list/light_queue, datum/light_eater) +#define COMSIG_LIGHT_EATER_QUEUE "light_eater_queue" +///from base of [/datum/element/light_eater/proc/devour]: (datum/light_eater) +#define COMSIG_LIGHT_EATER_ACT "light_eater_act" + ///Prevents the default light eater behavior from running in case of immunity or custom behavior + #define COMPONENT_BLOCK_LIGHT_EATER (1<<0) +///from base of [/datum/element/light_eater/proc/devour]: (atom/eaten_light) +#define COMSIG_LIGHT_EATER_DEVOUR "light_eater_devour" diff --git a/code/__defines/flags.dm b/code/__defines/flags.dm index 2ff8f44dbab..aa2db4bb1b4 100644 --- a/code/__defines/flags.dm +++ b/code/__defines/flags.dm @@ -13,6 +13,12 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) +/* Directions */ +///All the cardinal direction bitflags. +#define ALL_CARDINALS (NORTH|SOUTH|EAST|WEST) +///All the dirs except UP and DOWN +#define ALL_FLAT_DIRS (NORTH|SOUTH|EAST|WEST|NORTHWEST|SOUTHWEST|NORTHEAST|SOUTHEAST) + // datum_flags #define DF_VAR_EDITED (1<<0) #define DF_ISPROCESSING (1<<1) diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm index 999bb7473ad..bf854548760 100644 --- a/code/__defines/lighting.dm +++ b/code/__defines/lighting.dm @@ -1,88 +1,119 @@ -#define FOR_DVIEW(type, range, center, invis_flags) \ - dview_mob.loc = center; \ - dview_mob.see_invisible = invis_flags; \ - for(type in view(range, dview_mob)) +///Object doesn't use any of the light systems. Should be changed to add a light source to the object. +#define NO_LIGHT_SUPPORT 0 +///Light made with the lighting datums, applying a matrix. +#define STATIC_LIGHT 1 +///Light made by masking the lighting darkness plane. +#define MOVABLE_LIGHT 2 +///Light made by masking the lighting darkness plane, and is directional. +#define MOVABLE_LIGHT_DIRECTIONAL 3 -#define END_FOR_DVIEW dview_mob.loc = null +///Is a movable light source attached to another movable (its loc), meaning that the lighting component should go one level deeper. +#define LIGHT_ATTACHED (1<<0) -#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 +//Bay lighting engine shit, not in /code/modules/lighting because BYOND is being shit about it +/// frequency, in 1/10ths of a second, of the lighting process +#define LIGHTING_INTERVAL 5 -#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects -#define LIGHTING_ICON_STATE_DARK "soft_dark" // Change between "soft_dark" and "dark" to swap soft darkvision +#define MINIMUM_USEFUL_LIGHT_RANGE 1.4 -#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. +/// type of falloff to use for lighting; 1 for circular, 2 for square +#define LIGHTING_FALLOFF 1 +/// use lambertian shading for light sources +#define LIGHTING_LAMBERTIAN 0 +/// height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone +#define LIGHTING_HEIGHT 1 +/// Value used to round lumcounts, values smaller than 1/129 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_ROUND_VALUE (1 / 64) -#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. This also should be the transparancy of the "soft_dark" icon state. +/// icon used for lighting shading effects +#define LIGHTING_ICON 'icons/effects/lighting_object.dmi' -#define LIGHTING_MULT_FACTOR 0.5 +/// If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting objects. +/// Set to zero to disable soft lighting. Luminosity changes then work if it's lit at all. +#define LIGHTING_SOFT_THRESHOLD 0 -// If I were you I'd leave this alone. +/// 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, \ + 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 -#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 +///How many tiles standard fires glow. +#define LIGHT_RANGE_FIRE 3 -//Some defines to generalise colours used in lighting. -//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated -#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130) -#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100) -#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250) +#define LIGHTING_PLANE_ALPHA_VISIBLE 255 +#define LIGHTING_PLANE_ALPHA_NV_TRAIT 245 +#define LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE 192 +/// For lighting alpha, small amounts lead to big changes. even at 128 its hard to figure out what is dark and what is light, at 64 you almost can't even tell. +#define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128 +#define LIGHTING_PLANE_ALPHA_INVISIBLE 0 -#define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175) -#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225) -#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255) -#define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248) -#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225) -#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125) -#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50) -#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50) -#define LIGHT_COLOR_PURPLE "#952CF4" //Light Purple. rgb(149, 44, 244) -#define LIGHT_COLOR_LAVENDER "#9B51FF" //Less-saturated light purple. rgb(155, 81, 255) +//lighting area defines +/// dynamic lighting disabled (area stays at full brightness) +#define DYNAMIC_LIGHTING_DISABLED 0 +/// dynamic lighting enabled +#define DYNAMIC_LIGHTING_ENABLED 1 +/// dynamic lighting enabled even if the area doesn't require power +#define DYNAMIC_LIGHTING_FORCED 2 +/// dynamic lighting enabled only if starlight is. +#define DYNAMIC_LIGHTING_IFSTARLIGHT 3 +#define IS_DYNAMIC_LIGHTING(A) A.dynamic_lighting -//These ones aren't a direct colour like the ones above, because nothing would fit -#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25) -#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24) -#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75) -#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75) -#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175) -#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250) -//Lighting values used by the station lights -#define LIGHT_COLOR_FLUORESCENT_TUBE "#E0EFFF" -#define LIGHT_COLOR_FLUORESCENT_FLASHLIGHT "#CDDDFF" -#define LIGHT_COLOR_INCANDESCENT_TUBE "#FFFEB8" -#define LIGHT_COLOR_INCANDESCENT_BULB "#FFDDBB" -#define LIGHT_COLOR_INCANDESCENT_FLASHLIGHT "#FFCC66" -#define LIGHT_COLOR_NIGHTSHIFT "#EFCC86" +//code assumes higher numbers override lower numbers. +#define LIGHTING_NO_UPDATE 0 +#define LIGHTING_VIS_UPDATE 1 +#define LIGHTING_CHECK_UPDATE 2 +#define LIGHTING_FORCE_UPDATE 3 -//Fake ambient occlusion filter -#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-1, size=2, offset=2, color="#04080F55") //VOREStation Edit for prettier visuals. +#define FLASH_LIGHT_DURATION 2 +#define FLASH_LIGHT_POWER 3 +#define FLASH_LIGHT_RANGE 3.8 + +// Emissive blocking. +/// Uses vis_overlays to leverage caching so that very few new items need to be made for the overlay. For anything that doesn't change outline or opaque area much or at all. +#define EMISSIVE_BLOCK_GENERIC 1 +/// Uses a dedicated render_target object to copy the entire appearance in real time to the blocking layer. For things that can change in appearance a lot from the base state, like humans. +#define EMISSIVE_BLOCK_UNIQUE 2 + +/// The color matrix applied to all emissive overlays. Should be solely dependent on alpha and not have RGB overlap with [EM_BLOCK_COLOR]. +#define EMISSIVE_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,1,0) +/// A globaly cached version of [EMISSIVE_COLOR] for quick access. +GLOBAL_LIST_INIT(emissive_color, EMISSIVE_COLOR) +/// The color matrix applied to all emissive blockers. Should be solely dependent on alpha and not have RGB overlap with [EMISSIVE_COLOR]. +#define EM_BLOCK_COLOR list(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) +/// A globaly cached version of [EM_BLOCK_COLOR] for quick access. +GLOBAL_LIST_INIT(em_block_color, EM_BLOCK_COLOR) +/// The color matrix used to mask out emissive blockers on the emissive plane. Alpha should default to zero, be solely dependent on the RGB value of [EMISSIVE_COLOR], and be independant of the RGB value of [EM_BLOCK_COLOR]. +#define EM_MASK_MATRIX list(0,0,0,1/3, 0,0,0,1/3, 0,0,0,1/3, 0,0,0,0, 1,1,1,0) +/// A globaly cached version of [EM_MASK_MATRIX] for quick access. +GLOBAL_LIST_INIT(em_mask_matrix, EM_MASK_MATRIX) + +/// Returns the red part of a #RRGGBB hex sequence as number +#define GETREDPART(hexa) hex2num(copytext(hexa, 2, 4)) + +/// Returns the green part of a #RRGGBB hex sequence as number +#define GETGREENPART(hexa) hex2num(copytext(hexa, 4, 6)) + +/// Returns the blue part of a #RRGGBB hex sequence as number +#define GETBLUEPART(hexa) hex2num(copytext(hexa, 6, 8)) + +/// Parse the hexadecimal color into lumcounts of each perspective. +#define PARSE_LIGHT_COLOR(source) \ +do { \ + if (source.light_color != COLOR_WHITE) { \ + var/__light_color = source.light_color; \ + source.lum_r = GETREDPART(__light_color) / 255; \ + source.lum_g = GETGREENPART(__light_color) / 255; \ + source.lum_b = GETBLUEPART(__light_color) / 255; \ + } else { \ + source.lum_r = 1; \ + source.lum_g = 1; \ + source.lum_b = 1; \ + }; \ +} while (FALSE) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 824155f93eb..b853f4e9b55 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -20,6 +20,7 @@ #define SEE_INVISIBLE_MINIMUM 5 #define INVISIBILITY_MAXIMUM 100 +#define INVISIBILITY_ABSTRACT 101 //only used for abstract objects, things that are not really there. // Pseudo-Invis, like Ninja, Ling, Etc. #define EFFECTIVE_INVIS 50 // Below this, can't be examined, may as well be invisible to the game diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 7513ab3c006..b70001cbd61 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -377,37 +377,40 @@ //Vision flags, for dealing with plane visibility #define VIS_FULLBRIGHT 1 #define VIS_LIGHTING 2 -#define VIS_GHOSTS 3 -#define VIS_AI_EYE 4 +#define VIS_O_LIGHT 3 +#define VIS_EMISSIVE 4 -#define VIS_CH_STATUS 5 -#define VIS_CH_HEALTH 6 -#define VIS_CH_LIFE 7 -#define VIS_CH_ID 8 -#define VIS_CH_WANTED 9 -#define VIS_CH_IMPLOYAL 10 -#define VIS_CH_IMPTRACK 11 -#define VIS_CH_IMPCHEM 12 -#define VIS_CH_SPECIAL 13 -#define VIS_CH_STATUS_OOC 14 +#define VIS_GHOSTS 5 +#define VIS_AI_EYE 6 -#define VIS_ADMIN1 15 -#define VIS_ADMIN2 16 -#define VIS_ADMIN3 17 +#define VIS_CH_STATUS 7 +#define VIS_CH_HEALTH 8 +#define VIS_CH_LIFE 9 +#define VIS_CH_ID 10 +#define VIS_CH_WANTED 11 +#define VIS_CH_IMPLOYAL 12 +#define VIS_CH_IMPTRACK 13 +#define VIS_CH_IMPCHEM 14 +#define VIS_CH_SPECIAL 15 +#define VIS_CH_STATUS_OOC 16 -#define VIS_MESONS 18 +#define VIS_ADMIN1 17 +#define VIS_ADMIN2 18 +#define VIS_ADMIN3 19 -#define VIS_TURFS 19 -#define VIS_OBJS 20 -#define VIS_MOBS 21 +#define VIS_MESONS 20 -#define VIS_BUILDMODE 22 +#define VIS_TURFS 21 +#define VIS_OBJS 22 +#define VIS_MOBS 23 -#define VIS_CLOAKED 23 +#define VIS_BUILDMODE 24 -#define VIS_STATUS 24 +#define VIS_CLOAKED 25 -#define VIS_COUNT 24 //Must be highest number from above. +#define VIS_STATUS 26 + +#define VIS_COUNT 26 //Must be highest number from above. //Some mob icon layering defines #define BODY_LAYER -100 diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 0847e447dbb..687b6870261 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -56,13 +56,13 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_SQLITE 40 #define INIT_ORDER_MEDIA_TRACKS 38 // Gotta get that lobby music up, yo #define INIT_ORDER_CHEMISTRY 35 +#define INIT_ORDER_VIS 32 #define INIT_ORDER_SKYBOX 30 #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_SOUNDS 23 #define INIT_ORDER_INSTRUMENTS 22 #define INIT_ORDER_DECALS 20 #define INIT_ORDER_PLANTS 19 // Must initialize before atoms. -#define INIT_ORDER_PLANETS 18 #define INIT_ORDER_JOB 17 #define INIT_ORDER_ALARM 16 // Must initialize before atoms. #define INIT_ORDER_TRANSCORE 15 // VOREStation Edit @@ -73,6 +73,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_DEFAULT 0 #define INIT_ORDER_LIGHTING 0 #define INIT_ORDER_AIR -1 +#define INIT_ORDER_PLANETS -2 #define INIT_ORDER_ASSETS -3 #define INIT_ORDER_HOLOMAPS -5 #define INIT_ORDER_NIGHTSHIFT -6 @@ -94,6 +95,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_SUPPLY 5 #define FIRE_PRIORITY_NIGHTSHIFT 5 #define FIRE_PRIORITY_PLANTS 5 +#define FIRE_PRIORITY_VIS 5 #define FIRE_PRIORITY_ORBIT 7 #define FIRE_PRIORITY_VOTE 8 #define FIRE_PRIORITY_INSTRUMENTS 9 diff --git a/code/__defines/turfs.dm b/code/__defines/turfs.dm index 64593f6e114..770d58573f8 100644 --- a/code/__defines/turfs.dm +++ b/code/__defines/turfs.dm @@ -17,4 +17,6 @@ #define SMOOTH_GREYLIST 4 // Use a whitelist and a blacklist at the same time. atom smoothing only #define isCardinal(x) (x == NORTH || x == SOUTH || x == EAST || x == WEST) -#define isDiagonal(x) (x == NORTHEAST || x == SOUTHEAST || x == NORTHWEST || x == SOUTHWEST) \ No newline at end of file +#define isDiagonal(x) (x == NORTHEAST || x == SOUTHEAST || x == NORTHWEST || x == SOUTHWEST) + +#define IS_OPAQUE_TURF(turf) (turf.directional_opacity == ALL_CARDINALS) diff --git a/code/_helpers/lighting.dm b/code/_helpers/lighting.dm new file mode 100644 index 00000000000..7cfd434e699 --- /dev/null +++ b/code/_helpers/lighting.dm @@ -0,0 +1,10 @@ +/// Produces a mutable appearance glued to the [EMISSIVE_PLANE] dyed to be the [EMISSIVE_COLOR]. +/proc/emissive_appearance(icon, icon_state = "", layer = FLOAT_LAYER, alpha = 255, appearance_flags = NONE) + var/mutable_appearance/appearance = mutable_appearance(icon, icon_state, layer, PLANE_EMISSIVE, alpha, appearance_flags) + appearance.color = GLOB.emissive_color + return appearance + +/proc/em_block_image_generic(var/image/I) + var/mutable_appearance/em_overlay = mutable_appearance(I.icon, I.icon_state, plane = PLANE_EMISSIVE, alpha = I.alpha, appearance_flags = KEEP_APART) + em_overlay.color = GLOB.em_block_color + return em_overlay diff --git a/code/_helpers/sorts/comparators.dm b/code/_helpers/sorts/comparators.dm index de64ad26f7a..b1980d6da14 100644 --- a/code/_helpers/sorts/comparators.dm +++ b/code/_helpers/sorts/comparators.dm @@ -88,3 +88,6 @@ /proc/cmp_media_track_asc(datum/track/A, datum/track/B) var/genre_sort = sorttext(B.genre || "Uncategorized", A.genre || "Uncategorized") return genre_sort || sorttext(B.title, A.title) + +/proc/cmp_filter_data_priority(list/A, list/B) + return A["priority"] - B["priority"] diff --git a/code/_helpers/visual_filters.dm b/code/_helpers/visual_filters.dm index 6cafa5a04d2..96f68710000 100644 --- a/code/_helpers/visual_filters.dm +++ b/code/_helpers/visual_filters.dm @@ -1,20 +1,306 @@ -// These involve BYOND's built in filters that do visual effects, and not stuff that distinguishes between things. +#define ICON_NOT_SET "Not Set" +//This is stored as a nested list instead of datums or whatever because it json encodes nicely for usage in tgui +GLOBAL_LIST_INIT(master_filter_info, list( + "alpha" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "icon" = ICON_NOT_SET, + "render_source" = "", + "flags" = 0 + ), + "flags" = list( + "MASK_INVERSE" = MASK_INVERSE, + "MASK_SWAP" = MASK_SWAP + ) + ), + "angular_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1 + ) + ), + /* Not supported because making a proper matrix editor on the frontend would be a huge dick pain. + Uncomment if you ever implement it + "color" = list( + "defaults" = list( + "color" = matrix(), + "space" = FILTER_COLOR_RGB + ) + ), + */ + "displace" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = null, + "icon" = ICON_NOT_SET, + "render_source" = "" + ) + ), + "drop_shadow" = list( + "defaults" = list( + "x" = 1, + "y" = -1, + "size" = 1, + "offset" = 0, + "color" = COLOR_HALF_TRANSPARENT_BLACK + ) + ), + "blur" = list( + "defaults" = list( + "size" = 1 + ) + ), + "layer" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "icon" = ICON_NOT_SET, + "render_source" = "", + "flags" = FILTER_OVERLAY, + "color" = "", + "transform" = null, + "blend_mode" = BLEND_DEFAULT + ) + ), + "motion_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0 + ) + ), + "outline" = list( + "defaults" = list( + "size" = 0, + "color" = COLOR_BLACK, + "flags" = NONE + ), + "flags" = list( + "OUTLINE_SHARP" = OUTLINE_SHARP, + "OUTLINE_SQUARE" = OUTLINE_SQUARE + ) + ), + "radial_blur" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 0.01 + ) + ), + "rays" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 16, + "color" = COLOR_WHITE, + "offset" = 0, + "density" = 10, + "threshold" = 0.5, + "factor" = 0, + "flags" = FILTER_OVERLAY | FILTER_UNDERLAY + ), + "flags" = list( + "FILTER_OVERLAY" = FILTER_OVERLAY, + "FILTER_UNDERLAY" = FILTER_UNDERLAY + ) + ), + "ripple" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1, + "repeat" = 2, + "radius" = 0, + "falloff" = 1, + "flags" = NONE + ), + "flags" = list( + "WAVE_BOUNDED" = WAVE_BOUNDED + ) + ), + "wave" = list( + "defaults" = list( + "x" = 0, + "y" = 0, + "size" = 1, + "offset" = 0, + "flags" = NONE + ), + "flags" = list( + "WAVE_SIDEWAYS" = WAVE_SIDEWAYS, + "WAVE_BOUNDED" = WAVE_BOUNDED + ) + ) +)) -// All of this ported from TG. -/atom/movable - var/list/filter_data // For handling persistent filters +#undef ICON_NOT_SET -/proc/cmp_filter_data_priority(list/A, list/B) - return A["priority"] - B["priority"] +//Helpers to generate lists for filter helpers +//This is the only practical way of writing these that actually produces sane lists +/proc/alpha_mask_filter(x, y, icon/icon, render_source, flags) + . = list("type" = "alpha") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(icon)) + .["icon"] = icon + if(!isnull(render_source)) + .["render_source"] = render_source + if(!isnull(flags)) + .["flags"] = flags -/atom/movable/proc/add_filter(filter_name, priority, list/params) +/proc/angular_blur_filter(x, y, size) + . = list("type" = "angular_blur") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + +/proc/color_matrix_filter(matrix/in_matrix, space) + . = list("type" = "color") + .["color"] = in_matrix + if(!isnull(space)) + .["space"] = space + +/proc/displacement_map_filter(icon, render_source, x, y, size = 32) + . = list("type" = "displace") + if(!isnull(icon)) + .["icon"] = icon + if(!isnull(render_source)) + .["render_source"] = render_source + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + +/proc/drop_shadow_filter(x, y, size, offset, color) + . = list("type" = "drop_shadow") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(size)) + .["size"] = size + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(color)) + .["color"] = color + +/proc/gauss_blur_filter(size) + . = list("type" = "blur") + if(!isnull(size)) + .["size"] = size + +/proc/layering_filter(icon, render_source, x, y, flags, color, transform, blend_mode) + . = list("type" = "layer") + if(!isnull(icon)) + .["icon"] = icon + if(!isnull(render_source)) + .["render_source"] = render_source + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(color)) + .["color"] = color + if(!isnull(flags)) + .["flags"] = flags + if(!isnull(transform)) + .["transform"] = transform + if(!isnull(blend_mode)) + .["blend_mode"] = blend_mode + +/proc/motion_blur_filter(x, y) + . = list("type" = "motion_blur") + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/outline_filter(size, color, flags) + . = list("type" = "outline") + if(!isnull(size)) + .["size"] = size + if(!isnull(color)) + .["color"] = color + if(!isnull(flags)) + .["flags"] = flags + +/proc/radial_blur_filter(size, x, y) + . = list("type" = "radial_blur") + if(!isnull(size)) + .["size"] = size + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/rays_filter(size, color, offset, density, threshold, factor, x, y, flags) + . = list("type" = "rays") + if(!isnull(size)) + .["size"] = size + if(!isnull(color)) + .["color"] = color + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(density)) + .["density"] = density + if(!isnull(threshold)) + .["threshold"] = threshold + if(!isnull(factor)) + .["factor"] = factor + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(flags)) + .["flags"] = flags + +/proc/ripple_filter(radius, size, falloff, repeat, x, y, flags) + . = list("type" = "ripple") + if(!isnull(radius)) + .["radius"] = radius + if(!isnull(size)) + .["size"] = size + if(!isnull(falloff)) + .["falloff"] = falloff + if(!isnull(repeat)) + .["repeat"] = repeat + if(!isnull(flags)) + .["flags"] = flags + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + +/proc/wave_filter(x, y, size, offset, flags) + . = list("type" = "wave") + if(!isnull(size)) + .["size"] = size + if(!isnull(x)) + .["x"] = x + if(!isnull(y)) + .["y"] = y + if(!isnull(offset)) + .["offset"] = offset + if(!isnull(flags)) + .["flags"] = flags + +/atom/proc/add_filter(name,priority,list/params) LAZYINITLIST(filter_data) var/list/p = params.Copy() p["priority"] = priority - filter_data[filter_name] = p + filter_data[name] = p update_filters() -/atom/movable/proc/update_filters() +/atom/proc/update_filters() filters = null filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE) for(var/f in filter_data) @@ -22,15 +308,77 @@ var/list/arguments = data.Copy() arguments -= "priority" filters += filter(arglist(arguments)) + UNSETEMPTY(filter_data) -/atom/movable/proc/get_filter(filter_name) - if(filter_data && filter_data[filter_name]) - return filters[filter_data.Find(filter_name)] +/atom/proc/transition_filter(name, time, list/new_params, easing, loop) + var/filter = get_filter(name) + if(!filter) + return -// Polaris Extensions -/atom/movable/proc/remove_filter(filter_name) - var/thing = get_filter(filter_name) - if(thing) - LAZYREMOVE(filter_data, filter_name) - filters -= thing - update_filters() \ No newline at end of file + var/list/old_filter_data = filter_data[name] + + var/list/params = old_filter_data.Copy() + for(var/thing in new_params) + params[thing] = new_params[thing] + + animate(filter, new_params, time = time, easing = easing, loop = loop) + for(var/param in params) + filter_data[name][param] = params[param] + +/atom/proc/change_filter_priority(name, new_priority) + if(!filter_data || !filter_data[name]) + return + + filter_data[name]["priority"] = new_priority + update_filters() + +/obj/item/update_filters() + . = ..() + /* Will port this from TG + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + */ + +/atom/proc/get_filter(name) + if(filter_data && filter_data[name]) + return filters[filter_data.Find(name)] + +/atom/proc/remove_filter(name_or_names) + if(!filter_data) + return + + var/list/names = islist(name_or_names) ? name_or_names : list(name_or_names) + + for(var/name in names) + if(filter_data[name]) + filter_data -= name + update_filters() + +/atom/proc/clear_filters() + filter_data = null + filters = null + +/proc/apply_wibbly_filters(atom/in_atom, length) + for(var/i in 1 to 7) + //This is a very baffling and strange way of doing this but I am just preserving old functionality + var/X + var/Y + var/rsq + do + X = 60*rand() - 30 + Y = 60*rand() - 30 + rsq = X*X + Y*Y + while(rsq<100 || rsq>900) // Yeah let's just loop infinitely due to bad luck what's the worst that could happen? + var/random_roll = rand() + in_atom.add_filter("wibbly-[i]", 5, wave_filter(x = X, y = Y, size = rand() * 2.5 + 0.5, offset = random_roll)) + var/filter = in_atom.get_filter("wibbly-[i]") + animate(filter, offset = random_roll, time = 0, loop = -1, flags = ANIMATION_PARALLEL) + animate(offset = random_roll - 1, time = rand() * 20 + 10) + +/proc/remove_wibbly_filters(atom/in_atom) + var/filter + for(var/i in 1 to 7) + filter = in_atom.get_filter("wibbly-[i]") + animate(filter) + in_atom.remove_filter("wibbly-[i]") diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index ddd7ac5dcc6..38646ccbc33 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -5,25 +5,22 @@ condition ? overlay_fullscreen(screen_name, screen_type, arg) : clear_fullscreen(screen_name) /mob/proc/overlay_fullscreen(category, type, severity) - var/obj/screen/fullscreen/screen = screens[category] + var/obj/screen/fullscreen/screen = screens[category] + if (!screen || screen.type != type) + // needs to be recreated + clear_fullscreen(category, FALSE) + screens[category] = screen = new type() + else if ((!severity || severity == screen.severity) && (!client || screen.screen_loc != "CENTER-7,CENTER-7" || screen.view == client.view)) + // doesn't need to be updated + return screen - if(screen) - if(screen.type != type) - clear_fullscreen(category, FALSE) - screen = null - else if(!severity || severity == screen.severity) - return screen + screen.icon_state = "[initial(screen.icon_state)][severity]" + screen.severity = severity + if (client && screen.should_show_to(src)) + screen.update_for_view(client.view) + client.screen += screen - if(!screen) - screen = new type() - - screen.icon_state = "[initial(screen.icon_state)][severity]" - screen.severity = severity - - screens[category] = screen - if(client && stat != DEAD) - client.screen += screen - return screen + return screen /mob/proc/clear_fullscreen(category, animated = 10) var/obj/screen/fullscreen/screen = screens[category] @@ -64,13 +61,26 @@ screen_loc = "CENTER-7,CENTER-7" layer = FULLSCREEN_LAYER plane = PLANE_FULLSCREEN - mouse_opacity = 0 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + var/view = 7 var/severity = 0 + var/show_when_dead = FALSE /obj/screen/fullscreen/Destroy() severity = 0 return ..() +/obj/screen/fullscreen/proc/update_for_view(client_view) + if (screen_loc == "CENTER-7,CENTER-7" && view != client_view) + var/list/actualview = getviewsize(client_view) + view = client_view + transform = matrix(actualview[1]/15, 0, 0, 0, actualview[2]/15, 0) + +/obj/screen/fullscreen/proc/should_show_to(mob/mymob) + if(!show_when_dead && mymob.stat == DEAD) + return FALSE + return TRUE + /obj/screen/fullscreen/brute icon_state = "brutedamageoverlay" layer = DAMAGE_LAYER @@ -123,3 +133,21 @@ /obj/screen/fullscreen/fishbed icon_state = "fishbed" + +/obj/screen/fullscreen/lighting_backdrop + icon = 'icons/mob/screen_gen.dmi' + icon_state = "flash" + transform = matrix(200, 0, 0, 0, 200, 0) + plane = PLANE_LIGHTING + blend_mode = BLEND_OVERLAY + show_when_dead = TRUE + +//Provides darkness to the back of the lighting plane +/obj/screen/fullscreen/lighting_backdrop/lit + invisibility = INVISIBILITY_LIGHTING + layer = BACKGROUND_LAYER+21 + color = "#000" + +//Provides whiteness in case you don't see lights so everything is still visible +/obj/screen/fullscreen/lighting_backdrop/unlit + layer = BACKGROUND_LAYER+20 diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 257760845e6..06b51def249 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -630,6 +630,13 @@ return ..() // Background 'floor' +/obj/screen/setup_preview/pm_helper + icon = null + icon_state = null + appearance_flags = PLANE_MASTER + plane = PLANE_EMISSIVE + alpha = 0 + /obj/screen/setup_preview/bg mouse_over_pointer = MOUSE_HAND_POINTER diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index 5c7b15d8985..f851e3edf2d 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -1,171 +1,91 @@ -/* -** Lighting Subsystem - Process the lighting! Do it! -*/ - -#define SSLIGHTING_STAGE_LIGHTS 1 -#define SSLIGHTING_STAGE_CORNERS 2 -#define SSLIGHTING_STAGE_OVERLAYS 3 -#define SSLIGHTING_STAGE_DONE 4 -// This subsystem's fire() method also gets called once during Master.Initialize(). -// During this fire we need to use CHECK_TICK to sleep and continue, but in all other fires we need to use MC_CHECK_TICK to pause and return. -// This leads us to a rather annoying little tidbit of code that I have stuffed into this macro so I don't have to see it. -#define DUAL_TICK_CHECK if (init_tick_checks) { CHECK_TICK; } else if (MC_TICK_CHECK) { return; } - -// Globals -/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. - SUBSYSTEM_DEF(lighting) name = "Lighting" - wait = 2 // Ticks, not deciseconds + wait = 2 init_order = INIT_ORDER_LIGHTING flags = SS_TICKER + var/static/list/sources_queue = list() // List of lighting sources queued for update. + var/static/list/corners_queue = list() // List of lighting corners queued for update. + var/static/list/objects_queue = list() // List of lighting objects queued for update. - var/list/currentrun = list() - var/stage = null - - var/cost_lights = 0 - var/cost_corners = 0 - var/cost_overlays = 0 - -/datum/controller/subsystem/lighting/Initialize(timeofday) - if(!lighting_overlays_initialised) - // TODO - TG initializes starlight here. - create_all_lighting_overlays() - lighting_overlays_initialised = TRUE - - // Pre-process lighting once before the round starts. - internal_process_lights(FALSE, TRUE) - internal_process_corners(FALSE, TRUE) - internal_process_overlays(FALSE, TRUE) +/datum/controller/subsystem/lighting/stat_entry(msg) + msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]" return ..() -/datum/controller/subsystem/lighting/fire(resumed = FALSE) - var/timer - if(!resumed) - // Santity checks to make sure we don't somehow have items left over from last cycle - // Or somehow didn't finish all the steps from last cycle - if(LAZYLEN(currentrun) || stage) - log_and_message_admins("SSlighting: Was told to start a new run, but the previous run wasn't finished! currentrun.len=[currentrun.len], stage=[stage]") - resumed = TRUE - else - stage = SSLIGHTING_STAGE_LIGHTS // Start with Step 1 of course - if(stage == SSLIGHTING_STAGE_LIGHTS) - timer = TICK_USAGE - internal_process_lights(resumed) - cost_lights = MC_AVERAGE(cost_lights, TICK_DELTA_TO_MS(TICK_USAGE - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - stage = SSLIGHTING_STAGE_CORNERS +/datum/controller/subsystem/lighting/Initialize(timeofday) + if(!subsystem_initialized) + if (config.starlight) + for(var/area/A in world) + if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT) + A.luminosity = 0 - if(stage == SSLIGHTING_STAGE_CORNERS) - timer = TICK_USAGE - internal_process_corners(resumed) - cost_corners = MC_AVERAGE(cost_corners, TICK_DELTA_TO_MS(TICK_USAGE - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - stage = SSLIGHTING_STAGE_OVERLAYS + subsystem_initialized = TRUE + create_all_lighting_objects() - if(stage == SSLIGHTING_STAGE_OVERLAYS) - timer = TICK_USAGE - internal_process_overlays(resumed) - cost_overlays = MC_AVERAGE(cost_overlays, TICK_DELTA_TO_MS(TICK_USAGE - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - stage = SSLIGHTING_STAGE_DONE + fire(FALSE, TRUE) - // Okay, we're done! Woo! Got thru a whole air_master cycle! - if(LAZYLEN(currentrun) || stage != SSLIGHTING_STAGE_DONE) - log_and_message_admins("SSlighting: Was not able to complete a full lighting cycle despite reaching the end of fire(). This shouldn't happen.") - else - currentrun = null - stage = null + return ..() -/datum/controller/subsystem/lighting/proc/internal_process_lights(resumed = FALSE, init_tick_checks = FALSE) - if (!resumed) - // We swap out the lists so any additions to the global list during a pause don't make things wierd. - src.currentrun = global.lighting_update_lights - global.lighting_update_lights = list() +/datum/controller/subsystem/lighting/fire(resumed, init_tick_checks) + MC_SPLIT_TICK_INIT(3) + if(!init_tick_checks) + MC_SPLIT_TICK + var/list/queue = sources_queue + var/i = 0 + for (i in 1 to length(queue)) + var/datum/light_source/L = queue[i] - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/datum/light_source/L = currentrun[currentrun.len] - currentrun.len-- + L.update_corners() - if(!L) continue - if(L.check() || L.destroyed || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() + L.needs_update = LIGHTING_NO_UPDATE - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() + if(init_tick_checks) + CHECK_TICK + else if (MC_TICK_CHECK) + break + if (i) + queue.Cut(1, i+1) + i = 0 - L.vis_update = FALSE - L.force_update = FALSE - L.needs_update = FALSE + if(!init_tick_checks) + MC_SPLIT_TICK - DUAL_TICK_CHECK + queue = corners_queue + for (i in 1 to length(queue)) + var/datum/lighting_corner/C = queue[i] -/datum/controller/subsystem/lighting/proc/internal_process_corners(resumed = FALSE, init_tick_checks = FALSE) - if (!resumed) - // We swap out the lists so any additions to the global list during a pause don't make things wierd. - src.currentrun = global.lighting_update_corners - global.lighting_update_corners = list() + C.needs_update = FALSE //update_objects() can call qdel if the corner is storing no data + C.update_objects() + + if(init_tick_checks) + CHECK_TICK + else if (MC_TICK_CHECK) + break + if (i) + queue.Cut(1, i+1) + i = 0 - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/datum/lighting_corner/C = currentrun[currentrun.len] - currentrun.len-- - if(!C) continue - C.update_overlays() - C.needs_update = FALSE + if(!init_tick_checks) + MC_SPLIT_TICK - DUAL_TICK_CHECK + queue = objects_queue + for (i in 1 to length(queue)) + var/datum/lighting_object/O = queue[i] -/datum/controller/subsystem/lighting/proc/internal_process_overlays(resumed = FALSE, init_tick_checks = FALSE) - if (!resumed) - // We swap out the lists so any additions to the global list during a pause don't make things wierd. - src.currentrun = global.lighting_update_overlays - global.lighting_update_overlays = list() + if (QDELETED(O)) + continue - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/atom/movable/lighting_overlay/O = currentrun[currentrun.len] - currentrun.len-- - - if(!O) continue - O.update_overlay() + O.update() O.needs_update = FALSE + if(init_tick_checks) + CHECK_TICK + else if (MC_TICK_CHECK) + break + if (i) + queue.Cut(1, i+1) - DUAL_TICK_CHECK -/datum/controller/subsystem/lighting/stat_entry(msg_prefix) - var/list/msg = list(msg_prefix) - msg += "T:{" - msg += "S [total_lighting_sources] | " - msg += "C [total_lighting_corners] | " - msg += "O [total_lighting_overlays]" - msg += "}" - msg += "C:{" - msg += "S [round(cost_lights, 1)] | " - msg += "C [round(cost_corners, 1)] | " - msg += "O [round(cost_overlays, 1)]" - msg += "}" - ..(msg.Join()) - -#undef DUAL_TICK_CHECK -#undef SSLIGHTING_STAGE_LIGHTS -#undef SSLIGHTING_STAGE_CORNERS -#undef SSLIGHTING_STAGE_OVERLAYS -#undef SSLIGHTING_STAGE_STATS \ No newline at end of file +/datum/controller/subsystem/lighting/Recover() + subsystem_initialized = SSlighting.subsystem_initialized + ..() diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index 77c9d3ab94a..16662cc042e 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -224,6 +224,32 @@ var/global/image/appearance_bro = new() // Temporarily super-global because of B else if(cut_old) cut_overlays() +/** + * Returns a list of overlays that the target atom has + * + * @param priority If true, returns priority overlays as well + * @param special If true, returns special overlays like emissives and em_blockers + */ +/proc/get_overlays(atom/other, priority, special) + var/list/including = list() + if(!other) + return including + + for(var/image/I as anything in other.our_overlays) + if(!special && I.plane > 0) + continue + including += I + + if(!priority) + return including + + for(var/image/I as anything in other.priority_overlays) + if(!special && I.plane > 0) + continue + including += I + + return including + #undef NOT_QUEUED_ALREADY #undef QUEUE_FOR_COMPILE diff --git a/code/controllers/subsystems/planets.dm b/code/controllers/subsystems/planets.dm index d1c2de2410c..d468fa9ae57 100644 --- a/code/controllers/subsystems/planets.dm +++ b/code/controllers/subsystems/planets.dm @@ -14,6 +14,9 @@ SUBSYSTEM_DEF(planets) var/static/list/needs_sun_update = list() var/static/list/needs_temp_update = list() + var/static/list/queued_turfs = list() + var/static/accepting_turfs = FALSE + /datum/controller/subsystem/planets/Initialize(timeofday) admin_notice("Initializing planetary weather.", R_DEBUG) createPlanets() @@ -31,11 +34,23 @@ SUBSYSTEM_DEF(planets) admin_notice("Z[Z] is shared by more than one planet!", R_DEBUG) continue z_to_planet[Z] = NP + accepting_turfs = TRUE + while(queued_turfs.len) + addTurf(queued_turfs[queued_turfs.len]) + queued_turfs.len-- + CHECK_TICK + /* Seems to cause active edges, SOMEHOW. IT'S LIGHT AAAA. + for(var/datum/planet/P as anything in planets) + updateSunlight(P) + */ // DO NOT CALL THIS DIRECTLY UNLESS IT'S IN INITIALIZE, // USE turf/simulated/proc/make_indoors() and // tyrf/simulated/proc/make_outdoors() /datum/controller/subsystem/planets/proc/addTurf(var/turf/T) + if(!accepting_turfs) + queued_turfs |= T + return if(z_to_planet.len >= T.z && z_to_planet[T.z]) var/datum/planet/P = z_to_planet[T.z] if(!istype(P)) @@ -44,9 +59,8 @@ SUBSYSTEM_DEF(planets) P.planet_walls += T else if(istype(T, /turf/simulated) && T.outdoors) P.planet_floors += T - T.vis_contents |= P.weather_holder.visuals - T.vis_contents |= P.weather_holder.special_visuals - + P.weather_holder.apply_to_turf(T) + P.sun_holder.apply_to_turf(T) /datum/controller/subsystem/planets/proc/removeTurf(var/turf/T,var/is_edge) if(z_to_planet.len >= T.z) @@ -57,8 +71,8 @@ SUBSYSTEM_DEF(planets) P.planet_walls -= T else P.planet_floors -= T - T.vis_contents -= P.weather_holder.visuals - T.vis_contents -= P.weather_holder.special_visuals + P.weather_holder.remove_from_turf(T) + P.sun_holder.remove_from_turf(T) /datum/controller/subsystem/planets/fire(resumed = 0) @@ -102,39 +116,11 @@ SUBSYSTEM_DEF(planets) return /datum/controller/subsystem/planets/proc/updateSunlight(var/datum/planet/P) - // Remove old value from corners - var/list/sunlit_corners = P.sunlit_corners - var/old_lum_r = -P.sun["lum_r"] - var/old_lum_g = -P.sun["lum_g"] - var/old_lum_b = -P.sun["lum_b"] - if(old_lum_r || old_lum_g || old_lum_b) - for(var/C in sunlit_corners) - var/datum/lighting_corner/LC = C - LC.update_lumcount(old_lum_r, old_lum_g, old_lum_b) - CHECK_TICK - sunlit_corners.Cut() - - // Calculate new values to apply var/new_brightness = P.sun["brightness"] + P.sun_holder.update_brightness(new_brightness) + var/new_color = P.sun["color"] - var/lum_r = new_brightness * GetRedPart (new_color) / 255 - var/lum_g = new_brightness * GetGreenPart(new_color) / 255 - var/lum_b = new_brightness * GetBluePart (new_color) / 255 - var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs. - for(var/turf/simulated/T as anything in P.planet_floors) - if(!T.lighting_corners_initialised) - T.generate_missing_corners() - for(var/C in T.get_corners()) - var/datum/lighting_corner/LC = C - if(LC.update_gen != update_gen && LC.active) - sunlit_corners += LC - LC.update_gen = update_gen - LC.update_lumcount(lum_r, lum_g, lum_b) - CHECK_TICK - update_gen-- - P.sun["lum_r"] = lum_r - P.sun["lum_g"] = lum_g - P.sun["lum_b"] = lum_b + P.sun_holder.update_color(new_color) /datum/controller/subsystem/planets/proc/updateTemp(var/datum/planet/P) //Set new temperatures diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 58a66923c42..4a9c3b48a7c 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -4,6 +4,7 @@ // Clickable stat() button. /obj/effect/statclick name = "Initializing..." + blocks_emissive = FALSE var/target /obj/effect/statclick/New(loc, text, target) //Don't port this to Initialize it's too critical diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index c4ee090ce85..c5bd07cdcbd 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -188,7 +188,11 @@ var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types) for(var/sig_type in sig_types) if(!override && procs[target][sig_type]) - stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning") + var/trace_msg = "[sig_type] overridden. Use override = TRUE to suppress this warning." + if(isatom(target)) + var/atom/A = target + trace_msg += " [A.x],[A.y],[A.z]" + stack_trace(trace_msg) procs[target][sig_type] = proctype diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm new file mode 100644 index 00000000000..cfc0f1e921e --- /dev/null +++ b/code/datums/components/overlay_lighting.dm @@ -0,0 +1,511 @@ +///For switchable lights, is it on and currently emitting light? +#define LIGHTING_ON (1<<0) +///Is the parent attached to something else, its loc? Then we need to keep an eye of this. +#define LIGHTING_ATTACHED (1<<1) + +#define GET_PARENT (parent_attached_to || parent) + +#define GET_LIGHT_SOURCE (directional_atom || current_holder) + +#define SHORT_CAST 2 + +/** + * Movable atom overlay-based lighting component. + * + * * Component works by applying a visual object to the parent target. + * + * * The component tracks the parent's loc to determine the current_holder. + * * The current_holder is either the parent or its loc, whichever is on a turf. If none, then the current_holder is null and the light is not visible. + * + * * Lighting works at its base by applying a dark overlay and "cutting" said darkness with light, adding (possibly colored) transparency. + * * This component uses the visible_mask visual object to apply said light mask on the darkness. + * + * * The main limitation of this system is that it uses a limited number of pre-baked geometrical shapes, but for most uses it does the job. + * + * * Another limitation is for big lights: you only see the light if you see the object emiting it. + * * For small objects this is good (you can't see them behind a wall), but for big ones this quickly becomes prety clumsy. +*/ +/datum/component/overlay_lighting + ///How far the light reaches, float. + var/range = 1 + ///Ceiling of range, integer without decimal entries. + var/lumcount_range = 0 + ///How much this light affects the dynamic_lumcount of turfs. + var/lum_power = 0.5 + ///Transparency value. + var/set_alpha = 0 + ///For light sources that can be turned on and off. + var/overlay_lighting_flags = NONE + + ///Cache of the possible light overlays, according to size. + var/static/list/light_overlays = list( + "32" = 'icons/effects/light_overlays/light_32.dmi', + "64" = 'icons/effects/light_overlays/light_64.dmi', + "96" = 'icons/effects/light_overlays/light_96.dmi', + "128" = 'icons/effects/light_overlays/light_128.dmi', + "160" = 'icons/effects/light_overlays/light_160.dmi', + "192" = 'icons/effects/light_overlays/light_192.dmi', + "224" = 'icons/effects/light_overlays/light_224.dmi', + "256" = 'icons/effects/light_overlays/light_256.dmi', + "288" = 'icons/effects/light_overlays/light_288.dmi', + "320" = 'icons/effects/light_overlays/light_320.dmi', + "352" = 'icons/effects/light_overlays/light_352.dmi', + ) + + ///Overlay effect to cut into the darkness and provide light. + var/obj/effect/overlay/light_visible/visible_mask + ///Lazy list to track the turfs being affected by our light, to determine their visibility. + var/list/turf/affected_turfs + ///Movable atom currently holding the light. Parent might be a flashlight, for example, but that might be held by a mob or something else. + var/atom/movable/current_holder + ///Movable atom the parent is attached to. For example, a flashlight into a helmet or gun. We'll need to track the thing the parent is attached to as if it were the parent itself. + var/atom/movable/parent_attached_to + ///Whether we're a directional light + var/directional + ///Abstractional atom for directional light, we move this around to make the directional effect + var/obj/effect/abstract/directional_lighting/directional_atom + ///A cone overlay for directional light, it's alpha and color are dependant on the light + var/obj/effect/overlay/light_cone/cone + ///Current tracked direction for the directional cast behaviour + var/current_direction + ///Cast range for the directional cast (how far away the atom is moved) + var/cast_range = 2 + ///Cone offset X hint from atom, used when facing south, inverted when facing north + var/cone_hint_x + ///Cone offset Y hint from atom, when facing east/west, ignored for north/south (uses 16 in those cases) + var/cone_hint_y + + +/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on, is_directional) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + var/atom/movable/movable_parent = parent + if(movable_parent.light_system != MOVABLE_LIGHT && movable_parent.light_system != MOVABLE_LIGHT_DIRECTIONAL) + stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT] or [MOVABLE_LIGHT_DIRECTIONAL] instead.") + return COMPONENT_INCOMPATIBLE + + . = ..() + + visible_mask = new() + if(is_directional) + directional = TRUE + directional_atom = new() + cone = new() + cone_hint_x = movable_parent.light_cone_x_offset + cone_hint_y = movable_parent.light_cone_y_offset + cone.transform = cone.transform.Translate(-32, -32) + set_direction(movable_parent.dir) + if(!isnull(_range)) + movable_parent.set_light_range(_range) + set_range(parent, movable_parent.light_range) + if(!isnull(_power)) + movable_parent.set_light_power(_power) + set_power(parent, movable_parent.light_power) + if(!isnull(_color)) + movable_parent.set_light_color(_color) + set_color(parent, movable_parent.light_color) + if(!isnull(starts_on)) + movable_parent.set_light_on(starts_on) + + +/datum/component/overlay_lighting/RegisterWithParent() + . = ..() + if(directional) + RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/on_parent_dir_change) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .proc/set_range) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_POWER, .proc/set_power) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .proc/set_color) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_ON, .proc/on_toggle) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .proc/on_light_flags_change) + RegisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted) + RegisterSignal(parent, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater) + var/atom/movable/movable_parent = parent + if(movable_parent.light_flags & LIGHT_ATTACHED) + overlay_lighting_flags |= LIGHTING_ATTACHED + set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null) + check_holder() + if(movable_parent.light_on) + turn_on() + + +/datum/component/overlay_lighting/UnregisterFromParent() + overlay_lighting_flags &= ~LIGHTING_ATTACHED + set_parent_attached_to(null) + set_holder(null) + clean_old_turfs() + UnregisterSignal(parent, list( + COMSIG_MOVABLE_MOVED, + COMSIG_ATOM_UPDATE_LIGHT_RANGE, + COMSIG_ATOM_UPDATE_LIGHT_POWER, + COMSIG_ATOM_UPDATE_LIGHT_COLOR, + COMSIG_ATOM_UPDATE_LIGHT_ON, + COMSIG_ATOM_UPDATE_LIGHT_FLAGS, + COMSIG_ATOM_USED_IN_CRAFT, + COMSIG_LIGHT_EATER_QUEUE, + )) + if(directional) + UnregisterSignal(parent, COMSIG_ATOM_DIR_CHANGE) + if(overlay_lighting_flags & LIGHTING_ON) + turn_off() + return ..() + + +/datum/component/overlay_lighting/Destroy() + set_parent_attached_to(null) + set_holder(null) + clean_old_turfs() + QDEL_NULL(visible_mask) + if(directional) + QDEL_NULL(directional_atom) + QDEL_NULL(cone) + return ..() + + +///Clears the affected_turfs lazylist, removing from its contents the effects of being near the light. +/datum/component/overlay_lighting/proc/clean_old_turfs() + for(var/t in affected_turfs) + var/turf/lit_turf = t + lit_turf.dynamic_lumcount -= lum_power + affected_turfs = null + + +///Populates the affected_turfs lazylist, adding to its contents the effects of being near the light. +/datum/component/overlay_lighting/proc/get_new_turfs() + if(!current_holder) + return + var/atom/movable/light_source = GET_LIGHT_SOURCE + for(var/turf/lit_turf in view(lumcount_range, get_turf(light_source))) + lit_turf.dynamic_lumcount += lum_power + LAZYADD(affected_turfs, lit_turf) + + +///Clears the old affected turfs and populates the new ones. +/datum/component/overlay_lighting/proc/make_luminosity_update() + clean_old_turfs() + if(!isturf(current_holder?.loc)) + return + if(directional) + cast_directional_light() + get_new_turfs() + + +///Adds the luminosity and source for the afected movable atoms to keep track of their visibility. +/datum/component/overlay_lighting/proc/add_dynamic_lumi() + var/atom/movable/light_source = GET_LIGHT_SOURCE + LAZYSET(light_source.affected_dynamic_lights, src, lumcount_range + 1) + light_source.vis_contents += visible_mask + light_source.update_dynamic_luminosity() + if(directional) + current_holder.vis_contents += cone + +///Removes the luminosity and source for the afected movable atoms to keep track of their visibility. +/datum/component/overlay_lighting/proc/remove_dynamic_lumi() + var/atom/movable/light_source = GET_LIGHT_SOURCE + LAZYREMOVE(light_source.affected_dynamic_lights, src) + light_source.vis_contents -= visible_mask + light_source.update_dynamic_luminosity() + if(directional) + current_holder.vis_contents -= cone + directional_atom.moveToNullspace() + +///Called to change the value of parent_attached_to. +/datum/component/overlay_lighting/proc/set_parent_attached_to(atom/movable/new_parent_attached_to) + if(new_parent_attached_to == parent_attached_to) + return + + . = parent_attached_to + parent_attached_to = new_parent_attached_to + if(.) + var/atom/movable/old_parent_attached_to = . + UnregisterSignal(old_parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE)) + if(old_parent_attached_to == current_holder) + RegisterSignal(old_parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel) + RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved) + RegisterSignal(old_parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater) + if(parent_attached_to) + if(parent_attached_to == current_holder) + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE)) + RegisterSignal(parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_parent_attached_to_qdel) + RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_parent_attached_to_moved) + RegisterSignal(parent_attached_to, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater) + check_holder() + + +///Called to change the value of current_holder. +/datum/component/overlay_lighting/proc/set_holder(atom/movable/new_holder) + if(new_holder == current_holder) + return + if(current_holder) + if(current_holder != parent && current_holder != parent_attached_to) + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_LIGHT_EATER_QUEUE)) + if(directional) + UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE) + if(overlay_lighting_flags & LIGHTING_ON) + remove_dynamic_lumi() + current_holder = new_holder + if(new_holder == null) + clean_old_turfs() + return + if(new_holder != parent && new_holder != parent_attached_to) + RegisterSignal(new_holder, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel) + RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved) + RegisterSignal(new_holder, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater) + if(directional) + RegisterSignal(new_holder, COMSIG_ATOM_DIR_CHANGE, .proc/on_holder_dir_change) + if(overlay_lighting_flags & LIGHTING_ON) + make_luminosity_update() + add_dynamic_lumi() + + +///Used to determine the new valid current_holder from the parent's loc. +/datum/component/overlay_lighting/proc/check_holder() + var/atom/movable/movable_parent = GET_PARENT + if(isturf(movable_parent.loc)) + set_holder(movable_parent) + return + var/atom/inside = movable_parent.loc //Parent's loc + if(isnull(inside)) + set_holder(null) + return + if(isturf(inside.loc)) + set_holder(inside) + return + set_holder(null) + + +///Called when the current_holder is qdeleted, to remove the light effect. +/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force) + SIGNAL_HANDLER + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + if(directional) + UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE) + set_holder(null) + + +///Called when current_holder changes loc. +/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced) + SIGNAL_HANDLER + if(!(overlay_lighting_flags & LIGHTING_ON)) + return + make_luminosity_update() + + +///Called when parent changes loc. +/datum/component/overlay_lighting/proc/on_parent_moved(atom/movable/source, OldLoc, Dir, Forced) + SIGNAL_HANDLER + var/atom/movable/movable_parent = parent + if(overlay_lighting_flags & LIGHTING_ATTACHED) + set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null) + check_holder() + if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder) + return + make_luminosity_update() + + +///Called when the current_holder is qdeleted, to remove the light effect. +/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force) + SIGNAL_HANDLER + UnregisterSignal(parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + if(directional) + UnregisterSignal(parent_attached_to, COMSIG_ATOM_DIR_CHANGE) + if(parent_attached_to == current_holder) + set_holder(null) + set_parent_attached_to(null) + + +///Called when parent_attached_to changes loc. +/datum/component/overlay_lighting/proc/on_parent_attached_to_moved(atom/movable/source, OldLoc, Dir, Forced) + SIGNAL_HANDLER + check_holder() + if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder) + return + make_luminosity_update() + + +///Changes the range which the light reaches. 0 means no light, 6 is the maximum value. +/datum/component/overlay_lighting/proc/set_range(atom/source, old_range) + SIGNAL_HANDLER + var/new_range = source.light_range + if(range == new_range) + return + if(range == 0) + turn_off() + range = clamp(CEILING(new_range, 0.5), 1, 6) + var/pixel_bounds = ((range - 1) * 64) + 32 + lumcount_range = CEILING(range, 1) + visible_mask.icon = light_overlays["[pixel_bounds]"] + if(pixel_bounds == 32) + visible_mask.transform = null + return + var/offset = (pixel_bounds - 32) * 0.5 + var/matrix/transform = new + transform.Translate(-offset, -offset) + visible_mask.transform = transform + if(directional) + cast_range = clamp(round(new_range * 0.5), 1, 3) + if(overlay_lighting_flags & LIGHTING_ON) + make_luminosity_update() + + +///Changes the intensity/brightness of the light by altering the visual object's alpha. +/datum/component/overlay_lighting/proc/set_power(atom/source, old_power) + SIGNAL_HANDLER + var/new_power = source.light_power + set_lum_power(new_power >= 0 ? 0.5 : -0.5) + set_alpha = min(230, (abs(new_power) * 120) + 30) + visible_mask.alpha = set_alpha + if(directional) + cone.alpha = min(200, (abs(new_power) * 90)+20) + + +///Changes the light's color, pretty straightforward. +/datum/component/overlay_lighting/proc/set_color(atom/source, old_color) + SIGNAL_HANDLER + var/new_color = source.light_color + visible_mask.color = new_color + if(directional) + cone.color = new_color + + +///Toggles the light on and off. +/datum/component/overlay_lighting/proc/on_toggle(atom/source, old_value) + SIGNAL_HANDLER + var/new_value = source.light_on + if(new_value) //Truthy value input, turn on. + turn_on() + return + turn_off() //Falsey value, turn off. + + +///Triggered right after the parent light flags change. +/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, old_flags) + SIGNAL_HANDLER + var/new_flags = source.light_flags + var/atom/movable/movable_parent = parent + if(!((new_flags ^ old_flags) & LIGHT_ATTACHED)) + return + + if(new_flags & LIGHT_ATTACHED) // Gained the [LIGHT_ATTACHED] property + overlay_lighting_flags |= LIGHTING_ATTACHED + if(ismovable(movable_parent.loc)) + set_parent_attached_to(movable_parent.loc) + else // Lost the [LIGHT_ATTACHED] property + overlay_lighting_flags &= ~LIGHTING_ATTACHED + set_parent_attached_to(null) + + +///Toggles the light on. +/datum/component/overlay_lighting/proc/turn_on() + if(overlay_lighting_flags & LIGHTING_ON) + return + if(current_holder) + if(directional) + cast_directional_light() + add_dynamic_lumi() + overlay_lighting_flags |= LIGHTING_ON + get_new_turfs() + + +///Toggles the light off. +/datum/component/overlay_lighting/proc/turn_off() + if(!(overlay_lighting_flags & LIGHTING_ON)) + return + if(current_holder) + remove_dynamic_lumi() + overlay_lighting_flags &= ~LIGHTING_ON + clean_old_turfs() + + +///Here we append the behavior associated to changing lum_power. +/datum/component/overlay_lighting/proc/set_lum_power(new_lum_power) + if(lum_power == new_lum_power) + return + . = lum_power + lum_power = new_lum_power + var/difference = . - lum_power + for(var/t in affected_turfs) + var/turf/lit_turf = t + lit_turf.dynamic_lumcount -= difference + +///Here we append the behavior associated to changing lum_power. +/datum/component/overlay_lighting/proc/cast_directional_light() + var/final_distance = cast_range + //Lower the distance by 1 if we're not looking at a cardinal direction, and we're not a short cast + if(final_distance > SHORT_CAST && !(ALL_CARDINALS & current_direction)) + final_distance -= 1 + var/turf/scanning = get_turf(current_holder) + for(var/i in 1 to final_distance) + var/turf/next_turf = get_step(scanning, current_direction) + if(isnull(next_turf) || IS_OPAQUE_TURF(next_turf)) + break + scanning = next_turf + directional_atom.forceMove(scanning) + +///Called when current_holder changes loc. +/datum/component/overlay_lighting/proc/on_holder_dir_change(atom/movable/source, olddir, newdir) + SIGNAL_HANDLER + set_direction(newdir) + +///Called when parent changes loc. +/datum/component/overlay_lighting/proc/on_parent_dir_change(atom/movable/source, olddir, newdir) + SIGNAL_HANDLER + set_direction(newdir) + +///Sets a new direction for the directional cast, then updates luminosity +/datum/component/overlay_lighting/proc/set_direction(newdir) + if(!newdir) + return + if(current_direction == newdir) + return + current_direction = newdir + cone.set_dir(newdir) + + if(newdir & NORTH) + cone.pixel_y = 16 + else if(newdir & SOUTH) + cone.pixel_y = -16 + else + if(!isnull(cone_hint_y)) + cone.pixel_y = cone_hint_y + else + cone.pixel_y = 0 + + if(newdir & EAST) + cone.pixel_x = 16 + else if(newdir & WEST) + cone.pixel_x = -16 + else + if(!isnull(cone_hint_x)) + if(newdir & NORTH) + cone.pixel_x = -1*cone_hint_x + else + cone.pixel_x = cone_hint_x + else + cone.pixel_x = 0 + + if(overlay_lighting_flags & LIGHTING_ON) + make_luminosity_update() + +/datum/component/overlay_lighting/proc/on_parent_crafted(datum/source, atom/movable/new_craft) + SIGNAL_HANDLER + + if(!istype(new_craft)) + return + + UnregisterSignal(parent, COMSIG_ATOM_USED_IN_CRAFT) + RegisterSignal(new_craft, COMSIG_ATOM_USED_IN_CRAFT, .proc/on_parent_crafted) + set_parent_attached_to(new_craft) + +/// Handles putting the source for overlay lights into the light eater queue since we aren't tracked by [/atom/var/light_sources] +/datum/component/overlay_lighting/proc/on_light_eater(datum/source, list/light_queue, datum/light_eater) + SIGNAL_HANDLER + light_queue[parent] = TRUE + return NONE + +#undef LIGHTING_ON +#undef LIGHTING_ATTACHED +#undef GET_PARENT +#undef GET_LIGHT_SOURCE +#undef SHORT_CAST diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm index 46a295f90be..30bd98a3268 100644 --- a/code/datums/elements/_element.dm +++ b/code/datums/elements/_element.dm @@ -1,9 +1,9 @@ /** - * A holder for simple behaviour that can be attached to many different types - * - * Only one element of each type is instanced during game init. - * Otherwise acts basically like a lightweight component. - */ + * A holder for simple behaviour that can be attached to many different types + * + * Only one element of each type is instanced during game init. + * Otherwise acts basically like a lightweight component. + */ /datum/element /// Option flags for element behaviour var/element_flags = NONE @@ -18,17 +18,23 @@ /// Activates the functionality defined by the element on the given target datum /datum/element/proc/Attach(datum/target) - SHOULD_CALL_PARENT(1) + SHOULD_CALL_PARENT(TRUE) if(type == /datum/element) return ELEMENT_INCOMPATIBLE SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src) if(element_flags & ELEMENT_DETACH) - RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE) + RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/OnTargetDelete, override = TRUE) + +/datum/element/proc/OnTargetDelete(datum/source, force) + SIGNAL_HANDLER + Detach(source) /// Deactivates the functionality defines by the element on the given datum -/datum/element/proc/Detach(datum/source, force) +/datum/element/proc/Detach(datum/source, ...) + SIGNAL_HANDLER + SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src) - SHOULD_CALL_PARENT(1) + SHOULD_CALL_PARENT(TRUE) UnregisterSignal(source, COMSIG_PARENT_QDELETING) /datum/element/Destroy(force) @@ -41,15 +47,21 @@ /// Finds the singleton for the element type given and attaches it to src /datum/proc/_AddElement(list/arguments) + if(QDELING(src)) + CRASH("We just tried to add an element to a qdeleted datum, something is fucked") var/datum/element/ele = SSdcs.GetElement(arguments) arguments[1] = src if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE) CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]") /** - * Finds the singleton for the element type given and detaches it from src - * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE] - */ + * Finds the singleton for the element type given and detaches it from src + * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE] + */ /datum/proc/_RemoveElement(list/arguments) var/datum/element/ele = SSdcs.GetElement(arguments) - ele.Detach(src) + if(ele.element_flags & ELEMENT_COMPLEX_DETACH) + arguments[1] = src + ele.Detach(arglist(arguments)) + else + ele.Detach(src) diff --git a/code/datums/elements/light_blocking.dm b/code/datums/elements/light_blocking.dm new file mode 100644 index 00000000000..86aac9f0758 --- /dev/null +++ b/code/datums/elements/light_blocking.dm @@ -0,0 +1,36 @@ +/** + * Attached to movable atoms with opacity. Listens to them move and updates their old and new turf loc's opacity accordingly. + */ +/datum/element/light_blocking + element_flags = ELEMENT_DETACH + + +/datum/element/light_blocking/Attach(datum/target) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/on_target_move) + var/atom/movable/movable_target = target + if(isturf(movable_target.loc)) + var/turf/turf_loc = movable_target.loc + turf_loc.add_opacity_source(target) + + +/datum/element/light_blocking/Detach(atom/movable/target) + . = ..() + UnregisterSignal(target, list(COMSIG_MOVABLE_MOVED)) + var/atom/movable/movable_target = target + if(isturf(movable_target.loc)) + var/turf/turf_loc = movable_target.loc + turf_loc.remove_opacity_source(target) + + +///Updates old and new turf loc opacities. +/datum/element/light_blocking/proc/on_target_move(atom/movable/source, atom/OldLoc, Dir, Forced = FALSE) + SIGNAL_HANDLER + if(isturf(OldLoc)) + var/turf/old_turf = OldLoc + old_turf.remove_opacity_source(source) + if(isturf(source.loc)) + var/turf/new_turf = source.loc + new_turf.add_opacity_source(source) diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm index 16d10ae0356..56faf42469f 100644 --- a/code/datums/mutable_appearance.dm +++ b/code/datums/mutable_appearance.dm @@ -10,10 +10,13 @@ plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE // And yes this does have to be in the constructor, BYOND ignores it if you set it as a normal var -// Helper similar to image() -/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER) +/// Helper similar to image() +/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE) var/mutable_appearance/MA = new() MA.icon = icon MA.icon_state = icon_state MA.layer = layer - return MA \ No newline at end of file + MA.plane = plane + MA.alpha = alpha + MA.appearance_flags |= appearance_flags + return MA diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 9c46ab200e7..90d43a7c36c 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -80,7 +80,7 @@ A.contents.Add(T) if(old_area) // Handle dynamic lighting update if - if(T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting) + if(SSlighting.subsystem_initialized && T.dynamic_lighting && old_area.dynamic_lighting != A.dynamic_lighting) if(A.dynamic_lighting) T.lighting_build_overlay() else diff --git a/code/game/atoms.dm b/code/game/atoms.dm index daf2596ced3..186a156ba52 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -26,9 +26,16 @@ ///Chemistry. // Overlays - var/list/our_overlays //our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate - var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. + ///Our local copy of (non-priority) overlays without byond magic. Use procs in SSoverlays to manipulate + var/list/our_overlays + ///Overlays that should remain on top and not normally removed when using cut_overlay functions, like c4. + var/list/priority_overlays + ///vis overlays managed by SSvis_overlays to automaticaly turn them like other overlays + var/list/managed_vis_overlays + ///Our local copy of filter data so we can add/remove it + var/list/filter_data + //Detective Work, used for the duplicate data points kept in the scanners var/list/original_atom // Track if we are already had initialize() called to prevent double-initialization. @@ -82,6 +89,13 @@ initialized = TRUE return INITIALIZE_HINT_NORMAL +/atom/Destroy() + if(reagents) + QDEL_NULL(reagents) + if(light) + QDEL_NULL(light) + return ..() + // Called after all object's normal initialize() if initialize() returns INITIALIZE_HINT_LATELOAD /atom/proc/LateInitialize() return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 645194543fb..2d82dc60711 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -30,6 +30,27 @@ var/cloaked = FALSE //If we're cloaked or not var/image/cloaked_selfimage //The image we use for our client to let them see where we are +/atom/movable/Initialize(mapload) + . = ..() + switch(blocks_emissive) + if(EMISSIVE_BLOCK_GENERIC) + var/mutable_appearance/gen_emissive_blocker = mutable_appearance(icon, icon_state, plane = PLANE_EMISSIVE, alpha = src.alpha) + gen_emissive_blocker.color = GLOB.em_block_color + gen_emissive_blocker.dir = dir + gen_emissive_blocker.appearance_flags |= appearance_flags + add_overlay(list(gen_emissive_blocker), TRUE) + if(EMISSIVE_BLOCK_UNIQUE) + render_target = ref(src) + em_block = new(src, render_target) + add_overlay(list(em_block), TRUE) + if(opacity) + AddElement(/datum/element/light_blocking) + switch(light_system) + if(MOVABLE_LIGHT) + AddComponent(/datum/component/overlay_lighting, starts_on = light_on) + if(MOVABLE_LIGHT_DIRECTIONAL) + AddComponent(/datum/component/overlay_lighting, is_directional = TRUE, starts_on = light_on) + /atom/movable/Destroy() . = ..() if(reagents) @@ -37,30 +58,19 @@ reagents = null for(var/atom/movable/AM in contents) qdel(AM) - var/turf/un_opaque - if(opacity && isturf(loc)) - un_opaque = loc + + if(opacity) + RemoveElement(/datum/element/light_blocking) moveToNullspace() - if(un_opaque) - un_opaque.recalc_atom_opacity() - if (pulledby) - if (pulledby.pulling == src) - pulledby.pulling = null - pulledby = null + + if(pulledby) + pulledby.stop_pulling() + + if(orbiting) + stop_orbit() QDEL_NULL(riding_datum) //VOREStation Add - -/atom/movable/vv_get_dropdown() - . = ..() - VV_DROPDOWN_OPTION("move_atom", "Move To Coordinate") - -/atom/vv_do_topic(list/href_list) - . = ..() - IF_VV_OPTION("move_atom") - usr.client.cmd_admin_move_atom(src) - href_list["datumrefresh"] = "\ref[src]" - /atom/movable/vv_edit_var(var_name, var_value) if(var_name in GLOB.VVpixelmovement) //Pixel movement is not yet implemented, changing this will break everything irreversibly. return FALSE @@ -211,12 +221,15 @@ //Called after a successful Move(). By this point, we've already moved /atom/movable/proc/Moved(atom/old_loc, direction, forced = FALSE, movetime) + SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, direction, forced, movetime) // Handle any buckled mobs on this movable if(has_buckled_mobs()) handle_buckled_mob_movement(old_loc, direction, movetime) if(riding_datum) riding_datum.handle_vehicle_layer() riding_datum.handle_vehicle_offsets() + for (var/datum/light_source/light as anything in light_sources) // Cycle through the light sources on this atom and tell them to update. + light.source_atom.update_light() return TRUE /atom/movable/set_dir(newdir) diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index 310a7a9ae70..280d2ed6bd5 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -91,6 +91,8 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked A.updateicon() /datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() + return + /* TODO spawn(0) for(var/datum/lighting_corner/L in world) if(L.z in using_map.admin_levels) @@ -100,7 +102,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked for(var/turf/space/T in world) OnTurfChange(T) - + */ /datum/universal_state/supermatter_cascade/proc/MiscSet() for (var/obj/machinery/firealarm/alm in machines) if (!(alm.stat & BROKEN)) diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 9b230cc3d2e..110b70ab8c4 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -7,6 +7,7 @@ use_power = USE_POWER_IDLE idle_power_usage = 300 active_power_usage = 300 + blocks_emissive = FALSE var/processing = 0 var/icon_keyboard = "generic_key" @@ -62,29 +63,32 @@ /obj/machinery/computer/update_icon() cut_overlays() - // No power - if(stat & NOPOWER) - set_light(0) - if(icon_keyboard) - add_overlay("[icon_keyboard]_off") - playsound(src, 'sound/machines/terminal_off.ogg', 50, 1) - // Yes power - else - if(icon_keyboard) - add_overlay(icon_keyboard) - set_light(light_range_on, light_power_on) - playsound(src, 'sound/machines/terminal_on.ogg', 50, 1) + + . = list() - // Broken - if(stat & BROKEN) - add_overlay("[icon_state]_broken") - // Not broken - else - add_overlay(icon_screen) + if(icon_keyboard) + if(stat & NOPOWER) + playsound(src, 'sound/machines/terminal_off.ogg', 50, 1) + return add_overlay("[icon_keyboard]_off") + . += icon_keyboard + + // This whole block lets screens ignore lighting and be visible even in the darkest room + var/overlay_state = icon_screen + if(stat & BROKEN) + overlay_state = "[icon_state]_broken" + . += mutable_appearance(icon, overlay_state) + . += emissive_appearance(icon, overlay_state) + playsound(src, 'sound/machines/terminal_on.ogg', 50, 1) + + add_overlay(.) /obj/machinery/computer/power_change() ..() update_icon() + if(stat & NOPOWER) + set_light(0) + else + set_light(light_range_on, light_power_on) /obj/machinery/computer/proc/set_broken() stat |= BROKEN diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index 6834bc550c1..18322bf3085 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -388,26 +388,19 @@ obj/machinery/door/blast/gate/open . = ..() apply_opacity_to_my_turfs(opacity) -/obj/machinery/door/blast/multi_tile/open() - if((. = ..())) - apply_opacity_to_my_turfs(opacity) +/obj/machinery/door/blast/multi_tile/set_opacity() + . = ..() + apply_opacity_to_my_turfs(opacity) -/obj/machinery/door/blast/multi_tile/close() - if((. = ..())) - apply_opacity_to_my_turfs(opacity) - -/obj/machinery/door/blast/multi_tile/Destroy() - apply_opacity_to_my_turfs(0) - return ..() - -//Multi-tile poddoors don't turn invisible automatically, so we change the opacity of the turfs below instead one by one. /obj/machinery/door/blast/multi_tile/proc/apply_opacity_to_my_turfs(new_opacity) for(var/turf/T in locs) - T.opacity = new_opacity - T.has_opaque_atom = new_opacity - T.reconsider_lights() + T.set_opacity(new_opacity) update_nearby_tiles() +/obj/machinery/door/blast/multi_tile/Destroy() + UnregisterSignal(src, COMSIG_MOVABLE_MOVED) + return ..() + /obj/machinery/door/blast/multi_tile icon_state_open = "open" icon_state_opening = "opening" diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index fc03dcb8d28..616205563de 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -11,6 +11,7 @@ density = 1 can_atmos_pass = ATMOS_PASS_PROC layer = DOOR_OPEN_LAYER + blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/open_layer = DOOR_OPEN_LAYER var/closed_layer = DOOR_CLOSED_LAYER diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm index ec5acbea73c..23b71bdb0f1 100644 --- a/code/game/machinery/doors/multi_tile.dm +++ b/code/game/machinery/doors/multi_tile.dm @@ -7,41 +7,25 @@ open_sound_powered = 'sound/machines/door/WideOpen.ogg' close_sound_powered = 'sound/machines/door/WideClose.ogg' -/obj/machinery/door/airlock/multi_tile/New() - ..() +/obj/machinery/door/airlock/multi_tile/Initialize(mapload) + . = ..() SetBounds() - if(opacity) - create_fillers() + RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/SetBounds) + apply_opacity_to_my_turfs(opacity) + +/obj/machinery/door/airlock/multi_tile/set_opacity() + . = ..() + apply_opacity_to_my_turfs(opacity) + +/obj/machinery/door/airlock/multi_tile/proc/apply_opacity_to_my_turfs(new_opacity) + for(var/turf/T in locs) + T.set_opacity(new_opacity) + update_nearby_tiles() /obj/machinery/door/airlock/multi_tile/Destroy() - QDEL_NULL(filler1) - QDEL_NULL(filler2) + UnregisterSignal(src, COMSIG_MOVABLE_MOVED) return ..() -/obj/machinery/door/airlock/multi_tile/Moved(atom/old_loc, direction, forced = FALSE) - . = ..() - SetBounds() - -/obj/machinery/door/airlock/multi_tile/open() - . = ..() - - if(filler1) - filler1.set_opacity(opacity) - if(filler2) - filler2.set_opacity(opacity) - - return . - -/obj/machinery/door/airlock/multi_tile/close() - . = ..() - - if(filler1) - filler1.set_opacity(opacity) - if(filler2) - filler2.set_opacity(opacity) - - return . - /obj/machinery/door/airlock/multi_tile/proc/SetBounds() if(dir in list(EAST, WEST)) bound_width = width * world.icon_size @@ -50,18 +34,6 @@ bound_width = world.icon_size bound_height = width * world.icon_size -/obj/machinery/door/airlock/multi_tile/proc/create_fillers() - if(src.dir > 3) - filler1 = new/obj/machinery/filler_object (src.loc) - filler2 = new/obj/machinery/filler_object (get_step(src,EAST)) - else - filler1 = new/obj/machinery/filler_object (src.loc) - filler2 = new/obj/machinery/filler_object (get_step(src,NORTH)) - filler1.density = 0 - filler2.density = 0 - filler1.set_opacity(opacity) - filler2.set_opacity(opacity) - /obj/machinery/door/airlock/multi_tile/glass name = "Glass Airlock" icon = 'icons/obj/doors/Door2x1glass.dmi' @@ -74,12 +46,6 @@ icon = 'icons/obj/doors/Door2x1metal.dmi' assembly_type = /obj/structure/door_assembly/multi_tile -/obj/machinery/filler_object - name = "" - icon = 'icons/obj/doors/rapid_pdoor.dmi' - icon_state = "" - density = 0 - /obj/machinery/door/airlock/multi_tile/metal/mait icon = 'icons/obj/doors/Door2x1_Maint.dmi' //req_one_access = list(access_maint_tunnels) //VOREStaiton Edit - Maintenance is open access diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm index 315d470432a..a1a22b80c89 100644 --- a/code/game/machinery/fire_alarm.dm +++ b/code/game/machinery/fire_alarm.dm @@ -5,8 +5,9 @@ FIRE ALARM name = "fire alarm" desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." icon = 'icons/obj/monitors.dmi' - icon_state = "fire0" + icon_state = "fire" layer = ABOVE_WINDOW_LAYER + blocks_emissive = FALSE var/detecting = 1.0 var/working = 1.0 var/time = 10.0 @@ -45,24 +46,36 @@ FIRE ALARM if(stat & BROKEN) icon_state = "firex" set_light(0) + return else if(stat & NOPOWER) icon_state = "firep" set_light(0) + return + + var/fire_state + + . = list() + icon_state = "fire" + if(!detecting) + fire_state = "fire1" + set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") else - if(!detecting) - icon_state = "fire1" - set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") - else - icon_state = "fire0" - switch(seclevel) - if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00") - if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00") - if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff") - if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900") - if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9") - if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") - if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633") - add_overlay("overlay_[seclevel]") + fire_state = "fire0" + switch(seclevel) + if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00") + if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00") + if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff") + if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900") + if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9") + if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") + if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633") + + . += mutable_appearance(icon, fire_state) + . += emissive_appearance(icon, fire_state) + . += mutable_appearance(icon, "overlay_[seclevel]") + . += emissive_appearance(icon, "overlay_[seclevel]") + + add_overlay(.) /obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume) if(detecting) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index c078b854d0c..89bd996dea9 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -11,6 +11,7 @@ use_power = USE_POWER_IDLE idle_power_usage = 10 power_channel = LIGHT + blocks_emissive = FALSE var/on = 1 var/area/area = null var/otherarea = null @@ -36,19 +37,18 @@ return ..() /obj/machinery/light_switch/proc/updateicon() - if(!overlay) - overlay = image(icon, "light1-overlay") - overlay.plane = PLANE_LIGHTING_ABOVE - - overlays.Cut() + cut_overlays() if(stat & NOPOWER) icon_state = "light-p" set_light(0) else icon_state = "light[on]" - overlay.icon_state = "light[on]-overlay" - overlays += overlay set_light(2, 0.1, on ? "#82FF4C" : "#F86060") + . = list() + . += emissive_appearance(icon, "light[on]-overlay") + + return add_overlay(.) + /obj/machinery/light_switch/examine(mob/user) . = ..() diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 47d26c7ab1c..1900811c8a2 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -114,6 +114,8 @@ Class Procs: var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess. + blocks_emissive = EMISSIVE_BLOCK_GENERIC + /obj/machinery/New(l, d=0) ..(l) if(d) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index d4068974ae3..6af917ad035 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -45,6 +45,7 @@ active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power power_channel = EQUIP //drains power from the EQUIPMENT channel req_one_access = list(access_security, access_heads) + blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/raised = FALSE //if the turret cover is "open" and the turret is raised var/raising= FALSE //if the turret is currently opening or closing its cover diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 7033648deaa..151cf5b47c6 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -12,6 +12,7 @@ would spawn and follow the beaker, even if it is carried or thrown. mouse_opacity = 0 unacidable = 1//So effect are not targeted by alien acid. pass_flags = PASSTABLE | PASSGRILLE + blocks_emissive = EMISSIVE_BLOCK_GENERIC /datum/effect/effect/system var/number = 3 diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 5958f79d002..e9f2438027e 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -61,4 +61,41 @@ /obj/effect/temporary_effect/lightning_strike/Initialize() icon_state += "[rand(1,2)]" // To have two variants of lightning sprites. animate(src, alpha = 0, time = time_to_die - 1) - . = ..() \ No newline at end of file + . = ..() + +/obj/effect/dummy/lighting_obj + name = "lighting fx obj" + desc = "Tell a coder if you're seeing this." + icon_state = "nothing" + light_system = MOVABLE_LIGHT + light_range = MINIMUM_USEFUL_LIGHT_RANGE + light_color = COLOR_WHITE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + light_on = TRUE + +/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration) + . = ..() + if(!isnull(_range)) + set_light_range(_range) + if(!isnull(_power)) + set_light_power(_power) + if(!isnull(_color)) + set_light_color(_color) + if(_duration) + QDEL_IN(src, _duration) + +/obj/effect/dummy/lighting_obj/moblight + name = "mob lighting fx" + +/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration) + . = ..() + if(!ismob(loc)) + return INITIALIZE_HINT_QDEL + +/obj/effect/dummy/lighting_obj/moblight/fire + name = "fire" + light_color = LIGHT_COLOR_FIRE + light_range = LIGHT_RANGE_FIRE + +/obj/effect/abstract/directional_lighting + mouse_opacity = MOUSE_OPACITY_TRANSPARENT diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 6c8a04143b0..5ed1ccc66c1 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -109,3 +109,45 @@ plane = PLANE_LIGHTING_ABOVE pixel_x = -32 pixel_y = -32 + +/obj/effect/overlay/vis + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + anchored = TRUE + vis_flags = VIS_INHERIT_DIR + ///When detected to be unused it gets set to world.time, after a while it gets removed + var/unused = 0 + ///overlays which go unused for this amount of time get cleaned up + var/cache_expiration = 2 MINUTES + +/* +/obj/effect/overlay/atmos_excited + name = "excited group" + icon = null + icon_state = null + anchored = TRUE // should only appear in vis_contents, but to be safe + appearance_flags = RESET_TRANSFORM | TILE_BOUND + invisibility = INVISIBILITY_ABSTRACT + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + + plane = ATMOS_GROUP_PLANE +*/ + +/obj/effect/overlay/light_visible + name = "" + icon = 'icons/effects/light_overlays/light_32.dmi' + icon_state = "light" + plane = PLANE_O_LIGHTING_VISUAL + appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + alpha = 0 + vis_flags = NONE + +/obj/effect/overlay/light_cone + name = "" + icon = 'icons/effects/light_overlays/light_cone.dmi' + icon_state = "light" + plane = PLANE_O_LIGHTING_VISUAL + appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + vis_flags = NONE + alpha = 110 diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 5e109aafc9e..7bbffecbe8a 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -2,6 +2,7 @@ name = "item" icon = 'icons/obj/items.dmi' w_class = ITEMSIZE_NORMAL + blocks_emissive = EMISSIVE_BLOCK_GENERIC var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite var/randpixel = 6 @@ -632,7 +633,7 @@ var/list/global/slot_flags_enumeration = list( //Make the blood_overlay have the proper color then apply it. blood_overlay.color = blood_color - overlays += blood_overlay + add_overlay(blood_overlay) //if this blood isn't already in the list, add it if(istype(M)) @@ -824,6 +825,9 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. if(!inhands) apply_blood(standing) //Some items show blood when bloodied apply_accessories(standing) //Some items sport accessories like webbing + + //Apply overlays to our...overlay + apply_overlays(standing) //Return our icon return standing @@ -905,6 +909,15 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. /obj/item/proc/apply_accessories(var/image/standing) return standing +/obj/item/proc/apply_overlays(var/image/standing) + if(!blocks_emissive) + return standing + + var/mutable_appearance/blocker_overlay = mutable_appearance(standing.icon, standing.icon_state, plane = PLANE_EMISSIVE, appearance_flags = KEEP_APART) + blocker_overlay.color = GLOB.em_block_color + standing.add_overlay(blocker_overlay) + return standing + /obj/item/MouseEntered(location,control,params) . = ..() if(usr.is_preference_enabled(/datum/client_preference/inv_tooltips) && ((src in usr) || isstorage(loc))) // If in inventory or in storage we're looking at diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 3dafea4ac78..62d1b4b9341 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -7,15 +7,18 @@ slot_flags = SLOT_BELT matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) action_button_name = "Toggle Flashlight" + + light_system = MOVABLE_LIGHT_DIRECTIONAL + light_range = 4 //luminosity when on + light_power = 0.8 //lighting power when on + light_color = "#FFFFFF" //LIGHT_COLOR_INCANDESCENT_FLASHLIGHT //lighting colour when on + light_cone_y_offset = -7 + var/on = 0 - var/brightness_on = 4 //luminosity when on - var/flashlight_power = 0.8 //lighting power when on - var/flashlight_colour = LIGHT_COLOR_INCANDESCENT_FLASHLIGHT //lighting colour when on + var/obj/item/weapon/cell/cell var/cell_type = /obj/item/weapon/cell/device - var/list/brightness_levels - var/brightness_level = "medium" - var/power_usage + var/power_usage = 1 var/power_use = 1 /obj/item/device/flashlight/Initialize() @@ -23,12 +26,8 @@ if(power_use && cell_type) cell = new cell_type(src) - brightness_levels = list("low" = 0.25, "medium" = 0.5, "high" = 1) - power_usage = brightness_levels[brightness_level] - else - verbs -= /obj/item/device/flashlight/verb/toggle - - update_icon() + + update_brightness() /obj/item/device/flashlight/Destroy() STOP_PROCESSING(SSobj, src) @@ -38,63 +37,40 @@ /obj/item/device/flashlight/get_cell() return cell -/obj/item/device/flashlight/verb/toggle() - set name = "Toggle Flashlight Brightness" - set category = "Object" - set src in usr - set_brightness(usr) - -/obj/item/device/flashlight/proc/set_brightness(mob/user as mob) - var/choice = input("Choose a brightness level.") as null|anything in brightness_levels - if(choice) - brightness_level = choice - power_usage = brightness_levels[choice] - to_chat(user, "You set the brightness level on \the [src] to [brightness_level].") - update_icon() - /obj/item/device/flashlight/process() if(!on || !cell) return PROCESS_KILL - if(brightness_level && power_usage) + if(power_usage) if(cell.use(power_usage) != power_usage) // we weren't able to use our full power_usage amount! visible_message("\The [src] flickers before going dull.") - set_light(0) - playsound(src, 'sound/effects/sparks3.ogg', 10, 1, -3) //Small cue that your light went dull in your pocket. + playsound(src, 'sound/effects/sparks3.ogg', 10, 1, -3) //Small cue that your light went dull in your pocket. //VOREStation Edit on = 0 - update_icon() + update_brightness() return PROCESS_KILL -/obj/item/device/flashlight/update_icon() +/obj/item/device/flashlight/proc/update_brightness() if(on) icon_state = "[initial(icon_state)]-on" - - if(brightness_level == "low") - set_light(brightness_on/2, flashlight_power*0.75, flashlight_colour) - else if(brightness_level == "high") - set_light(brightness_on*1.5, flashlight_power*1.1, flashlight_colour) - else - set_light(brightness_on, flashlight_power, flashlight_colour) - else - icon_state = "[initial(icon_state)]" - set_light(0) + icon_state = initial(icon_state) + set_light_on(on) + if(light_system == STATIC_LIGHT) + update_light() /obj/item/device/flashlight/examine(mob/user) . = ..() - if(power_use && brightness_level) - . += "\The [src] is set to [brightness_level]." - if(cell) - . += "\The [src] has a \the [cell] attached." + if(power_use && cell) + . += "\The [src] has a \the [cell] attached." - if(cell.charge <= cell.maxcharge*0.25) - . += "It appears to have a low amount of power remaining." - else if(cell.charge > cell.maxcharge*0.25 && cell.charge <= cell.maxcharge*0.5) - . += "It appears to have an average amount of power remaining." - else if(cell.charge > cell.maxcharge*0.5 && cell.charge <= cell.maxcharge*0.75) - . += "It appears to have an above average amount of power remaining." - else if(cell.charge > cell.maxcharge*0.75 && cell.charge <= cell.maxcharge) - . += "It appears to have a high amount of power remaining." + if(cell.charge <= cell.maxcharge*0.25) + . += "It appears to have a low amount of power remaining." + else if(cell.charge > cell.maxcharge*0.25 && cell.charge <= cell.maxcharge*0.5) + . += "It appears to have an average amount of power remaining." + else if(cell.charge > cell.maxcharge*0.5 && cell.charge <= cell.maxcharge*0.75) + . += "It appears to have an above average amount of power remaining." + else if(cell.charge > cell.maxcharge*0.75 && cell.charge <= cell.maxcharge) + . += "It appears to have a high amount of power remaining." /obj/item/device/flashlight/attack_self(mob/user) if(power_use) @@ -109,8 +85,8 @@ START_PROCESSING(SSobj, src) else if(power_use) STOP_PROCESSING(SSobj, src) - playsound(src, 'sound/weapons/empty.ogg', 15, 1, -3) - update_icon() + playsound(src, 'sound/weapons/empty.ogg', 15, 1, -3) // VOREStation Edit + update_brightness() user.update_action_buttons() return 1 @@ -177,7 +153,7 @@ to_chat(user, "You remove the cell from the [src].") playsound(src, 'sound/machines/button.ogg', 30, 1, 0) on = 0 - update_icon() + update_brightness() return ..() else @@ -225,7 +201,7 @@ cell = W to_chat(user, "You install a cell in \the [src].") playsound(src, 'sound/machines/button.ogg', 30, 1, 0) - update_icon() + update_brightness() else to_chat(user, "\The [src] already has a cell.") else @@ -242,7 +218,7 @@ drop_sound = 'sound/items/drop/accessory.ogg' pickup_sound = 'sound/items/pickup/accessory.ogg' slot_flags = SLOT_EARS - brightness_on = 2 + light_range = 2 w_class = ITEMSIZE_TINY power_use = 0 @@ -270,7 +246,7 @@ name = "maglight" desc = "A very, very heavy duty flashlight." icon_state = "maglight" - flashlight_colour = LIGHT_COLOR_FLUORESCENT_FLASHLIGHT + light_color = LIGHT_COLOR_FLUORESCENT_FLASHLIGHT force = 10 slot_flags = SLOT_BELT w_class = ITEMSIZE_SMALL @@ -283,7 +259,7 @@ desc = "A miniature lamp, that might be used by small robots." icon_state = "penlight" item_state = null - brightness_on = 2 + light_range = 2 w_class = ITEMSIZE_TINY power_use = 0 @@ -294,10 +270,11 @@ icon_state = "lamp" force = 10 center_of_mass = list("x" = 13,"y" = 11) - brightness_on = 10 + light_range = 5 w_class = ITEMSIZE_LARGE power_use = 0 on = 1 + light_system = STATIC_LIGHT // green-shaded desk lamp @@ -305,8 +282,7 @@ desc = "A classic green-shaded desk lamp." icon_state = "lampgreen" center_of_mass = list("x" = 15,"y" = 11) - brightness_on = 5 - flashlight_colour = "#FFC58F" + light_color = "#FFC58F" /obj/item/device/flashlight/lamp/verb/toggle_light() set name = "Toggle light" @@ -322,9 +298,9 @@ name = "flare" desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'." w_class = ITEMSIZE_SMALL - brightness_on = 8 // Pretty bright. - flashlight_power = 0.8 - flashlight_colour = LIGHT_COLOR_FLARE + light_range = 8 // Pretty bright. + light_power = 0.8 + light_color = LIGHT_COLOR_FLARE icon_state = "flare" item_state = "flare" action_button_name = null //just pull it manually, neckbeard. @@ -334,6 +310,7 @@ power_use = 0 drop_sound = 'sound/items/drop/gloves.ogg' pickup_sound = 'sound/items/pickup/gloves.ogg' + light_system = MOVABLE_LIGHT /obj/item/device/flashlight/flare/New() fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds. @@ -354,7 +331,7 @@ on = 0 src.force = initial(src.force) src.damtype = initial(src.damtype) - update_icon() + update_brightness() /obj/item/device/flashlight/flare/attack_self(mob/user) @@ -375,7 +352,7 @@ /obj/item/device/flashlight/flare/proc/ignite() //Used for flare launchers. on = !on - update_icon() + update_brightness() force = on_damage damtype = "fire" START_PROCESSING(SSobj, src) @@ -387,9 +364,10 @@ name = "green glowstick" desc = "A green military-grade glowstick." w_class = ITEMSIZE_SMALL - brightness_on = 4 - flashlight_power = 0.9 - flashlight_colour = "#49F37C" + light_system = MOVABLE_LIGHT + light_range = 4 + light_power = 0.9 + light_color = "#49F37C" icon_state = "glowstick" item_state = "glowstick" var/fuel = 0 @@ -409,7 +387,7 @@ /obj/item/device/flashlight/glowstick/proc/turn_off() on = 0 - update_icon() + update_brightness() /obj/item/device/flashlight/glowstick/attack_self(mob/user) @@ -427,28 +405,28 @@ /obj/item/device/flashlight/glowstick/red name = "red glowstick" desc = "A red military-grade glowstick." - flashlight_colour = "#FC0F29" + light_color = "#FC0F29" icon_state = "glowstick_red" item_state = "glowstick_red" /obj/item/device/flashlight/glowstick/blue name = "blue glowstick" desc = "A blue military-grade glowstick." - flashlight_colour = "#599DFF" + light_color = "#599DFF" icon_state = "glowstick_blue" item_state = "glowstick_blue" /obj/item/device/flashlight/glowstick/orange name = "orange glowstick" desc = "A orange military-grade glowstick." - flashlight_colour = "#FA7C0B" + light_color = "#FA7C0B" icon_state = "glowstick_orange" item_state = "glowstick_orange" /obj/item/device/flashlight/glowstick/yellow name = "yellow glowstick" desc = "A yellow military-grade glowstick." - flashlight_colour = "#FEF923" + light_color = "#FEF923" icon_state = "glowstick_yellow" item_state = "glowstick_yellow" @@ -460,17 +438,17 @@ icon = 'icons/obj/lighting.dmi' icon_state = "floor1" //not a slime extract sprite but... something close enough! item_state = "slime" - flashlight_colour = "#FFF423" + light_color = "#FFF423" w_class = ITEMSIZE_TINY - brightness_on = 6 + light_range = 6 on = 1 //Bio-luminesence has one setting, on. power_use = 0 /obj/item/device/flashlight/slime/New() ..() - set_light(brightness_on, flashlight_power, flashlight_colour) + set_light(light_range, light_power, light_color) -/obj/item/device/flashlight/slime/update_icon() +/obj/item/device/flashlight/slime/update_brightness() return /obj/item/device/flashlight/slime/attack_self(mob/user) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index f81419be75e..87332c776f0 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -1,6 +1,7 @@ /obj/structure icon = 'icons/obj/structures.dmi' w_class = ITEMSIZE_NO_CONTAINER + blocks_emissive = EMISSIVE_BLOCK_GENERIC var/climbable var/climb_delay = 3.5 SECONDS diff --git a/code/game/objects/structures/crates_lockers/__closets.dm b/code/game/objects/structures/crates_lockers/__closets.dm index 85e45314de4..4af69175fd8 100644 --- a/code/game/objects/structures/crates_lockers/__closets.dm +++ b/code/game/objects/structures/crates_lockers/__closets.dm @@ -7,6 +7,7 @@ density = 1 w_class = ITEMSIZE_HUGE layer = UNDER_JUNK_LAYER + blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/opened = 0 var/sealed = 0 diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index 2ea6372aef3..dc6e92355d7 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -6,6 +6,7 @@ density = 1 anchored = 1 health = 0 //destroying the statue kills the mob within + blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/intialTox = 0 //these are here to keep the mob from taking damage from things that logically wouldn't affect a rock var/intialFire = 0 //it's a little sloppy I know but it was this or the GODMODE flag. Lesser of two evils. var/intialBrute = 0 @@ -43,7 +44,7 @@ qdel(src) return - START_PROCESSING(SSobj, src) + START_PROCESSING(SSobj, src) ..() /obj/structure/closet/statue/process() diff --git a/code/game/objects/structures/fitness.dm b/code/game/objects/structures/fitness.dm index 729e578ba58..f41fbfa8cf8 100644 --- a/code/game/objects/structures/fitness.dm +++ b/code/game/objects/structures/fitness.dm @@ -29,6 +29,7 @@ name = "weightlifting machine" desc = "A machine used to lift weights." icon_state = "weightlifter" + blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/weight = 1 var/list/qualifiers = list("with ease", "without any trouble", "with great effort") diff --git a/code/game/objects/structures/flora/trees.dm b/code/game/objects/structures/flora/trees.dm index 8eefe0c3134..2ced6ba550c 100644 --- a/code/game/objects/structures/flora/trees.dm +++ b/code/game/objects/structures/flora/trees.dm @@ -265,6 +265,7 @@ icon = 'icons/obj/flora/deadtrees.dmi' icon_state = "tree_sif" base_state = "tree_sif" + blocks_emissive = FALSE product = /obj/item/stack/material/log/sif catalogue_data = list(/datum/category_item/catalogue/flora/sif_tree) randomize_size = TRUE @@ -289,7 +290,10 @@ update_icon() /obj/structure/flora/tree/sif/update_icon() - set_light(5 - light_shift, 1, "#33ccff") // 5 variants, missing bulbs. 5th has no bulbs, so no glow. - var/image/glow = image(icon = icon, icon_state = "[base_state][light_shift]_glow") - glow.plane = PLANE_LIGHTING_ABOVE - overlays = list(glow) + cut_overlays() + var/bulbs = (5 - light_shift) + if(bulbs > 0) + set_light(bulbs, 1, "#33ccff") // 5 variants, missing bulbs. 5th has no bulbs, so no glow. + add_overlay(mutable_appearance(icon, "[base_state][bulbs]_glow")) + add_overlay(emissive_appearance(icon, "[base_state][bulbs]_glow")) + \ No newline at end of file diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm index 19ae278730d..6fe2aa384ad 100644 --- a/code/game/objects/structures/simple_doors.dm +++ b/code/game/objects/structures/simple_doors.dm @@ -12,7 +12,7 @@ var/isSwitchingStates = 0 var/hardness = 1 var/oreAmount = 7 - + /obj/structure/simple_door/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) TemperatureAct(exposed_temperature) @@ -20,13 +20,22 @@ hardness -= material.combustion_effect(get_turf(src),temperature, 0.3) CheckHardness() -/obj/structure/simple_door/New(var/newloc, var/material_name) - ..() +/obj/structure/simple_door/Initialize(mapload, var/material_name) + . = ..() + set_material(material_name) + if(!material) + return INITIALIZE_HINT_QDEL + +/obj/structure/simple_door/Destroy() + STOP_PROCESSING(SSobj, src) + update_nearby_tiles() + return ..() + +/obj/structure/simple_door/proc/set_material(var/material_name) if(!material_name) material_name = DEFAULT_WALL_MATERIAL material = get_material_by_name(material_name) if(!material) - qdel(src) return hardness = max(1,round(material.integrity/10)) icon_state = material.door_icon_base @@ -40,11 +49,6 @@ START_PROCESSING(SSobj, src) update_nearby_tiles(need_rebuild=1) -/obj/structure/simple_door/Destroy() - STOP_PROCESSING(SSobj, src) - update_nearby_tiles() - return ..() - /obj/structure/simple_door/get_material() return material @@ -198,38 +202,38 @@ return SSradiation.radiate(src, round(material.radioactivity/3)) -/obj/structure/simple_door/iron/New(var/newloc,var/material_name) - ..(newloc, "iron") +/obj/structure/simple_door/iron/Initialize(mapload,var/material_name) + ..(mapload, material_name || "iron") -/obj/structure/simple_door/silver/New(var/newloc,var/material_name) - ..(newloc, "silver") +/obj/structure/simple_door/silver/Initialize(mapload,var/material_name) + ..(mapload, material_name || "silver") -/obj/structure/simple_door/gold/New(var/newloc,var/material_name) - ..(newloc, "gold") +/obj/structure/simple_door/gold/Initialize(mapload,var/material_name) + ..(mapload, material_name || "gold") -/obj/structure/simple_door/uranium/New(var/newloc,var/material_name) - ..(newloc, "uranium") +/obj/structure/simple_door/uranium/Initialize(mapload,var/material_name) + ..(mapload, material_name || "uranium") -/obj/structure/simple_door/sandstone/New(var/newloc,var/material_name) - ..(newloc, "sandstone") +/obj/structure/simple_door/sandstone/Initialize(mapload,var/material_name) + ..(mapload, material_name || "sandstone") -/obj/structure/simple_door/phoron/New(var/newloc,var/material_name) - ..(newloc, "phoron") +/obj/structure/simple_door/phoron/Initialize(mapload,var/material_name) + ..(mapload, material_name || "phoron") -/obj/structure/simple_door/diamond/New(var/newloc,var/material_name) - ..(newloc, "diamond") +/obj/structure/simple_door/diamond/Initialize(mapload,var/material_name) + ..(mapload, material_name || "diamond") -/obj/structure/simple_door/wood/New(var/newloc,var/material_name) - ..(newloc, MAT_WOOD) +/obj/structure/simple_door/wood/Initialize(mapload,var/material_name) + ..(mapload, material_name || MAT_WOOD) -/obj/structure/simple_door/sifwood/New(var/newloc,var/material_name) - ..(newloc, MAT_SIFWOOD) +/obj/structure/simple_door/sifwood/Initialize(mapload,var/material_name) + ..(mapload, material_name || MAT_SIFWOOD) -/obj/structure/simple_door/resin/New(var/newloc,var/material_name) - ..(newloc, "resin") +/obj/structure/simple_door/resin/Initialize(mapload,var/material_name) + ..(mapload, material_name || "resin") -/obj/structure/simple_door/cult/New(var/newloc,var/material_name) - ..(newloc, "cult") +/obj/structure/simple_door/cult/Initialize(mapload,var/material_name) + ..(mapload, material_name || "cult") /obj/structure/simple_door/cult/TryToSwitchState(atom/user) if(isliving(user)) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index b0670868861..2ae7c7adfcc 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -424,7 +424,7 @@ return fulltile /obj/structure/window/is_between_turfs(var/turf/origin, var/turf/target) - if(fulltile) + if(is_fulltile()) return TRUE return ..() @@ -458,6 +458,8 @@ icon_state = "[basestate]" return + else + flags = 0 // Removes ON_BORDER and OPPOSITE_OPACITY var/list/dirs = list() if(anchored) for(var/obj/structure/window/W in orange(src,1)) @@ -503,6 +505,7 @@ icon_state = "window-full" maxhealth = 24 fulltile = TRUE + flags = 0 /obj/structure/window/phoronbasic name = "phoron window" @@ -520,6 +523,7 @@ icon_state = "phoronwindow-full" maxhealth = 80 fulltile = TRUE + flags = 0 /obj/structure/window/phoronreinforced name = "reinforced borosilicate window" @@ -538,6 +542,7 @@ icon_state = "phoronrwindow-full" maxhealth = 160 fulltile = TRUE + flags = 0 /obj/structure/window/reinforced name = "reinforced window" @@ -555,6 +560,7 @@ icon_state = "rwindow-full" maxhealth = 80 fulltile = TRUE + flags = 0 /obj/structure/window/reinforced/tinted name = "tinted window" @@ -592,6 +598,7 @@ icon_state = "rwindow-full" maxhealth = 80 fulltile = TRUE + flags = 0 /obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/device/multitool) && !anchored) // Only allow programming if unanchored! @@ -617,8 +624,8 @@ else animate(src, color="#222222", time=5) set_opacity(1) - - + var/turf/T = get_turf(src) + T.recalculate_directional_opacity() /obj/machinery/button/windowtint name = "window tint control" diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 9cacb36eaf4..db8947b0563 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -41,7 +41,9 @@ //Lighting related luminosity = !(dynamic_lighting) - has_opaque_atom |= (opacity) + + if(opacity) + directional_opacity = ALL_CARDINALS //Pathfinding related if(movement_cost && pathweight == 1) // This updates pathweight automatically. diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index b3988f3f77a..efbea4ffb37 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -32,11 +32,13 @@ N = /turf/simulated/open var/obj/fire/old_fire = fire - var/old_opacity = opacity var/old_dynamic_lighting = dynamic_lighting - var/old_affecting_lights = affecting_lights - var/old_lighting_overlay = lighting_overlay - var/old_corners = corners + var/old_lighting_object = lighting_object + var/old_lighting_corner_NE = lighting_corner_NE + var/old_lighting_corner_SE = lighting_corner_SE + var/old_lighting_corner_SW = lighting_corner_SW + var/old_lighting_corner_NW = lighting_corner_NW + var/old_directional_opacity = directional_opacity var/old_outdoors = outdoors var/old_dangerous_objects = dangerous_objects @@ -94,21 +96,29 @@ W.post_change() . = W - recalc_atom_opacity() - dangerous_objects = old_dangerous_objects - 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_corner_NE = old_lighting_corner_NE + lighting_corner_SE = old_lighting_corner_SE + lighting_corner_SW = old_lighting_corner_SW + lighting_corner_NW = old_lighting_corner_NW + + if(SSlighting.subsystem_initialized) + lighting_object = old_lighting_object + + directional_opacity = old_directional_opacity + recalculate_directional_opacity() + + if (dynamic_lighting != old_dynamic_lighting) + if (IS_DYNAMIC_LIGHTING(src)) lighting_build_overlay() else lighting_clear_overlay() + else if(lighting_object && !lighting_object.needs_update) + lighting_object.update() + + for(var/turf/space/space_tile in RANGE_TURFS(1, src)) + space_tile.update_starlight() if(preserve_outdoors) outdoors = old_outdoors diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index a98e0898510..3d31c9e08fb 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -86,7 +86,8 @@ datum/preferences "2" = "character_preview_map:2,5", "4" = "character_preview_map:2,3", "8" = "character_preview_map:2,1", - "BG" = "character_preview_map:1,1 to 3,8" + "BG" = "character_preview_map:1,1 to 3,8", + "PMH" = "character_preview_map:2,7" ) //Jobs, uses bitflags @@ -270,6 +271,13 @@ datum/preferences if(!client) return + var/obj/screen/setup_preview/pm_helper/PMH = LAZYACCESS(char_render_holders, "PMH") + if(!PMH) + PMH = new + LAZYSET(char_render_holders, "PMH", PMH) + client.screen |= PMH + PMH.screen_loc = preview_screen_locs["PMH"] + var/obj/screen/setup_preview/bg/BG = LAZYACCESS(char_render_holders, "BG") if(!BG) BG = new diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 8c54e2ff551..c57c261322a 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -463,10 +463,10 @@ w_class = ITEMSIZE_SMALL blood_sprite_state = "helmetblood" + light_system = MOVABLE_LIGHT_DIRECTIONAL + light_cone_y_offset = 11 + var/light_overlay = "helmet_light" - var/light_applied - var/brightness_on - var/on = 0 var/image/helmet_light sprite_sheets = list( @@ -477,23 +477,21 @@ pickup_sound = 'sound/items/pickup/hat.ogg' /obj/item/clothing/head/attack_self(mob/user) - if(brightness_on) + if(light_range) if(!isturf(user.loc)) - to_chat(user, "You cannot turn the light on while in this [user.loc]") + to_chat(user, "You cannot toggle the light while in this [user.loc]") return - on = !on - to_chat(user, "You [on ? "enable" : "disable"] the helmet light.") update_flashlight(user) + to_chat(user, "You [light_on ? "enable" : "disable"] the helmet light.") else return ..(user) /obj/item/clothing/head/proc/update_flashlight(var/mob/user = null) - if(on && !light_applied) - set_light(brightness_on) - light_applied = 1 - else if(!on && light_applied) - set_light(0) - light_applied = 0 + set_light_on(!light_on) + + if(light_system == STATIC_LIGHT) + update_light() + update_icon(user) user.update_action_buttons() @@ -537,7 +535,7 @@ if(ishuman(user)) H = user - if(on) + if(light_on) // Generate object icon. if(!light_overlay_cache["[light_overlay]_icon"]) light_overlay_cache["[light_overlay]_icon"] = image(icon = 'icons/obj/light_overlays.dmi', icon_state = "[light_overlay]") diff --git a/code/modules/clothing/clothing_icons.dm b/code/modules/clothing/clothing_icons.dm index 2adfbfa0b98..1762d092017 100644 --- a/code/modules/clothing/clothing_icons.dm +++ b/code/modules/clothing/clothing_icons.dm @@ -19,7 +19,7 @@ //HELMET: May have a lighting overlay /obj/item/clothing/head/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer = 0,var/icon/clip_mask = null) var/image/standing = ..() - if(on && slot_name == slot_head_str) + if(light_on && slot_name == slot_head_str) var/cache_key = "[light_overlay][LAZYACCESS(sprite_sheets,body_type) ? "_[body_type]" : ""]" if(standing && light_overlay_cache[cache_key]) standing.add_overlay(light_overlay_cache[cache_key]) diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index f974c321c06..47a5b89f1aa 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -2,7 +2,8 @@ name = "hard hat" desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight." icon_state = "hardhat0_yellow" - brightness_on = 4 //luminosity when on + light_range = 4 //luminosity when on + light_cone_y_offset = 14 light_overlay = "hardhat_light" armor = list(melee = 30, bullet = 5, laser = 20,energy = 10, bomb = 20, bio = 10, rad = 20) flags_inv = 0 diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 8cf8a6292e7..cf0527c6a6c 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -111,7 +111,7 @@ icon_state = "flexitac" armor = list(melee = 40, bullet = 40, laser = 60, energy = 35, bomb = 30, bio = 0, rad = 0) siemens_coefficient = 0.6 - brightness_on = 6 + light_range = 6 light_overlay = "helmet_light_dual_green" action_button_name = "Toggle Head-light" min_cold_protection_temperature = T0C - 20 diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 6ef9ee2be6b..dbb5f6d9398 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -167,7 +167,7 @@ icon_state = "hardhat0_pumpkin"//Could stand to be renamed flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|BLOCKHAIR body_parts_covered = HEAD|FACE|EYES - brightness_on = 2 + light_range = 2 light_overlay = "jackolantern" w_class = ITEMSIZE_NORMAL drop_sound = 'sound/items/drop/herb.ogg' diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces.dm b/code/modules/clothing/spacesuits/rig/rig_pieces.dm index cc76771d459..3c1843698c0 100644 --- a/code/modules/clothing/spacesuits/rig/rig_pieces.dm +++ b/code/modules/clothing/spacesuits/rig/rig_pieces.dm @@ -9,7 +9,7 @@ body_parts_covered = HEAD|FACE|EYES heat_protection = HEAD|FACE|EYES cold_protection = HEAD|FACE|EYES - brightness_on = 4 + light_range = 4 sprite_sheets = list( SPECIES_TAJ = 'icons/mob/species/tajaran/helmet.dmi', SPECIES_SKRELL = 'icons/mob/species/skrell/helmet.dmi', diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index 162b097aa71..4cd8ade06e2 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -29,8 +29,7 @@ action_button_name = "Toggle Helmet Light" light_overlay = "helmet_light" - brightness_on = 4 - on = 0 + light_range = 4 /obj/item/clothing/head/helmet/space/Initialize() . = ..() diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm index 3a92bd2be10..926365c5c1b 100644 --- a/code/modules/clothing/spacesuits/void/void.dm +++ b/code/modules/clothing/spacesuits/void/void.dm @@ -120,7 +120,6 @@ to_chat(M, "Your suit's cooling unit deploys.") cooler.canremove = 0 - /obj/item/clothing/suit/space/void/dropped() ..() @@ -150,6 +149,22 @@ cooler.canremove = 1 cooler.forceMove(src) +/obj/item/clothing/suit/space/void/proc/attach_helmet(var/obj/item/clothing/head/helmet/space/void/helm) + if(!istype(helm) || helmet) + return + + helm.forceMove(src) + helm.set_light_flags(helm.light_flags | LIGHT_ATTACHED) + helmet = helm + +/obj/item/clothing/suit/space/void/proc/remove_helmet() + if(!helmet) + return + + helmet.forceMove(get_turf(src)) + helmet.set_light_flags(helmet.light_flags & ~LIGHT_ATTACHED) + helmet = null + /obj/item/clothing/suit/space/void/verb/toggle_helmet() set name = "Toggle Helmet" @@ -243,9 +258,8 @@ src.cooler = null else if(choice == helmet) to_chat(user, "You detach \the [helmet] from \the [src]'s helmet mount.") - helmet.forceMove(get_turf(src)) + remove_helmet() playsound(src, W.usesound, 50, 1) - src.helmet = null else if(choice == boots) to_chat(user, "You detach \the [boots] from \the [src]'s boot mounts.") boots.forceMove(get_turf(src)) @@ -260,8 +274,7 @@ else to_chat(user, "You attach \the [W] to \the [src]'s helmet mount.") user.drop_item() - W.forceMove(src) - src.helmet = W + attach_helmet(W) return else if(istype(W,/obj/item/clothing/shoes/magboots)) if(boots) diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm new file mode 100644 index 00000000000..690b9b52163 --- /dev/null +++ b/code/modules/lighting/emissive_blocker.dm @@ -0,0 +1,46 @@ +/** + * Internal atom that copies an appearance on to the blocker plane + * + * Copies an appearance vis render_target and render_source on to the emissive blocking plane. + * This means that the atom in question will block any emissive sprites. + * This should only be used internally. If you are directly creating more of these, you're + * almost guaranteed to be doing something wrong. + */ +/atom/movable/emissive_blocker + name = "emissive blocker" + plane = PLANE_EMISSIVE + layer = FLOAT_LAYER + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + //Why? + //render_targets copy the transform of the target as well, but vis_contents also applies the transform + //to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform. + //Since only render_target handles transform we don't get any applied transform "stacking" + appearance_flags = RESET_TRANSFORM + +/atom/movable/emissive_blocker/Initialize(mapload, source) + . = ..() + verbs.Cut() //Cargo culting from lighting object, this maybe affects memory usage? + + render_source = source + color = GLOB.em_block_color + + +/atom/movable/emissive_blocker/ex_act(severity) + return FALSE + +/atom/movable/emissive_blocker/singularity_act() + return + +/atom/movable/emissive_blocker/singularity_pull() + return + +/atom/movable/emissive_blocker/blob_act() + return + +/atom/movable/emissive_blocker/onTransitZ() + return + +//Prevents people from moving these after creation, because they shouldn't be. +/atom/movable/emissive_blocker/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE) + if(harderforce) + return ..() diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 39894b13947..0d91198f440 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -1,110 +1,218 @@ /atom - var/light_power = 1 // intensity of the light - var/light_range = 0 // range in tiles of the light - var/light_color // Hexadecimal RGB string representing the colour of the light + ///Light systems, both shouldn't be active at the same time. + var/light_system = STATIC_LIGHT + ///Range of the light in tiles. Zero means no light. + var/light_range = 0 + ///Intensity of the light. The stronger, the less shadows you will see on the lit area. + var/light_power = 1 + ///Hexadecimal RGB string representing the colour of the light. White by default. + var/light_color = COLOR_WHITE + ///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values. + var/light_on = FALSE + ///Bitflags to determine lighting-related atom properties. + var/light_flags = NONE + ///Our light source. Don't fuck with this directly unless you have a good reason! + var/tmp/datum/light_source/light + ///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. + var/tmp/list/light_sources - var/datum/light_source/light - var/list/light_sources +/atom/movable + ///Hint for directional light cone positioning. X is relevant when facing north/south (this setting is for south and inverted for north) + var/light_cone_x_offset // When facing south, inverted when facing north + ///Hint for directional light cone positioning. Y is relevant when facing east/west (same value used for both east and west) + var/light_cone_y_offset // When facing east/west, ignored for north/south (uses 16 in those cases) + ///Highest-intensity light affecting us, which determines our visibility. + var/affecting_dynamic_lumi = 0 + ///Lazylist to keep track on the sources of illumination. + var/list/affected_dynamic_lights + ///Either FALSE, [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE] + var/blocks_emissive = FALSE + ///Internal holder for emissive blocker object, do not use directly use blocks_emissive + var/atom/movable/emissive_blocker/em_block -// Nonsensical value for l_color default, so we can detect if it gets set to null. +// The proc you should always use to set the light of this atom. +// Nonesensical 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) - . = 0 //make it less costly if nothing's changed +/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_on) + if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE) + l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players. + + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT, l_range, l_power, l_color, l_on) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + + // Legacy behavior helper + if(l_range == 0) + l_on = FALSE + else if(l_range > 0) + l_on = TRUE + + var/needs_update = FALSE + if(!isnull(l_power) && l_power != light_power) + if(!isnull(set_light_power(l_power))) + needs_update = TRUE + + if(!isnull(l_range) && l_range != light_range) + if(!isnull(set_light_range(l_range))) + needs_update = TRUE - if(l_power != null && l_power != light_power) - light_power = l_power - . = 1 - if(l_range != null && l_range != light_range) - light_range = l_range - . = 1 if(l_color != NONSENSICAL_VALUE && l_color != light_color) - light_color = l_color - . = 1 + if(!isnull(set_light_color(l_color))) + needs_update = TRUE - if(.) update_light() + if(!isnull(l_on) && l_on != light_on) + if(!isnull(set_light_on(l_on))) + needs_update = TRUE + + if(needs_update) + update_light() #undef NONSENSICAL_VALUE +// 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 (QDELETED(src)) + return - if(!light_power || !light_range) - if(light) - light.destroy() - light = null + if(light_system != STATIC_LIGHT) + CRASH("update_light() for [src] with following light_system value: [light_system]") + + if (!light_power || !light_range || !light_on) // We won't emit light anyways, destroy the light source. + QDEL_NULL(light) else - if(!istype(loc, /atom/movable)) + if (!ismovable(loc)) // We choose what atom should be the top atom of the light here. . = src else . = loc - if(light) + if (light) // Update the light or create it if it does not exist. light.update(.) else - light = new /datum/light_source(src, .) + light = new/datum/light_source(src, .) -/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() - light = null - return ..() - -/atom/movable/Destroy() - var/turf/T = loc - if(opacity && istype(T)) - T.reconsider_lights() - return ..() - -/atom/movable/Moved(atom/old_loc, direction, forced = FALSE) - . = ..() - - for(var/datum/light_source/L in light_sources) - L.source_atom.update_light() - - var/turf/new_turf = loc - var/turf/old_turf = old_loc - if(istype(old_turf) && opacity) - old_turf.reconsider_lights() - - if(istype(new_turf) && opacity) - new_turf.reconsider_lights() +/** + * Updates the atom's opacity value. + * + * This exists to act as a hook for associated behavior. + * It notifies (potentially) affected light sources so they can update (if needed). + */ /atom/proc/set_opacity(new_opacity) if(new_opacity == opacity) return - + SEND_SIGNAL(src, COMSIG_ATOM_SET_OPACITY, new_opacity) + . = opacity opacity = new_opacity - var/turf/T = isturf(src) ? src : loc - if(!isturf(T)) + + +/atom/movable/set_opacity(new_opacity) + . = ..() + if(isnull(.) || !isturf(loc)) return - if(new_opacity == TRUE) - T.has_opaque_atom = TRUE - T.reconsider_lights() + if(opacity) + AddElement(/datum/element/light_blocking) 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() + RemoveElement(/datum/element/light_blocking) -/obj/item/equipped() - . = ..() - update_light() -/obj/item/pickup() +/turf/set_opacity(new_opacity) . = ..() - update_light() + if(isnull(.)) + return + recalculate_directional_opacity() -/obj/item/dropped() - . = ..() - update_light() +/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + return + + +/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + if(!_duration) + stack_trace("Lighting FX obj created on a turf without a duration") + new /obj/effect/dummy/lighting_obj (src, _range, _power, _color, _duration) + + +/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + if(!_duration) + stack_trace("Lighting FX obj created on a obj without a duration") + new /obj/effect/dummy/lighting_obj (get_turf(src), _range, _power, _color, _duration) + + +/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + mob_light(_range, _power, _color, _duration) + + +/mob/living/proc/mob_light(_range, _power, _color, _duration) + var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _range, _power, _color, _duration) + return mob_light_obj + +/// Setter for the light power of this atom. +/atom/proc/set_light_power(new_power) + if(new_power == light_power) + return + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + . = light_power + light_power = new_power + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_POWER, .) + +/// Setter for the light range of this atom. +/atom/proc/set_light_range(new_range) + if(new_range == light_range) + return + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + . = light_range + light_range = new_range + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_RANGE, .) + +/// Setter for the light color of this atom. +/atom/proc/set_light_color(new_color) + if(new_color == light_color) + return + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + . = light_color + light_color = new_color + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_COLOR, .) + +/// Setter for whether or not this atom's light is on. +/atom/proc/set_light_on(new_value) + if(new_value == light_on) + return + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + . = light_on + light_on = new_value + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .) + +/// Setter for the light flags of this atom. +/atom/proc/set_light_flags(new_value) + if(new_value == light_flags) + return + if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE) + return + . = light_flags + light_flags = new_value + SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_FLAGS, .) + +///Keeps track of the sources of dynamic luminosity and updates our visibility with the highest. +/atom/movable/proc/update_dynamic_luminosity() + var/highest = 0 + for(var/i in affected_dynamic_lights) + if(affected_dynamic_lights[i] <= highest) + continue + highest = affected_dynamic_lights[i] + if(highest == affecting_dynamic_lumi) + return + luminosity -= affecting_dynamic_lumi + affecting_dynamic_lumi = highest + luminosity += affecting_dynamic_lumi + + +///Helper to change several lighting overlay settings. +/atom/movable/proc/set_light_range_power_color(range, power, color) + set_light_range(range) + set_light_power(power) + set_light_color(color) diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index 30230a69e04..e02e04b0f7c 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -1,41 +1,37 @@ -/var/total_lighting_corners = 0 -/var/datum/lighting_corner/dummy/dummy_lighting_corner = new -// Because we can control each corner of every lighting overlay. +// Because we can control each corner of every lighting object. // 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/list/datum/light_source/affecting // Light sources affecting us. - var/x = 0 - var/y = 0 - var/z = 0 + var/x = 0 + var/y = 0 + var/turf/master_NE + var/turf/master_SE + var/turf/master_SW + var/turf/master_NW + + //"raw" color values, changed by update_lumcount() var/lum_r = 0 var/lum_g = 0 var/lum_b = 0 + //true color values, guaranteed to be between 0 and 1 + var/cache_r = LIGHTING_SOFT_THRESHOLD + var/cache_g = LIGHTING_SOFT_THRESHOLD + var/cache_b = LIGHTING_SOFT_THRESHOLD + + ///the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this + var/largest_color_luminosity = 0 + + ///whether we are to be added to SSlighting's corners_queue list for an update 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) +/datum/lighting_corner/New(turf/new_turf, diagonal) . = ..() - - total_lighting_corners++ - - masters[new_turf] = turn(diagonal, 180) - z = new_turf.z + save_master(new_turf, turn(diagonal, 180)) 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. @@ -46,69 +42,75 @@ // 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 + var/turf/new_master_turf // 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 + new_master_turf = get_step(new_turf, diagonal) + if (new_master_turf) // In case we're on the map's border. + save_master(new_master_turf, diagonal) // 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 + new_master_turf = get_step(new_turf, horizontal) + if (new_master_turf) // Ditto. + save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. // And finally the vertical one. - T = get_step(new_turf, vertical) - if (T) - if (!T.corners) - T.corners = list(null, null, null, null) + new_master_turf = get_step(new_turf, vertical) + if (new_master_turf) + save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. - 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 +/datum/lighting_corner/proc/save_master(turf/master, dir) + switch (dir) + if (NORTHEAST) + master_NE = master + master.lighting_corner_SW = src + if (SOUTHEAST) + master_SE = master + master.lighting_corner_NW = src + if (SOUTHWEST) + master_SW = master + master.lighting_corner_NE = src + if (NORTHWEST) + master_NW = master + master.lighting_corner_SE = src - update_active() +/datum/lighting_corner/proc/self_destruct_if_idle() + if (!LAZYLEN(affecting)) + qdel(src, force = TRUE) -/datum/lighting_corner/proc/update_active() - active = FALSE - for (var/turf/T in masters) - if (T.lighting_overlay) - active = TRUE +/datum/lighting_corner/proc/vis_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.vis_update() + +/datum/lighting_corner/proc/full_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.recalc_corner(src) // 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) +/datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b) + if (!(delta_r || delta_g || delta_b)) // 0 is falsey ok + return + lum_r += delta_r lum_g += delta_g lum_b += delta_b if (!needs_update) needs_update = TRUE - lighting_update_corners += src + SSlighting.corners_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 - var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1. +/datum/lighting_corner/proc/update_objects() + // Cache these values ahead of time so 4 individual lighting objects don't all calculate them individually. + var/lum_r = src.lum_r + var/lum_g = src.lum_g + var/lum_b = src.lum_b + var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1. . = 1 // factor - if (mx > 1) - . = 1 / mx + if (largest_color_luminosity > 1) + . = 1 / largest_color_luminosity #if LIGHTING_SOFT_THRESHOLD != 0 - else if (mx < LIGHTING_SOFT_THRESHOLD) + else if (largest_color_luminosity < LIGHTING_SOFT_THRESHOLD) . = 0 // 0 means soft lighting. cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD @@ -119,21 +121,56 @@ cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) #endif - 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 - lighting_update_overlays += T.lighting_overlay + src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE) + + var/datum/lighting_object/lighting_object = master_NE?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_SE?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_SW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_NW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + self_destruct_if_idle() /datum/lighting_corner/dummy/New() return -/datum/lighting_corner/Destroy(var/force) +/datum/lighting_corner/Destroy(force) if (!force) return QDEL_HINT_LETMELIVE - crash_with("Who decided to force qdel() a lighting corner? Why did you do this?") + + for (var/datum/light_source/light_source as anything in affecting) + LAZYREMOVE(light_source.effect_str, src) + affecting = null + + if (master_NE) + master_NE.lighting_corner_SW = null + master_NE.lighting_corners_initialised = FALSE + if (master_SE) + master_SE.lighting_corner_NW = null + master_SE.lighting_corners_initialised = FALSE + if (master_SW) + master_SW.lighting_corner_NE = null + master_SW.lighting_corners_initialised = FALSE + if (master_NW) + master_NW.lighting_corner_SE = null + master_NW.lighting_corners_initialised = FALSE + if(needs_update) + SSlighting.corners_queue -= src + return ..() diff --git a/code/modules/lighting/lighting_fake_sun_vr.dm b/code/modules/lighting/lighting_fake_sun_vr.dm index 898532d8c22..9eb76e7f52b 100644 --- a/code/modules/lighting/lighting_fake_sun_vr.dm +++ b/code/modules/lighting/lighting_fake_sun_vr.dm @@ -3,6 +3,7 @@ desc = "Deletes itself, but first updates all the lighting on outdoor turfs." icon = 'icons/effects/effects_vr.dmi' icon_state = "fakesun" + var/datum/light_source/sun/fake_sun var/list/possible_light_setups = list( list( @@ -66,28 +67,31 @@ /obj/effect/fake_sun/LateInitialize() . = ..() + var/list/choice = pick(possible_light_setups) + if(choice["brightness"] <= LIGHTING_SOFT_THRESHOLD) // dark! + return - var/list/our_choice = pick(possible_light_setups) + fake_sun = new + fake_sun.light_color = choice["color"] + fake_sun.light_power = choice["brightness"] + + var/list/zees = GetConnectedZlevels() + var/min = z + var/max = z + for(var/zee in zees) + if(zee < min) + min = z + if(zee > max) + max = z + + var/list/all_turfs = block(locate(1, 1, min), locate(world.maxx, world.maxy, max)) + var/list/turfs_to_use = list() + for(var/turf/T as anything in all_turfs) + if(T.outdoors) + turfs_to_use += T - // Calculate new values to apply - var/new_brightness = our_choice["brightness"] - var/new_color = our_choice["color"] - var/lum_r = new_brightness * GetRedPart (new_color) / 255 - var/lum_g = new_brightness * GetGreenPart(new_color) / 255 - var/lum_b = new_brightness * GetBluePart (new_color) / 255 - var/static/update_gen = -1 // Used to prevent double-processing corners. Otherwise would happen when looping over adjacent turfs. - - var/list/turfs = block(locate(1,1,z),locate(world.maxx,world.maxy,z)) - - for(var/turf/simulated/T as anything in turfs) - if(!T.lighting_overlay) - T.lighting_build_overlay() - if(!T.outdoors) - continue - for(var/C in T.get_corners()) - var/datum/lighting_corner/LC = C - if(LC.update_gen != update_gen && LC.active) - LC.update_gen = update_gen - LC.update_lumcount(lum_r, lum_g, lum_b) - update_gen-- - qdel(src) \ No newline at end of file + if(!turfs_to_use.len) + warning("Fake sun placed on a level where it can't find any outdoor turfs to color at [x],[y],[z].") + return + + fake_sun.update_corners(turfs_to_use) diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index eb5097cf5b2..abf3c39ba6a 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -1,51 +1,51 @@ -/var/total_lighting_overlays = 0 -/atom/movable/lighting_overlay - name = "" - mouse_opacity = 0 - simulated = 0 - anchored = 1 - icon = LIGHTING_ICON - plane = PLANE_LIGHTING - //invisibility = INVISIBILITY_LIGHTING - color = LIGHTING_BASE_MATRIX - icon_state = "light1" - //auto_init = 0 // doesn't need special init - blend_mode = BLEND_OVERLAY - - var/lum_r = 0 - var/lum_g = 0 - var/lum_b = 0 +/datum/lighting_object + ///the underlay we are currently applying to our turf to apply light + var/mutable_appearance/current_underlay + ///whether we are already in the SSlighting.objects_queue list var/needs_update = FALSE -/atom/movable/lighting_overlay/Initialize() - // doesn't need special init - initialized = TRUE - return INITIALIZE_HINT_NORMAL + ///the turf that our light is applied to + var/turf/affected_turf -/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE) - . = ..() - verbs.Cut() - total_lighting_overlays++ - - 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 - if(no_update) +/datum/lighting_object/New(turf/source) + if(!SSlighting.subsystem_initialized) + stack_trace("lighting_object created before SSlighting up!") return - update_overlay() - -/atom/movable/lighting_overlay/proc/update_overlay() - set waitfor = FALSE - var/turf/T = loc - - 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!") + if(!isturf(source)) qdel(src, force=TRUE) + stack_trace("a lighting object was assigned to [source], a non turf! ") return + . = ..() + + current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", source.z, PLANE_LIGHTING, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM) + + affected_turf = source + if (affected_turf.lighting_object) + qdel(affected_turf.lighting_object, force = TRUE) + stack_trace("a lighting object was assigned to a turf that already had a lighting object!") + + affected_turf.lighting_object = src + affected_turf.luminosity = 0 + + for(var/turf/space/space_tile in RANGE_TURFS(1, affected_turf)) + space_tile.update_starlight() + + needs_update = TRUE + SSlighting.objects_queue += src + +/datum/lighting_object/Destroy(force) + if (!force) + return QDEL_HINT_LETMELIVE + SSlighting.objects_queue -= src + if (isturf(affected_turf)) + affected_turf.lighting_object = null + affected_turf.luminosity = 1 + affected_turf.underlays -= current_underlay + affected_turf = null + return ..() + +/datum/lighting_object/proc/update() // To the future coder who sees this and thinks // "Why didn't he just use a loop?" @@ -55,50 +55,54 @@ // 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/static/datum/lighting_corner/dummy/dummy_lighting_corner = new - var/datum/lighting_corner/cr = LAZYACCESS(T.corners,3) || dummy_lighting_corner - var/datum/lighting_corner/cg = LAZYACCESS(T.corners,2) || dummy_lighting_corner - var/datum/lighting_corner/cb = LAZYACCESS(T.corners,4) || dummy_lighting_corner - var/datum/lighting_corner/ca = LAZYACCESS(T.corners,1) || dummy_lighting_corner + var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner + var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner + var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner + var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner - var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) + var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity) - var/rr = cr.cache_r - var/rg = cr.cache_g - var/rb = cr.cache_b + var/rr = red_corner.cache_r + var/rg = red_corner.cache_g + var/rb = red_corner.cache_b - var/gr = cg.cache_r - var/gg = cg.cache_g - var/gb = cg.cache_b + var/gr = green_corner.cache_r + var/gg = green_corner.cache_g + var/gb = green_corner.cache_b - var/br = cb.cache_r - var/bg = cb.cache_g - var/bb = cb.cache_b + var/br = blue_corner.cache_r + var/bg = blue_corner.cache_g + var/bb = blue_corner.cache_b - var/ar = ca.cache_r - var/ag = ca.cache_g - var/ab = ca.cache_b + var/ar = alpha_corner.cache_r + var/ag = alpha_corner.cache_g + var/ab = alpha_corner.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. + // 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" - color = null + //anything that passes the first case is very likely to pass the second, and addition is a little faster in this case + affected_turf.underlays -= current_underlay + current_underlay.icon_state = "transparent" + current_underlay.color = null + affected_turf.underlays += current_underlay else if(!set_luminosity) - icon_state = LIGHTING_ICON_STATE_DARK - color = null + affected_turf.underlays -= current_underlay + current_underlay.icon_state = "dark" + current_underlay.color = null + affected_turf.underlays += current_underlay else - icon_state = null - color = list( + affected_turf.underlays -= current_underlay + current_underlay.icon_state = "gradient" + current_underlay.color = list( rr, rg, rb, 00, gr, gg, gb, 00, br, bg, bb, 00, @@ -106,38 +110,12 @@ 00, 00, 00, 01 ) - luminosity = set_luminosity + affected_turf.underlays += current_underlay -// Variety of overrides so the overlays don't get affected by weird things. -/atom/movable/lighting_overlay/ex_act() - return + affected_turf.luminosity = set_luminosity -/atom/movable/lighting_overlay/singularity_act() - return +/datum/lighting_object/proc/removefromturf() + affected_turf.underlays -= current_underlay -/atom/movable/lighting_overlay/singularity_pull() - return - -/atom/movable/lighting_overlay/forceMove() - return 0 //should never move - -/atom/movable/lighting_overlay/Move() - return 0 - -/atom/movable/lighting_overlay/throw_at() - return 0 - -/atom/movable/lighting_overlay/Destroy(var/force) - if (force) - total_lighting_overlays-- - global.lighting_update_overlays -= src - LAZYREMOVE(SSlighting.currentrun, src) - - var/turf/T = loc - if(istype(T)) - T.lighting_overlay = null - T.luminosity = 1 - - return ..() - else - return QDEL_HINT_LETMELIVE +/datum/lighting_object/proc/addtoturf() + affected_turf.underlays += current_underlay diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index ad014b013d3..b6473f36ddf 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -1,24 +1,6 @@ // Create lighting overlays on all turfs with dynamic lighting in areas with dynamic lighting. -/proc/create_all_lighting_overlays() - for(var/area/A in world) - if(!A.dynamic_lighting) - continue - for(var/turf/T in A) - if(!T.dynamic_lighting) - continue - new /atom/movable/lighting_overlay(T, TRUE) - CHECK_TICK +/proc/create_all_lighting_objects() + var/list/all_turfs = block(locate(1,1,1), locate(world.maxx, world.maxy, world.maxz)) + for(var/turf/T as anything in all_turfs) + T.lighting_build_overlay() CHECK_TICK - -/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) \ No newline at end of file diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 451b8273c84..4f863bf34ae 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -1,15 +1,22 @@ -/var/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/source_atom // The atom that we belong to. + ///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 that we belong to. + var/atom/source_atom - 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() + ///The turf under the source atom. + var/turf/source_turf + ///The turf the top_atom appears to over. + var/turf/pixel_turf + ///Intensity of the emitter light. + var/light_power + /// The range of the emitted light. + var/light_range + /// The colour of the light, string, decomposed by parse_light_color() + var/light_color // Variables for keeping track of the colour. var/lum_r @@ -21,142 +28,83 @@ 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 + /// List used to store how much we're affecting corners. + var/list/datum/lighting_corner/effect_str - var/applied = FALSE // Whether we have applied our light yet or not. + /// Whether we have applied our light yet or not. + var/applied = FALSE - 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 + /// whether we are to be added to SSlighting's sources_queue list for an update + var/needs_update = LIGHTING_NO_UPDATE -/datum/light_source/New(var/atom/owner, var/atom/top) - total_lighting_sources++ + +/datum/light_source/New(atom/owner, 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. + LAZYADD(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 + if (top_atom != source_atom) + LAZYADD(top_atom.light_sources, src) source_turf = top_atom + pixel_turf = get_turf_pixel(top_atom) || source_turf + light_power = source_atom.light_power light_range = source_atom.light_range light_color = source_atom.light_color - parse_light_color() - - effect_str = list() - affecting_turfs = list() + PARSE_LIGHT_COLOR(src) update() +/datum/light_source/Destroy(force) + remove_lum() + if (source_atom) + LAZYREMOVE(source_atom.light_sources, src) + + if (top_atom) + LAZYREMOVE(top_atom.light_sources, src) + + if (needs_update) + SSlighting.sources_queue -= src + + top_atom = null + source_atom = null + source_turf = null + pixel_turf = null return ..() -// Kill ourselves. -/datum/light_source/proc/destroy() - total_lighting_sources-- - destroyed = TRUE - force_update() - if(source_atom) - if(!source_atom.light_sources) - log_runtime(EXCEPTION("Atom [source_atom] was a light source, but lacked a light source list!\n"), source_atom) - else - source_atom.light_sources -= src +// Yes this doesn't align correctly on anything other than 4 width tabs. +// If you want it to go switch everybody to elastic tab stops. +// Actually that'd be great if you could! +#define EFFECT_UPDATE(level) \ + if (needs_update == LIGHTING_NO_UPDATE) \ + SSlighting.sources_queue += src; \ + if (needs_update < level) \ + needs_update = level; \ - 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) +/datum/light_source/proc/update(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 + if (new_top_atom && new_top_atom != top_atom) + if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom. + LAZYREMOVE(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() + if (top_atom != source_atom) + LAZYADD(top_atom.light_sources, src) // 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) + EFFECT_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) + EFFECT_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 - - 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 + EFFECT_UPDATE(LIGHTING_VIS_UPDATE) // Macro that applies light to a new corner. // It is a macro in the interest of speed, yet not having to copy paste it. @@ -164,127 +112,264 @@ // 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 \ +// /tg/ falloff alg +#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) + +// Bay/Polaris falloff alg +//#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range))) + +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, pixel_turf); \ + . *= light_power; \ + var/OLD = effect_str[C]; \ + \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b) \ + ); \ + +#define REMOVE_CORNER(C) \ + . = -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 \ - ); +#define APPLY_CORNER_SIMPLE(C) \ + . = light_power; \ + var/OLD = effect_str[C]; \ + \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b) \ + ); \ -// This is the define used to calculate falloff. -#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range))) -/datum/light_source/proc/apply_lum() - var/static/update_gen = 1 - applied = 1 +/datum/light_source/proc/remove_lum() + applied = FALSE + for (var/datum/lighting_corner/corner as anything in effect_str) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) + + effect_str = null + +/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner) + LAZYINITLIST(effect_str) + if (effect_str[corner]) // Already have one. + REMOVE_CORNER(corner) + effect_str[corner] = 0 + + APPLY_CORNER(corner) + effect_str[corner] = . + +/datum/light_source/proc/get_turfs_in_range() + return view(CEILING(light_range, 1), source_turf) + +/datum/light_source/proc/update_corners() + var/update = FALSE + var/atom/source_atom = src.source_atom + + if (QDELETED(source_atom)) + qdel(src) + return + + if (source_atom.light_power != light_power) + light_power = source_atom.light_power + update = TRUE + + if (source_atom.light_range != light_range) + light_range = source_atom.light_range + update = TRUE + + if (!top_atom) + top_atom = source_atom + update = TRUE + + if (!light_range || !light_power) + qdel(src) + return + + if (isturf(top_atom)) + if (source_turf != top_atom) + source_turf = top_atom + pixel_turf = source_turf + update = TRUE + else if (top_atom.loc != source_turf) + source_turf = top_atom.loc + pixel_turf = get_turf_pixel(top_atom) + update = TRUE + else + var/pixel_loc = get_turf_pixel(top_atom) + if (pixel_loc != pixel_turf) + pixel_turf = pixel_loc + update = TRUE + + if (!isturf(source_turf)) + if (applied) + remove_lum() + return + + if (light_range && light_power && !applied) + update = TRUE + + if (source_atom.light_color != light_color) + light_color = source_atom.light_color + PARSE_LIGHT_COLOR(src) + update = TRUE + + else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b) + update = TRUE + + if (update) + needs_update = LIGHTING_CHECK_UPDATE + applied = TRUE + else if (needs_update == LIGHTING_CHECK_UPDATE) + return //nothing's changed + + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + + if (source_turf) + var/oldlum = source_turf.luminosity + source_turf.luminosity = CEILING(light_range, 1) + for(var/turf/T in get_turfs_in_range()) + if(!IS_OPAQUE_TURF(T)) + if (!T.lighting_corners_initialised) + T.generate_missing_corners() + corners[T.lighting_corner_NE] = 0 + corners[T.lighting_corner_SE] = 0 + corners[T.lighting_corner_SW] = 0 + corners[T.lighting_corner_NW] = 0 + turfs += T + source_turf.luminosity = oldlum + + var/list/datum/lighting_corner/new_corners = (corners - effect_str) + LAZYINITLIST(effect_str) + if (needs_update == LIGHTING_VIS_UPDATE) + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . + else + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . + + for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners + APPLY_CORNER(corner) + if (. != 0) + effect_str[corner] = . + else + LAZYREMOVE(corner.affecting, src) + effect_str -= corner + + var/list/datum/lighting_corner/gone_corners = effect_str - corners + for (var/datum/lighting_corner/corner as anything in gone_corners) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) + effect_str -= gone_corners - // 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() + UNSETEMPTY(effect_str) - for(var/datum/lighting_corner/C in T.get_corners()) - if(C.update_gen == update_gen) - continue +// For planets and fake suns +/datum/light_source/sun + light_range = 1 + light_color = "#FFFFFF" + light_power = 2 + var/applied_power = 2 - C.update_gen = update_gen - C.affecting += src +/datum/light_source/sun/New() + return - if(!C.active) - effect_str[C] = 0 - continue +/datum/light_source/sun/force_update() + return - APPLY_CORNER(C) +/datum/light_source/sun/vis_update() + return - if(!T.affecting_lights) - T.affecting_lights = list() +/datum/light_source/sun/update_corners(var/list/turfs_to_update) + if(!LAZYLEN(turfs_to_update)) + stack_trace("Planet sun tried to update with no turfs given") + return - T.affecting_lights += src - affecting_turfs += T + // Update lum_r/g/b from our light_color + PARSE_LIGHT_COLOR(src) + + // Noop update + if(lum_r == applied_lum_r && lum_g == applied_lum_g && lum_b == applied_lum_b && light_power == applied_power) + return + + // No reason to unapply on the first run or if previous run was 0 power + if(applied) + remove_lum() - update_gen++ + // Entirely dark, just stop now that we've remove_lum()'d + if(!light_power) + applied = FALSE + return -/datum/light_source/proc/remove_lum() - applied = FALSE + LAZYINITLIST(effect_str) - 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 + for(var/turf/T as anything in turfs_to_update) + if(!IS_OPAQUE_TURF(T)) + if(!T.lighting_corners_initialised) + T.generate_missing_corners() + + var/datum/lighting_corner/LC = T.lighting_corner_NE + if(!corners[LC]) + corners[LC] = 1 + APPLY_CORNER_SIMPLE(LC) + LAZYADD(LC.affecting, src) + effect_str[LC] = . + + LC = T.lighting_corner_SE + if(!corners[LC]) + corners[LC] = 1 + APPLY_CORNER_SIMPLE(LC) + LAZYADD(LC.affecting, src) + effect_str[LC] = . + + LC = T.lighting_corner_NW + if(!corners[LC]) + corners[LC] = 1 + APPLY_CORNER_SIMPLE(LC) + LAZYADD(LC.affecting, src) + effect_str[LC] = . + + LC = T.lighting_corner_SW + if(!corners[LC]) + corners[LC] = 1 + APPLY_CORNER_SIMPLE(LC) + LAZYADD(LC.affecting, src) + effect_str[LC] = . - 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 + CHECK_TICK - 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 + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + applied_power = light_power + applied = TRUE // remove_lum() now necessary in the future - for(var/datum/lighting_corner/C in corners - effect_str) // New corners - C.affecting += src - if(!C.active) - effect_str[C] = 0 - continue + UNSETEMPTY(effect_str) - 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 EFFECT_UPDATE #undef LUM_FALLOFF #undef REMOVE_CORNER #undef APPLY_CORNER +#undef REMOVE_CORNER_SIMPLE +#undef APPLY_CORNER_SIMPLE \ No newline at end of file diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index b8a29fc43a1..59732b5d60e 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -1,96 +1,142 @@ /turf - var/dynamic_lighting = TRUE // Does the turf use dynamic lighting? - luminosity = 1 + ///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component. + var/dynamic_lumcount = 0 + + var/dynamic_lighting = TRUE 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. + ///Our lighting object. + var/tmp/datum/lighting_object/lighting_object + ///Lighting Corner datums. + var/tmp/datum/lighting_corner/lighting_corner_NE + var/tmp/datum/lighting_corner/lighting_corner_SE + var/tmp/datum/lighting_corner/lighting_corner_SW + var/tmp/datum/lighting_corner/lighting_corner_NW + + ///Which directions does this turf block the vision of, taking into account both the turf's opacity and the movable opacity_sources. + var/directional_opacity = NONE + ///Lazylist of movable atoms providing opacity sources. + var/list/atom/movable/opacity_sources // 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() + lighting_corner_NE?.vis_update() + lighting_corner_SE?.vis_update() + lighting_corner_SW?.vis_update() + lighting_corner_NW?.vis_update() /turf/proc/lighting_clear_overlay() - if(lighting_overlay) - qdel(lighting_overlay, force = TRUE) + if(lighting_object) + qdel(lighting_object, force=TRUE) - for(var/datum/lighting_corner/C in corners) - C.update_active() - -// Builds a lighting overlay for us, but only if our area is dynamic. +// Builds a lighting object for us, but only if our area is dynamic. /turf/proc/lighting_build_overlay() - if(lighting_overlay) + if(!has_dynamic_lighting()) return - var/area/A = loc - if(A.dynamic_lighting && 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 + lighting_clear_overlay() + new/datum/lighting_object(src) // Used to get a scaled lumcount. -/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) - if(!lighting_overlay) +/turf/proc/get_lumcount(minlum = 0, maxlum = 1) + if (!lighting_object) return 1 var/totallums = 0 - for(var/datum/lighting_corner/L in corners) - totallums += max(L.lum_r, L.lum_g, L.lum_b) + var/datum/lighting_corner/L + L = lighting_corner_NE + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SE + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SW + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_NW + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g - totallums /= 4 // 4 corners, max channel selected, return the average - totallums =(totallums - minlum) /(maxlum - minlum) + totallums /= 12 // 4 corners, each with 3 channels, get the average. + + totallums = (totallums - minlum) / (maxlum - minlum) + + totallums += dynamic_lumcount 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 +// Returns a boolean whether the turf is on soft lighting. +// Soft lighting being the threshold at which point the overlay considers +// itself as too dark to allow sight and see_in_dark becomes useful. +// So basically if this returns true the tile is unlit black. +/turf/proc/is_softly_lit() + if (!lighting_object) + return FALSE -// If an opaque movable atom moves around we need to potentially update visibility. -/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) - . = ..() + return !(luminosity || dynamic_lumcount) - 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) - . = ..() +///Proc to add movable sources of opacity on the turf and let it handle lighting code. +/turf/proc/add_opacity_source(atom/movable/new_source) + LAZYADD(opacity_sources, new_source) + if(opacity) + return + recalculate_directional_opacity() - 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. +///Proc to remove movable sources of opacity on the turf and let it handle lighting code. +/turf/proc/remove_opacity_source(atom/movable/old_source) + LAZYREMOVE(opacity_sources, old_source) + if(opacity) //Still opaque, no need to worry on updating. + return + recalculate_directional_opacity() - return corners + +///Calculate on which directions this turfs block view. +/turf/proc/recalculate_directional_opacity() + . = directional_opacity + if(opacity) + directional_opacity = ALL_CARDINALS + if(. != directional_opacity) + reconsider_lights() + return + directional_opacity = NONE + for(var/atom/movable/opacity_source as anything in opacity_sources) + if(opacity_source.flags & ON_BORDER) + directional_opacity |= opacity_source.dir + else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking. + directional_opacity = ALL_CARDINALS + break + if(. != directional_opacity && (. == ALL_CARDINALS || directional_opacity == ALL_CARDINALS)) + reconsider_lights() //The lighting system only cares whether the tile is fully concealed from all directions or not. + + +/turf/proc/change_area(area/old_area, area/new_area) + if(SSlighting.subsystem_initialized) + if (new_area.dynamic_lighting != old_area.dynamic_lighting) + if (new_area.dynamic_lighting) + lighting_build_overlay() + else + lighting_clear_overlay() + +/turf/proc/has_dynamic_lighting() + var/area/A = loc + return (IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) /turf/proc/generate_missing_corners() + + if (!lighting_corner_NE) + lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST) + + if (!lighting_corner_SE) + lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST) + + if (!lighting_corner_SW) + lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST) + + if (!lighting_corner_NW) + lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST) + 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]) diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm deleted file mode 100644 index 2f863b73d5b..00000000000 --- a/code/modules/lighting/~lighting_undefs.dm +++ /dev/null @@ -1,7 +0,0 @@ -#undef LIGHTING_FALLOFF -#undef LIGHTING_LAMBERTIAN -#undef LIGHTING_HEIGHT - -#undef LIGHTING_ICON - -#undef LIGHTING_BASE_MATRIX diff --git a/code/modules/maps/tg/reader.dm b/code/modules/maps/tg/reader.dm index aa0bd51b899..542a0b9582c 100644 --- a/code/modules/maps/tg/reader.dm +++ b/code/modules/maps/tg/reader.dm @@ -159,7 +159,6 @@ GLOBAL_DATUM_INIT(_preloader, /dmm_suite/preloader, new) var/model_key = copytext(line, tpos, tpos + key_len) line_keys[++line_keys.len] = model_key #ifdef TESTING - else ++turfsSkipped #endif CHECK_TICK diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index e74c241ffb1..1d62a20a61a 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -4,7 +4,7 @@ name = "lantern" icon_state = "lantern" desc = "A mining lantern." - brightness_on = 6 // luminosity when on + light_range = 6 // luminosity when on light_color = "FF9933" // A slight yellow/orange color. /*****************************Pickaxe********************************/ diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index fd41dc7e137..6ef8200455e 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -125,7 +125,7 @@ turf/simulated/mineral/floor/light_corner /turf/simulated/mineral/proc/update_general() update_icon(1) - recalc_atom_opacity() + recalculate_directional_opacity() if(ticker && ticker.current_state == GAME_STATE_PLAYING) reconsider_lights() if(air_master) diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 03a878e32d1..132be558597 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -7,6 +7,7 @@ health = 100 maxHealth = 100 mob_size = 4 + blocks_emissive = EMISSIVE_BLOCK_UNIQUE inventory_panel_type = null // Disable inventory diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 07cd72fce99..a5230484ed2 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -1,5 +1,6 @@ /mob/living/carbon gender = MALE + blocks_emissive = EMISSIVE_BLOCK_UNIQUE // BLEH, this could be improved for transparent species and stuff! And blocks glowing eyes?! var/datum/species/species //Contains icon generation and language information, set during New(). var/list/stomach_contents = list() var/list/datum/disease2/disease/virus2 = list() diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index 90949f401f8..3c6451fc99a 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -2,6 +2,7 @@ real_name = "Test Dummy" status_flags = GODMODE|CANPUSH has_huds = FALSE + blocks_emissive = FALSE /mob/living/carbon/human/dummy/Initialize() . = ..() diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index b4836d168f8..143e0315eb3 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -207,7 +207,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() else DI = damage_icon_parts[cache_index] - standing_image.overlays += DI + standing_image.add_overlay(DI) overlays_standing[DAMAGE_LAYER] = standing_image apply_layer(DAMAGE_LAYER) @@ -476,10 +476,17 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() face_standing += rgb(,,,120) var/icon/ears_s = get_ears_overlay() + var/image/em_block_ears if(ears_s) face_standing.Blend(ears_s, ICON_OVERLAY) + if(ear_style?.em_block) + em_block_ears = em_block_image_generic(image(ears_s)) + + var/image/semifinal = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset) + if(em_block_ears) + semifinal.overlays += em_block_ears // Leaving this as overlays += - overlays_standing[HAIR_LAYER] = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset) + overlays_standing[HAIR_LAYER] = semifinal apply_layer(HAIR_LAYER) //return //VOREStation Edit @@ -532,6 +539,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() else eyes_icon.Blend(rgb(128,0,0), ICON_ADD) + // Convert to emissive at some point var/image/eyes_image = image(eyes_icon) eyes_image.plane = PLANE_LIGHTING_ABOVE eyes_image.appearance_flags = appearance_flags @@ -566,7 +574,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() for(var/mut in mutations) if(mut == LASER) - standing.overlays += "lasereyes_s" //TODO + standing.overlays += "lasereyes_s" // Leaving this as overlays += overlays_standing[MUTATIONS_LAYER] = standing apply_layer(MUTATIONS_LAYER) @@ -1067,7 +1075,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() for(var/datum/modifier/M in modifiers) if(M.mob_overlay_state) var/image/I = image(icon = 'icons/mob/modifier_effects.dmi', icon_state = M.mob_overlay_state) - effects.overlays += I //TODO, this compositing is annoying. + effects.overlays += I // Leaving this as overlays += overlays_standing[MODIFIER_EFFECTS_LAYER] = effects @@ -1113,7 +1121,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() for(var/obj/item/organ/external/E in organs) if(E.open) var/image/I = image(icon = 'icons/mob/surgery.dmi', icon_state = "[E.icon_name][round(E.open)]", layer = BODY_LAYER+SURGERY_LAYER) - total.overlays += I //TODO: This compositing is annoying + total.overlays += I // Leaving this as overlays += if(total.overlays.len) overlays_standing[SURGERY_LAYER] = total @@ -1127,7 +1135,9 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(synthetic && synthetic.includes_wing && !wing_style && !wings_hidden) //VOREStation Edit var/icon/wing_s = new/icon("icon" = synthetic.icon, "icon_state" = "wing") //I dunno. If synths have some custom wing? wing_s.Blend(rgb(src.r_skin, src.g_skin, src.b_skin), species.color_mult ? ICON_MULTIPLY : ICON_ADD) - return image(wing_s) + var/image/working = image(wing_s) + working.overlays += em_block_image_generic(working) // Leaving this as overlays += + return working //If you have custom wings selected if(wing_style && !(wear_suit && wear_suit.flags_inv & HIDETAIL) && !wings_hidden) //VOREStation Edit @@ -1150,7 +1160,10 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() overlay.Blend(rgb(src.r_wing3, src.g_wing3, src.b_wing3), wing_style.color_blend_mode) wing_s.Blend(overlay, ICON_OVERLAY) qdel(overlay) - return image(wing_s) + var/image/working = image(wing_s) + if(wing_style.em_block) + working.overlays += em_block_image_generic(working) // Leaving this as overlays += + return working /mob/living/carbon/human/proc/get_ears_overlay() if(ear_style && !(head && (head.flags_inv & BLOCKHEADHAIR))) @@ -1208,15 +1221,20 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() tail_s.Blend(overlay, ICON_OVERLAY) qdel(overlay) + var/image/working = image(tail_s) + if(tail_style.em_block) + working.overlays += em_block_image_generic(working) // Leaving this as overlays += + if(isTaurTail(tail_style)) var/datum/sprite_accessory/tail/taur/taurtype = tail_style + working.pixel_x = -16 if(taurtype.can_ride && !riding_datum) riding_datum = new /datum/riding/taur(src) verbs |= /mob/living/carbon/human/proc/taur_mount verbs |= /mob/living/proc/toggle_rider_reins - return image(tail_s, "pixel_x" = -16) + return working else - return image(tail_s) + return working return null // TODO - Move this to where it should go ~Leshana diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index a88a434d968..90bec77cb7d 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -238,10 +238,6 @@ set_light(distance, distance * 4, l_color = "#660066") return TRUE - else if(on_fire) - set_light(min(round(fire_stacks), 3), round(fire_stacks), l_color = "#FF9933") - return TRUE - else if(glow_toggle) set_light(glow_range, glow_intensity, glow_color) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index b6e6ffc03fd..589d9ac6a31 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -366,7 +366,7 @@ /mob/living/proc/IgniteMob() if(fire_stacks > 0 && !on_fire) on_fire = 1 - handle_light() + new/obj/effect/dummy/lighting_obj/moblight/fire(src) throw_alert("fire", /obj/screen/alert/fire) update_fire() @@ -374,7 +374,8 @@ if(on_fire) on_fire = 0 fire_stacks = 0 - handle_light() + for(var/obj/effect/dummy/lighting_obj/moblight/fire/F in src) + qdel(F) clear_alert("fire") update_fire() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 82bc2e24989..4164b13e24b 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -12,6 +12,8 @@ mob_swap_flags = ~HEAVY mob_push_flags = ~HEAVY //trundle trundle + blocks_emissive = EMISSIVE_BLOCK_UNIQUE + var/lights_on = 0 // Is our integrated light on? var/used_power_this_tick = 0 var/sight_mode = 0 diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 90f6943a8c8..a0ca4cd4922 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -3,6 +3,7 @@ layer = MOB_LAYER plane = MOB_PLANE animate_movement = 2 + blocks_emissive = EMISSIVE_BLOCK_GENERIC var/datum/mind/mind var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm index 1d557e4e519..cfd4a917296 100644 --- a/code/modules/mob/mob_planes.dm +++ b/code/modules/mob/mob_planes.dm @@ -16,6 +16,8 @@ // 'Utility' planes plane_masters[VIS_FULLBRIGHT] = new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects) plane_masters[VIS_LIGHTING] = new /obj/screen/plane_master/lighting //Lighting system (but different!) + plane_masters[VIS_O_LIGHT] = new /obj/screen/plane_master/o_light_visual //Object lighting (using masks) + plane_masters[VIS_EMISSIVE] = new /obj/screen/plane_master/emissive //Emissive overlays plane_masters[VIS_GHOSTS] = new /obj/screen/plane_master/ghosts //Ghosts! plane_masters[VIS_AI_EYE] = new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye! @@ -48,6 +50,9 @@ ..() + for(var/obj/screen/plane_master/PM as anything in plane_masters) + PM.backdrop(my_mob) + /datum/plane_holder/Destroy() my_mob = null QDEL_LIST_NULL(plane_masters) //Goodbye my children, be free @@ -106,14 +111,17 @@ for(var/SP in subplanes) alter_values(SP, values) + + + //////////////////// // The Plane Master //////////////////// /obj/screen/plane_master - screen_loc = "1,1" + screen_loc = "CENTER" plane = -100 //Dodge just in case someone instantiates one of these accidentally, don't end up on 0 with plane_master appearance_flags = PLANE_MASTER - mouse_opacity = 0 //Normally unclickable + mouse_opacity = MOUSE_OPACITY_TRANSPARENT //Normally unclickable alpha = 0 //Hidden from view var/desired_alpha = 255 //What we go to when we're enabled var/invis_toggle = FALSE @@ -122,6 +130,8 @@ /obj/screen/plane_master/New() ..(null) //Never be in anything ever. +/obj/screen/plane_master/proc/backdrop(mob/mymob) + /obj/screen/plane_master/proc/set_desired_alpha(var/new_alpha) if(new_alpha != alpha && new_alpha > 0 && new_alpha <= 255) desired_alpha = new_alpha @@ -176,6 +186,43 @@ blend_mode = BLEND_MULTIPLY alpha = 255 +/obj/screen/plane_master/lighting/backdrop(mob/mymob) + /* I'm unconvinced. + mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit) + mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit) + */ + +/*! + * This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers. + * + * Emissive overlays are pasted with an atom color that converts them to be entirely some specific color. + * Emissive blockers are pasted with an atom color that converts them to be entirely some different color. + * Emissive overlays and emissive blockers are put onto the same plane. + * The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects. + * A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is. + * This is then used to alpha mask the lighting plane. + */ + +/obj/screen/plane_master/lighting/Initialize() + . = ..() + add_filter("emissives", 1, alpha_mask_filter(render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE)) + add_filter("object_lighting", 2, alpha_mask_filter(render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE)) + +/obj/screen/plane_master/o_light_visual + plane = PLANE_O_LIGHTING_VISUAL + render_target = O_LIGHTING_VISUAL_RENDER_TARGET + blend_mode = BLEND_MULTIPLY + alpha = 255 + +/obj/screen/plane_master/emissive + plane = PLANE_EMISSIVE + render_target = EMISSIVE_RENDER_TARGET + alpha = 255 + +/obj/screen/plane_master/emissive/Initialize() + . = ..() + add_filter("em_block_masking", 1, color_matrix_filter(GLOB.em_mask_matrix)) + ///////////////// //Ghosts has a special alpha level /obj/screen/plane_master/ghosts diff --git a/code/modules/mob/mob_planes_vr.dm b/code/modules/mob/mob_planes_vr.dm index 5d41209b196..1c47b13e720 100644 --- a/code/modules/mob/mob_planes_vr.dm +++ b/code/modules/mob/mob_planes_vr.dm @@ -1,11 +1,12 @@ /datum/plane_holder/New(mob/this_guy) - ..() + my_mob = this_guy plane_masters[VIS_CH_STATUS_R] = new /obj/screen/plane_master{plane = PLANE_CH_STATUS_R} //Right-side status icon plane_masters[VIS_CH_HEALTH_VR] = new /obj/screen/plane_master{plane = PLANE_CH_HEALTH_VR} //Health bar but transparent at 100 plane_masters[VIS_CH_BACKUP] = new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status plane_masters[VIS_CH_VANTAG] = new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(my_mob) //Augmented reality + ..() ///////////////// //AR planemaster does some special image handling diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 1a13a7ed621..1e7184f9655 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -39,6 +39,9 @@ // Ckey of person allowed to use this, if defined. var/list/ckeys_allowed = null + /// Should this sprite block emissives? + var/em_block = FALSE + /* //////////////////////////// / =--------------------= / @@ -1519,6 +1522,7 @@ shaved /datum/sprite_accessory/facial_hair icon = 'icons/mob/Human_face.dmi' color_blend_mode = ICON_ADD + em_block = TRUE /datum/sprite_accessory/facial_hair/shaved name = "Shaved" diff --git a/code/modules/mob/new_player/sprite_accessories_ear.dm b/code/modules/mob/new_player/sprite_accessories_ear.dm index 24e82043e41..fbf59a0fecc 100644 --- a/code/modules/mob/new_player/sprite_accessories_ear.dm +++ b/code/modules/mob/new_player/sprite_accessories_ear.dm @@ -14,6 +14,7 @@ var/extra_overlay // Icon state of an additional overlay to blend in. var/extra_overlay2 var/desc = "You should not see this..." + em_block = TRUE species_allowed = list(SPECIES_EVENT1, SPECIES_EVENT2, SPECIES_EVENT3) diff --git a/code/modules/mob/new_player/sprite_accessories_tail.dm b/code/modules/mob/new_player/sprite_accessories_tail.dm index dec95139744..f2d6fce6360 100644 --- a/code/modules/mob/new_player/sprite_accessories_tail.dm +++ b/code/modules/mob/new_player/sprite_accessories_tail.dm @@ -11,6 +11,7 @@ do_colouration = 0 //Set to 1 to enable coloration using the tail color. color_blend_mode = ICON_ADD // Only appliciable if do_coloration = 1 + em_block = TRUE var/extra_overlay // Icon state of an additional overlay to blend in. var/extra_overlay2 //Tertiary. var/show_species_tail = 0 // If false, do not render species' tail. diff --git a/code/modules/mob/new_player/sprite_accessories_taur.dm b/code/modules/mob/new_player/sprite_accessories_taur.dm index dad54ed188c..59f8f8f4d77 100644 --- a/code/modules/mob/new_player/sprite_accessories_taur.dm +++ b/code/modules/mob/new_player/sprite_accessories_taur.dm @@ -123,6 +123,7 @@ icon = 'icons/mob/human_races/sprite_accessories/taurs.dmi' do_colouration = 1 // Yes color, using tail color color_blend_mode = ICON_MULTIPLY // The sprites for taurs are designed for ICON_MULTIPLY + em_block = TRUE var/icon/suit_sprites = null //File for suit sprites, if any. var/icon/under_sprites = null diff --git a/code/modules/mob/new_player/sprite_accessories_wing.dm b/code/modules/mob/new_player/sprite_accessories_wing.dm index 486e81f4b10..85bdedd04ae 100644 --- a/code/modules/mob/new_player/sprite_accessories_wing.dm +++ b/code/modules/mob/new_player/sprite_accessories_wing.dm @@ -11,6 +11,7 @@ do_colouration = 0 //Set to 1 to enable coloration using the tail color. color_blend_mode = ICON_ADD // Only appliciable if do_coloration = 1 + em_block = TRUE var/extra_overlay // Icon state of an additional overlay to blend in. var/extra_overlay2 //Tertiary. var/clothing_can_hide = 1 // If true, clothing with HIDETAIL hides it. If the clothing is bulky enough to hide a tail, it should also hide wings. diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index d4b311e8e25..8639aadb63b 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -72,22 +72,34 @@ /obj/item/modular_computer/update_icon() icon_state = icon_state_unpowered - overlays.Cut() + cut_overlays() + + . = list() + if(bsod) - overlays += image(icon = overlay_icon, icon_state = "bsod") - return + . += mutable_appearance(overlay_icon, "bsod") + . += emissive_appearance(overlay_icon, "bsod") + return add_overlay(.) if(!enabled) if(icon_state_screensaver) - overlays += image(icon = overlay_icon, icon_state = icon_state_screensaver) + . += mutable_appearance(overlay_icon, icon_state_screensaver) + . += emissive_appearance(overlay_icon, icon_state_screensaver) set_light(0) - return + return add_overlay(.) + set_light(light_strength) + if(active_program) - overlays += image(icon = overlay_icon, icon_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu) + var/program_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu + . += mutable_appearance(overlay_icon, program_state) + . += emissive_appearance(overlay_icon, program_state) if(active_program.program_key_state) - overlays += image(icon = overlay_icon, icon_state = active_program.program_key_state) + . += mutable_appearance(overlay_icon, active_program.program_key_state) else - overlays += image(icon = overlay_icon, icon_state = icon_state_menu) + . += mutable_appearance(overlay_icon, icon_state_menu) + . += emissive_appearance(overlay_icon, icon_state_menu) + + return add_overlay(.) /obj/item/modular_computer/proc/turn_on(var/mob/user) if(bsod) diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm index 373d2ad3e1f..59c45f993a2 100644 --- a/code/modules/modular_computers/computers/modular_computer/variables.dm +++ b/code/modules/modular_computers/computers/modular_computer/variables.dm @@ -24,6 +24,7 @@ // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. icon = null // This thing isn't meant to be used on it's own. Subtypes should supply their own icon. + blocks_emissive = FALSE var/overlay_icon = null // Icon file used for overlays icon_state = null center_of_mass = null // No pixelshifting by placing on tables, etc. diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm index b069e2fddaf..293a64c9fbd 100644 --- a/code/modules/planet/planet.dm +++ b/code/modules/planet/planet.dm @@ -10,10 +10,10 @@ var/sun_last_process = null // world.time var/datum/weather_holder/weather_holder + var/datum/sun_holder/sun_holder var/sun_position = 0 // 0 means midnight, 1 means noon. - var/list/sun = list("range","brightness","color","lum_r","lum_g","lum_b") - var/list/datum/lighting_corner/sunlit_corners = list() + var/list/sun = list("range","brightness","color") var/list/expected_z_levels = list() var/turf/unsimulated/wall/planetary/planetary_wall_type = /turf/unsimulated/wall/planetary @@ -31,6 +31,7 @@ /datum/planet/New() ..() weather_holder = new(src) + sun_holder = new(src) current_time = current_time.make_random_time() if(moon_name) moon_phase = pick(list( diff --git a/code/modules/planet/sun.dm b/code/modules/planet/sun.dm new file mode 100644 index 00000000000..55f739d2178 --- /dev/null +++ b/code/modules/planet/sun.dm @@ -0,0 +1,53 @@ +/datum/sun_holder + var/atom/movable/sun_visuals/sun = new + var/datum/planet/our_planet + +/datum/sun_holder/New(var/source) + our_planet = source + +/datum/sun_holder/proc/update_color(new_color) + sun.color = new_color + +/datum/sun_holder/proc/update_brightness(new_brightness) + sun.alpha = round(CLAMP01(new_brightness)*255,1) + +/datum/sun_holder/proc/apply_to_turf(turf/T) + if(sun in T.vis_contents) + warning("Was asked to add fake sun to [T.x], [T.y], [T.z] despite already having us in it's vis contents") + return + T.vis_contents += sun + +/datum/sun_holder/proc/remove_from_turf(turf/T) + if(!(sun in T.vis_contents)) + warning("Was asked to remove fake sun from [T.x], [T.y], [T.z] despite it not having us in it's vis contents") + return + T.vis_contents -= sun + +/datum/sun_holder/proc/rainbow() + var/end = world.time + 30 SECONDS + + var/col_index = 1 + + var/list/colors = list("#ff5d5d","#ffd17b","#ffff5e","#7eff7e","#6868ff","#b753ff","#d08fff","#ffffff") + var/original_brightness = sun.alpha/255 + var/original_color = sun.color + + update_brightness(0.8) + + while(world.time < end) + update_color(colors[col_index]) + if(++col_index > colors.len) + col_index = 1 + sleep(3) + + update_brightness(original_brightness) + update_color(original_color) + +// Holds a full white icon that can be mutated to make sun on the O_LIGHTING plane +/atom/movable/sun_visuals + icon = 'icons/mob/screen_gen.dmi' + icon_state = "flash" + plane = PLANE_O_LIGHTING_VISUAL + mouse_opacity = 0 + alpha = 0 + color = "#FFFFFF" diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm index c5202ab067c..48953a97f19 100644 --- a/code/modules/planet/weather.dm +++ b/code/modules/planet/weather.dm @@ -23,6 +23,20 @@ visuals = new() special_visuals = new() +/datum/weather_holder/proc/apply_to_turf(turf/T) + if(visuals in T.vis_contents) + warning("Was asked to add weather to [T.x], [T.y], [T.z] despite already having us in it's vis contents") + return + T.vis_contents += visuals + T.vis_contents += special_visuals + +/datum/weather_holder/proc/remove_from_turf(turf/T) + if(!(visuals in T.vis_contents)) + warning("Was asked to remove weather from [T.x], [T.y], [T.z] despite it not having us in it's vis contents") + return + T.vis_contents -= visuals + T.vis_contents -= special_visuals + /datum/weather_holder/proc/change_weather(var/new_weather) var/old_light_modifier = null var/datum/weather/old_weather = null diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index c576b96635f..4f7ac688d73 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -85,6 +85,7 @@ GLOBAL_LIST_EMPTY(apcs) use_power = USE_POWER_OFF clicksound = "switch" req_access = list(access_engine_equip) + blocks_emissive = FALSE var/area/area var/areastring = null var/obj/item/weapon/cell/cell @@ -128,10 +129,6 @@ GLOBAL_LIST_EMPTY(apcs) var/failure_timer = 0 var/force_update = 0 var/updating_icon = 0 - var/global/list/status_overlays_lock - var/global/list/status_overlays_charging - var/global/list/status_overlays_equipment - var/global/list/status_overlays_lighting var/global/list/status_overlays_environ var/alarms_hidden = FALSE //If power alarms from this APC are visible on consoles @@ -306,42 +303,6 @@ GLOBAL_LIST_EMPTY(apcs) // update the APC icon to show the three base states // also add overlays for indicator lights /obj/machinery/power/apc/update_icon() - if(!status_overlays) - status_overlays = 1 - status_overlays_lock = new - status_overlays_charging = new - status_overlays_equipment = new - status_overlays_lighting = new - status_overlays_environ = new - - status_overlays_lock.len = 2 - status_overlays_charging.len = 3 - status_overlays_equipment.len = 4 - status_overlays_lighting.len = 4 - status_overlays_environ.len = 4 - - status_overlays_lock[1] = image(icon, "apcox-0") // 0=blue 1=red - status_overlays_lock[2] = image(icon, "apcox-1") - - status_overlays_charging[1] = image(icon, "apco3-0") - status_overlays_charging[2] = image(icon, "apco3-1") - status_overlays_charging[3] = image(icon, "apco3-2") - - status_overlays_equipment[1] = image(icon, "apco0-0") - status_overlays_equipment[2] = image(icon, "apco0-1") - status_overlays_equipment[3] = image(icon, "apco0-2") - status_overlays_equipment[4] = image(icon, "apco0-3") - - status_overlays_lighting[1] = image(icon, "apco1-0") - status_overlays_lighting[2] = image(icon, "apco1-1") - status_overlays_lighting[3] = image(icon, "apco1-2") - status_overlays_lighting[4] = image(icon, "apco1-3") - - status_overlays_environ[1] = image(icon, "apco2-0") - status_overlays_environ[2] = image(icon, "apco2-1") - status_overlays_environ[3] = image(icon, "apco2-2") - status_overlays_environ[4] = image(icon, "apco2-3") - var/update = check_updates() //returns 0 if no need to update icons. // 1 if we need to update the icon_state // 2 if we need to update the overlays @@ -368,20 +329,25 @@ GLOBAL_LIST_EMPTY(apcs) icon_state = "apcemag" if(!(update_state & UPDATE_ALLGOOD)) - if(overlays.len) - overlays = 0 - return + cut_overlays() + return if(update & 2) - if(overlays.len) - overlays.len = 0 + cut_overlays() if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) - overlays += status_overlays_lock[locked+1] - overlays += status_overlays_charging[charging+1] + var/list/new_overlays = list() + new_overlays += mutable_appearance(icon, "apcox-[locked]") + new_overlays += emissive_appearance(icon, "apcox-[locked]") + new_overlays += mutable_appearance(icon, "apco3-[charging]") + new_overlays += emissive_appearance(icon, "apco3-[charging]") if(operating) - overlays += status_overlays_equipment[equipment+1] - overlays += status_overlays_lighting[lighting+1] - overlays += status_overlays_environ[environ+1] + new_overlays += mutable_appearance(icon, "apco0-[equipment]") + new_overlays += emissive_appearance(icon, "apco0-[equipment]") + new_overlays += mutable_appearance(icon, "apco1-[lighting]") + new_overlays += emissive_appearance(icon, "apco1-[lighting]") + new_overlays += mutable_appearance(icon, "apco2-[environ]") + new_overlays += emissive_appearance(icon, "apco2-[environ]") + add_overlay(new_overlays) if(update & 3) if(update_state & UPDATE_BLUESCREEN) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 67cd3bb51ab..f7350a3daa7 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -283,7 +283,7 @@ var/global/list/light_type_cache = list() plane = OBJ_PLANE layer = OBJ_LAYER desc = "A floor lamp." - light_type = /obj/item/weapon/light/bulb + light_type = /obj/item/weapon/light/bulb/large construct_type = /obj/machinery/light_construct/flamp shows_alerts = FALSE //VOREStation Edit var/lamp_shade = 1 @@ -885,20 +885,34 @@ var/global/list/light_type_cache = list() force = 2 throwforce = 5 w_class = ITEMSIZE_TINY - var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN - var/base_state - var/switchcount = 0 // number of times switched matter = list(DEFAULT_WALL_MATERIAL = 60) - var/rigged = 0 // true if rigged to explode + + ///LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN + var/status = 0 + ///Base icon_state name to append suffixes for status + var/base_state + ///Number of times switched on/off + var/switchcount = 0 + ///Is this light set to explode + var/rigged = 0 + ///The chance (prob()) that this light will be broken at roundstart var/broken_chance = 2 - var/brightness_range = 2 //how much light it gives off + ///The raidus in turfs this light will reach. It will be at it's most dim this many turfs away. + /// This is also used in power draw calculation for machinery/lights. + var/brightness_range = 8 + ///The light will fall off over more/less range based on this. The formula is complicated. var/brightness_power = 1 + ///The color of the light emitted. var/brightness_color = LIGHT_COLOR_INCANDESCENT_TUBE + ///Replaces brightness_range during nightshifts. var/nightshift_range = 8 - var/nightshift_power = 1 + ///Replaces brightness_power during nightshifts. + var/nightshift_power = 0.45 + ///Replaces brightness_color during nightshifts. var/nightshift_color = LIGHT_COLOR_NIGHTSHIFT + drop_sound = 'sound/items/drop/glass.ogg' pickup_sound = 'sound/items/pickup/glass.ogg' @@ -909,14 +923,14 @@ var/global/list/light_type_cache = list() base_state = "ltube" item_state = "c_tube" matter = list("glass" = 100) - brightness_range = 10 // luminosity when on, also used in power calculation //VOREStation Edit - brightness_power = 6 + brightness_range = 7 + brightness_power = 2 /obj/item/weapon/light/tube/large w_class = ITEMSIZE_SMALL name = "large light tube" brightness_range = 15 - brightness_power = 9 + brightness_power = 4 nightshift_range = 10 nightshift_power = 1.5 @@ -929,12 +943,21 @@ var/global/list/light_type_cache = list() item_state = "contvapour" matter = list("glass" = 100) brightness_range = 5 - brightness_power = 4 + brightness_power = 1 brightness_color = LIGHT_COLOR_INCANDESCENT_BULB nightshift_range = 3 nightshift_power = 0.5 +// For 'floor lamps' in outdoor use and such +/obj/item/weapon/light/bulb/large + name = "large light bulb" + brightness_range = 7 + brightness_power = 1.5 + + nightshift_range = 4 + nightshift_power = 0.75 + /obj/item/weapon/light/throw_impact(atom/hit_atom) ..() shatter() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 6cd885f0c17..4a1be60a5eb 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -11,6 +11,9 @@ pass_flags = PASSTABLE mouse_opacity = 0 hitsound = 'sound/weapons/pierce.ogg' + + blocks_emissive = EMISSIVE_BLOCK_GENERIC + var/hitsound_wall = null // Played when something hits a wall, or anything else that isn't a mob. ////TG PROJECTILE SYTSEM diff --git a/icons/effects/light_overlays/light_128.dmi b/icons/effects/light_overlays/light_128.dmi new file mode 100644 index 0000000000000000000000000000000000000000..22dc0b0108702f5dbc74a2d1170026743fa7dd9d GIT binary patch literal 7040 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 literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_224.dmi b/icons/effects/light_overlays/light_224.dmi new file mode 100644 index 0000000000000000000000000000000000000000..9fab531d1a691cf1cc53c3f54aec69c2e4bfba09 GIT binary patch literal 17004 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 P00000NkvXXu0mjf9iK$$ literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_256.dmi b/icons/effects/light_overlays/light_256.dmi new file mode 100644 index 0000000000000000000000000000000000000000..701562efcd8f85fea23b0bf9475c33698c57c338 GIT binary patch literal 21365 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 literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_32.dmi b/icons/effects/light_overlays/light_32.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5269b1fba36d8ad0dcde7862da177a51a4632e26 GIT binary patch literal 1140 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 TI$=2z10LMB_#1QAE$RON=Yb3V literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_352.dmi b/icons/effects/light_overlays/light_352.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f895792da42d63143e15641a198443e290f3671c GIT binary patch literal 35566 zcmXt9cRX9&|Bn&WR=YM&O9fG_2eGTIK5CXE_Ex1zjM#hEZq;b*sv04bB4Y1ZR0XY_ zh&>XjHb37#et+E8ecf~JIp=fkx##_Pf5v%ZsISdLe~TUf05JXc^wDzwfWr2F7ah%Y zNsL{w?)A+*(8Sc|k(0NBmkYwj#lsx{@XwX*SEdh_Wd(LXf)e8X;v03vZoGTAC(QFb zQs^mHYg>%(eWgHU%#9a5K4;m-kfI-4x69+WZ;Zdhel#Jq08g?Uxmc3j)})_4ab36VnyK7rn6ORG;9HJB^fv5hqN<#z!p_=b3q;h5I@kPUV|_rG;1i22q{ty}y3- zxz6&x$2v=Dby8W4l=z>*Cp7zucRc{@L>rgjZ;KS2d+$||5T=hF!dC*dt?lvTqoJje znP0ZSkH-by-sLceS>x*qOS$fzdl13hWtJA)mlfPLEEz)c(ja1;udluFx{7wVtD#!e zHmL6zX0Il#;Kn)_xPM($a9tHQ$Xv?5Fbots2cy8iyEQKQ5a2gSjw2v!;)QOC&ZkGQD89O=j6Gd9E0vbHra7QO}F zjx+`C>4X~0ZvLeq9}V+$fF+f~FfWP;W~au9#~+$y@-xN+QAo}N?foD~(xULC+O?Fu zD*%7^gr0Sho)o^E5A==f>Y^`apIB45Dp!PDA#PxE}j$FqJ=OU0<3= zpZoJ1{u8}Y2T$3B7?OMds#Lik@RH=!!P_d&t0BIgwQD&HGSfSoUFXp~dWG%w7ha*x z5x$&5&cSc-@wc(|F3SG;(tH0|LqE#w>MsbZ$#?+N|6>k@`Xk47@)bGv09Mj8R+lpK zL-p(mC-C1PV=~l?v#*xzk1L3l#PXGL;ZUvP>=ugP+FZH?C<*Gx9bfRiof5{}ZkU^n zn`cMWIxlWNGN91w{8krjm2Z3$i%J|S9$sU@dt9%+!MiB+l>3K+SVdo^!b2?mPqf+w zpLKxCRBLojcp$DeZ&Md3Ub7|T0KXFl*MOh2QO7T`T4!B1OrvV=R1V=K0#+;aO4=zM zoN#CTmdR0wAoNbgjp_!9Is zRxaY}P#xvgiqq22GsWA^4^P&`{;m)|KI;x--bKkSoYn3z;kmEH^c#w}f-CQPfgU#V z-GP-*p=v*g!*=4z2oH81q-=eYOwWR%z{`@a6zo^Up0N7u#!K2bSye~+*QO~3G~Z?( z;_FECB7wuO+%I!SDZc(B*3kdfr#*xWAFVU=yy5$lXp^@dBxRm8Mz4!Iab{PK*c7*_ zru;i_k+mONb3NI(efy;c6MqvL$~oGHexW&h#M&mOo- zM#!fs; zYWi2tcASKRR2%7Zg{$`SPSKz|)nztvtnBq}Nap`@=$rPz6b0qk(>FY^d|EJU_1y;7 zDp`Ouu?BfU&+`Z8n`k9NqF1Qf^6GzYR7T=DElTz_Pko=MXf6Q$^%~#I3wD}T-Sx|S z*+XEEo%#=sGrUc&F;Ycm(fsbFW{q$K!z@kesn4zeGtyq z`1_iv;Ccu5Z^*GV2t*60>+Div9-*Rw%tVN^_bEA%r`hF`fJ*6N1w>T2q4kQZi| z(W7`DbbPr1W}=FV@knlu@zpWYa>O|fpms9rhJtwz7ppq@uz6=ivnPce!>7Ayuu5xa zYyv^{HanmiVCQ;KD;$oxXlJeo$nB`pNfjD-Mx2ev<}RpU`fJ|pL3bqHiKoq!qrNDSuxrX;eF%XmB&@=FV6G*6)J0@+;+ z6)@x5nLCu1EzDYR1ogOLA|FTf66R*tv(=B{=DlC zr$GC{Opr*=;8YR(9kP`_=h~e>U^sKn?vK{lHytO6i(jcKYClEcq1YkOU5(1$JrOg~ zru=(otC{xw(uc>@0Fow(d#toSJ_OuP;&U^8rZ{YGRsSr~W)&EXf_Md38jPZ-TkBRqAVY)ieA91%x6AbL)8mC_50>F{oZ_ZKE#O3pL^^uEE!|b{tsH$wsnZTRk%srDYnFv}ZCupr&GwmJO zKG}>uvu_1ynOl{BP3v{CfgNO63E#Gm;bA6l5-cwzdZ|Kp^#h=GqfNWgdPK`C{dj+9 z2VofSX_qB__R+1_Z?l=Jn?;)=CtfEqYCQo*VV*Ln9I+c5zv(%cxmr*i8_NDqRNA(U zxg=si3Nf`9f%y50d!M0-iw00Q@-miWcxehKpj&(+&%fLl+SGp_#4#3t@xTz*w4%%N zSm^h0_(G{A*ElMRo^&DKHH3^oN$Pm|yTej<+S0Y)&$~Zn&GG_#umumbBX|h7O!*{K zr8_!m0?CEJayKHNXGKQLP5)eS&|SR+ERbuzM|7HbfM6b*pMAJq5ff|`v<{obl@=Et zuiIJSrtZTHkOl5!uTWcL>&?vNjCy&``z9`V${IU6Rh1UbA(9M@I&q$i+fY`N3JO~m z#6Slpwu|WQ_fs4{UP4vEL(ky_vM%bvXiAw)iSSU4jk)@Y>Zq4%`kLjxp&Ls`c`{Fz zK7;{1u`CNzb8_**8WcsHDAxF)scC8>UqZRj>9ymy%Z(e+O5bgmmeuJy#5?>>@dHhq zb23zya$1KIdcB}6?&0CuaqKF@PR&w*1{`~E;dO!8b*ISrhDv}>^DBJl;c2|N=lhSu zmRZP;&K;HbaaQ65cGu$dXe4w>b}`QUA4}`e&D8NLC%9R=2VMI4JwT{jFbE|(mUji! zeE$>Gf2jgD-0PS%>tXcagqi)3N!dd|Qdd)bc^>X1d_xalqptGGFVi)`cZbz zn0=uy+;qzEQmA4QoX=7n^DWJqMKR_NL73m( zx%ehCHuR|%`!%C7bSAFTV!q(FLZ$8KTDtg+_qZ)OCdU+l1AX&NSyJ9iij8jH339NR^1C@N9>TmNdeMGU^Zlm31 zwfxol2#X$$xj6>KhHSIc)C@517GY_l(skN8kFzo*Of@>p0w5F(wkS#0c0PKpW7bSR zDuRcE!)%E@qfTsvDB<1Bk~uM*EF{KCnL#nZ8(D?V1&*XS&JR5_P95eg{Y&u5je74b z@@P&AO7WZ+VVL4?$^U*Uf-slDMC$_dYhivHI~%-k$ZnxwM zL)X1Tc{{za4<-^WSeHkqQImjs} zKnT)g>9K^Ue_rp<+BPjL5g2yBG%wfE{O}~NX_vw-y;oXdL?AVxF81E`!)4d~y2Hi` z@0RGWlP^o$X_*JlcQR`(!d29SzdN7Xgo#9}<9|SUztNpC^t?udvblI%y+35%On6<> zd2h*lp0HDZ4UUv)P`38YWjK4i(pVeL($#qIxWb>=IQ3-69J=v~KF_p;(@X68@Wi}rbc^@n_bhyN&;w)`&3fGjhpQnVm99x>DOAM7JoG6A>QhuzkQE|mws5Gww?Ndfw!A9XV#SgwTx+P;XI!O9KRtsp=45XW0#FpPeCZth^(Sq zVoh&l2cM@$5jN`;GkRO0@65XpwqvO2Pf09%OwIodaG?^NK~jeqxI}HI z2zyMOU)67j;4{jSHCL#aXKwV3j_p;QD+8l3!>uog7;x&r_UBrE zWrnhkBg`#~SsXyeqgiZAdbrRP6l*Zi3#nnyi~(gkHGZr!UEpSmlA8&+KK`m%2~AUOcqnlc-jqj6<> zj)1}txXV1;mK0IP|EAubUmuw~cmBwoQ!cMRS*i(^8Uu<5?fj^UNL?x~n34+pL5ZyP zNuGKw({f{wp{LZ1JPdq`91S|xbotSn_L?;PoqEePR7LC`YrBw>0OFA7X`(!2fs?` zbpP-lPA2K zk0$FQD-%*Nw8fFUeInTz`otH5wo}rjxE@fhD*&NF}@=E1iTT`v}1J2XjqT=Mt@rq-VGB~Jd!8-HqW z!;Q1dc_oXBY}$fiYeUl>2fnyBdw|M5ZTWyZ>}gi4#sCRZ#Tf`Is+itENH!{KIZgv+ zF)1ssnut}uYaL?2JZ!vNA)R4hUY|#`BSgELb&ZJSOQ=7&L?T|C1O+d>Z`SBMDvpQ4 zKz*LAlfz0=P*@d}N?hEJwIG%W&(|Xe7=ts=TAv^YHS&M%#ZQkFCdCtxfYm^8U75mC z{4rV3F6X33nQ|+b6S97P0ng^nSMu!XCkv4+l2*@}!nC16e}{Npm|>ug5+ctqF6PXh zy+0|@-wl3>a|FCAdHhFd<0NA@0B4^3=>BjHW<3mmtMh77UFy1u90nos==tpZu zQ%n8FuPyD&m%Hab5;V1uzD+>)e)Z&urkz_1%PW?CqXz&TfBbBu>7Vy}cu60e*uUx(4uQT}HH(=SWd#UEY+uU^ zI4N*js}E7>@#TW|RBZyu=4m6|rXbaS(uMM6rblu87GNX38Qi5T4hT^OQSb z?S`P|)s)~*CE?GUu`mI(P0+9(JDFQ2hwQc^BCIZKDGhLW^TPTi#S8vMUh~wKH3ZpCF=Sv^OFq@yU=@|&-(pWoO)$RbxL7|;>Akj)_x~|rPw3`VJ1z_3 zB-2^9JjwP_!3wAm1f`gJW@5K1FwfOAH%=6|WD7Wu`E4#G-Q*j+*T^pDKl_35bsDp^ zgT+0c1M^PB?#M3Qfo8x3FM- zqiFu#bbYe7s?W}dtkagFgmtGM$KS%IzMg)161~gvM`TU@@&z^3feY)UE9lq) z&~hxMETLj&_Qh5sjXK)XABdrEV>BLRNOc>u=T%?&$W41rQd`kmcNY~{2&z{sa@zWR zS3~{LM^?x#&z)dCG(I`5R8(DvlKT9Njq5#JBOB|x z92{EmYRz})K$3AeHuH5)D|DphyJG&_D0fl-B0z#pDq1deFS^*3W!u8XxJ>S=Os-Ae z{pcTZdMBR|f5g1cM54duUjy|wi}zx?v!T4THZH(0rEmk%8H@yF?eo5rdz3FWDOcd$ z7)3Qp+gm5oCzfp-*NHywX5WJ2pb^u(J)64Dln>IAl2-ndIk#<5_}1zXhv>*Mlp zk?#hK+o1yvKszU39r5BFIv)Nt9CYmKGFfP6s(36HFRRFrhgWTD}PFnROn@;JkX z>fpwJ*doEHuwpq`@Elv`yDLO467#6%s;{+vD7;UcdRMv9B6AQtH6tI{Q7L7!P|}s= z%gU^CP=$_r4+fIPkA@*C{{`Ii=8sa+jI%4N?oyLTSxzi`J|%MvZ6_bAUc@#H=PVBu z`X;{7DdxHxDq{DfH4lsT)Xnpfx}mu8%+C ze#y5^V7@`kwcAXrvghlKi654B{4jQvXk*wH)O8X;rtiADT`?egUQ1`uza0cWB1oAb ztu>EkE0@4jr18VTJ1^1SAUg9(Vv!NQ#*EAn-+ z1`JL2KKYOJ5GPquCZ0p#tIX$O+mD|bph~Z%I=PiOknA;f`-Ybmz6>VrG){*Vn4vvX zr9W_4c)rlz`4C2$U+?y;j9LyJbuskEOBl(-Nsj7G4l#9xS~jeR3SNA8*;xw`D~i{6 z5$;}O#W=%!4orF<4T`)HFL_pTCl~w>{7_4A>%HB28%EQb!fxm>ThUo`b%spiD?LU!V%C zTGQN6U>ggE3c11c+420TGE&tz>Wb))n&AAdDe&h0C^gXT=-q!O33Ut8{*^+4W(Arf zT*BrJH@f13cx(uQDd#)#En(3zU%D?fZN;P2qeB}W>zEJDz)XD&vjZs&kMcJVKP)29 zNkLyY&wT(wKB^K+_SfhjEl0})p@Ri{k|Dw1(FvlqyN`%%OOQxurPiNk z4mq+Ic5D-%#>QVv^*n?&R^il>Z9l++@x{4szD13pS0y>rK1;iSsTsWACMN)PUwi>< zk7Tfy`ymNJ)wPk%_zg6iM94-I z(aX0u`qvom1)FGhh~_FJpfs$_zUO*q%+SVw5|3$n?yf`V;^>USi48ssj=~qs&^&Y|&oESD1zD7W(yHHb~gvV}U2jV~%K9F#Wkb zlk_U1mcU$o>`v6{v_M9SKTY=?Ge8fMx!tB)SQwpKONad|IvA(Q>wVZxbHz&u+K2{~ zd(vIZ!#%PMa-6|t1P6H}Z$LS8<*dGs(mDpmk<5(7& zkLuzXV$>k2nMQ!8ac1*bq6W^7z4J#mi3hC9n*E$4eL&Ku36qHp&tPXJ5Z!@N_t;77 zHNROMB8J-q_o%R9XY$WYZR#D`e6$3dTID#Dn5*oq`PG)<)eYW!3hp)IiadR?%=jYo zmaPDAIsQzIk^RaCbc~X=mEWj1c%!CuC#JJAtuvUXM$%@j&WWKevP|dT>hdo5kaOT9 zkZPXps+pt0GQ~J;)%Q8;YA<*RB9TPEIxtq_2#(pWI7@{sV~U`|@E7&oGvia#3Dpo@{Db7*5UJp2x!hMWeSJiaF4i45v4!alz^JC}z;`O`eG7+~%=|D>mx zE$znDA~fajEW0XnYRtFeflBGGNasaa!6+Ypev|Rn5y2*H6O_Am1X$8oCX6#PY6oZv z()Rv87vQ~(4Ce8a%H%}z;OSmlwL<(CSO*0%(LcYR@bOmgRS6o){WBAG%Ew{zRU{8v=i z8KBHfokakQ6hw=yz74nKrdjPj{4JqpXc>A8jx|p+RC66RTkG5K8TVQhS{x*gzUC*t zynWwNY&RmsfZN{yI&WOcrwrP`NZB}1_!+Jqvm|t<3?hIGx(5_4tUUA@+h>mzCCly> zUh9*mHl1){)h4D_EEgWWoq}0Ms5CxnB*iGM$uhGf7*9)aV|}?~)(DmMPJ^*@TCJcM z@?Y5u8DafS(uikKF?7xfjsdn%I_0154hVOUsJXPbXqi?!r~aW#E$UITJEYV%8>O4( zJocUP09p~xs-$db7wG#$e!o8x)u^@zj>6|5__e%?YZ#raGNuFs!r7nlpu=+k%Z-OE z20TY|*3s@gsu(31VcmLz;1;IjDjRCYg}BIjTA3nP%|L5X zB>Et@*t;_87W-WrcVGd{Qr?tDNgUPF)-;03FVXo&SQY2vyT?!bXUel&KX8Y6fA8eB zs~W-!urn^}t)l|#@+t2|nQz#tG?Y&m$-*u=?9yLxXMU>W&-WL><5pG>^%qHpJQE+> z#ROu(l@k8w^%pP1%p%5oSezc?JldWl&+vZgax(-}nQCI&ctpvUl* z=BLQc~FU>G1k!V;yLJ;1F&~on&?U?m*$!k_%A)-UoQZXCN%B{JL(?Wn^ES+NRYbL1q=rHNKMm^BEwkr-vCN{>2Q-&>58) zGsd0Ga0)@YI4YVSK3&gCl{E%Wkx2I>KGKs&L1~O==O;mV%&q80%L_6+{?c~+Bb>@K z;TS+yLp}89{cOZ+LOWAjN6*RiKX@+J%(zV zxJPZT3rwd~(xdpM`M+Gx*<9CMMi>5o7 z8<)#?=Q)cWc!Ji^qZGnbOpA;U%Mh&~dH7vlka6Ojw&-r9lwI1S_MX;Zkw>>UVRDtyHVPtT{| zwUw(4xx!!nAQCpmj@rzHvZfB>f|6E4eRj}uy6A$uXAhJ0_!)+t8g5vsZA=Xy4uSv3 z@A|v%pX2Y9^nLi~9Gv%VZ6H}#p!a^i+})r#R%eS2V~J)yV?bNsENw=(Zg#|w1{Ci4OAA*%L^*b`fGeur~n(p8LN zV^9P^)&QCBRGhPX^GGIPRFs)5lzmy}C=H=4kb(QJyO1cGKS@{4LCwC_{Pyw*Rz|<` zo=9mZ1EuD4#5?Jn8wiw226AOrbEEum>1kO5GBNMj@M*=^r+AAC47Rxi8j_(esQ$=& zw-lW`e@qxlE$dH#)OIfQ{h_gwykgoP{_71x8lD0KMyg%GY85r%EvQ$kQ4`({26@lS z>LdNkIudPK44I0%j7=O+K9c%Oj1^VNODNLb<|qH?X?+|DRzqZweMupaPXRt+0ZiDMhJR- zy=8k3$PcGofNQBoWx*Jg^8_!AQy|`JVn%C?6oo;ebD&|VF zpfI?G$yhr==%?)&Nzun8AXWB@!&BOgd>Qta3xk?l+yt;_N|lUrfSh7Y3(KU6U}O z75V-({A+?8m{DLaxYbnQk^iA%KXSN13m)fMP*_ul0px}IGZMZ9RCax$GnSjM@YKq6 zqA<`v-(nf_v<0c|$}$=YKbd!pwB^wnW0Iro-x8>Jrjw;U?cTF>hh=1KD zw9Sqy&`Cv_+6?*w5?d6jg5JQ0y_v)((?gKWYuB2Jd1$srA0c(rQ9b0jAaCCR#nJu? z|J4(UX@Bs#S_hfWXLKqwc3J$8oHb4=5nYSml1`QPc}8Mr9}(ZfCAW{#_toMOAuS%_ zDuS6S%ApKh6j^XJ8j4b*!ljICxPv}Qih;VE$~T|Dz!odJM(n7lG(@U->XAYa*^wSV z!hbg92R!-O>}{0x;@NQ@CC>k~Y!!enTc}+A)yS_)HOt7c)!_L$OVR#0y!}Q|_(%L@ z)y#?W$=2Ymg4p<4;u1DZKLywFL~#*+*}qUXul6){@-Kdn_moAt<97dv8Ei8hc}0)E9gp`gIj3qnoLjGI2I{buVy08UP@{A_2uycNsjOCJ+cy1Bpam`y&0#Y_aoZ3F>2FrUA67e z_P%Bv1<6KzI6!gHIcMmq4MiG;=K+36r=UYnzKaa=bs8=3Tp?NUTl&X^id;0ns{u&< zeI8aX3zgGIF~N{Fw!o~%t5JdHQ5)NzY=w4jKR|FA^3I(M&a)1&F6G@Epri&z2^?~m ziajuGYRy1gl^@K13YTzN{%#E zxmC3}AnRMeDdAU>BC7VNWx@{|wAteYQ~I!KkG8tS-_P?U-&(PKGbDl!uCj|Fm+T{C zDE`$qu~HZ+mQ$=y(^&q?R1{~Bp9|Y?xDXQ@HgOnCt`2kR8WH0{$PXBa$9Rk~>5LW} zdM?>7;G$va(LcS^6bB}S$0!cP1Zk}mBIf@2sL^N+;0Iu9T8>!lTni!o%ks~-)!$ff zW^r3!cw(1_Zmz1}5_$cuw(SRsYX?XwRdXZaXF4Iv8sDkDnUdi%HG=+N#V3k_TS)<> zj=?=4O{QZl3L^|Z&;PlQ-o3i%QXEXOCNDG@G+DX7r`_C7Y#IHXx2`hqp;`Et2GlAk z9SMMIrx>F?Q)bd@cepRZPm=M!Dtb@h&0zkQUj^w4IpfW=V?Zxytx&!`(-i%zcJw2g zxlSH)3)&h$>)5ghZ{d8*ZPtgD+`h_~#l$6PSGFT%(F(A4jk4xW{8CKB&x(1bIW9%; zd!d|RLx<$O<(sLC!QPji`ss<>M?ZR=u3PHRFFfnIgXOT(F{tE_cfnCRlO!)#uDJlK zER^?`nd?D7=CW|?nr1+`!p~7x^xRG6kIZdDADN4r>22Dk>Bkw5Bt1Ad75-b>H@(n3 zux({suE<0Eg%aLXL)*REv7UG?8~IgIs6RiP1`vjrLj`#r3=;W7SsbZTgIZYfXC?H* z*vT^UrVxc5Bko7nIX9M3Bn?CM@WvKIz)(Uj0-Z|9c2+TGOVIq(6(CGYY{Dnz=xQ)m z-|^#^MuQ((Hs4zcx3DU>{b6tAEnA6~P~ml2XO+~{BL1s&_LITef??8(?L9vtBCLSt zqA7b(eo}}J-0{QShe2&GMXuu_*oTUBSBpLky4Oo^AyfjieCMWZ7Ip{% zQ*)%LrNkU8%1Qm&HzYIH?iTM}=Yy)Ee3S4zqUTb_*#CSpb@$=qpE0F;sN8Fngl?Zt ze^xK-N9b=F_itH3Dm3KXPWF@(k{_$pbvnlUT|0WDqiuF=#K9e29GOZ>+sft5Q?DeH z>6AO*Y@wkUxKha5YY#=mPh_erPWXlJf#ar>l>%vUWf_8HnKtWf3iS%%^=z$UML}+-;=gz<&EpWbOt1xMj#KNPUiv7jy@$H@fTnFKfIU`dB3`d z4_O5hiwHJnBh43|bkBI>FPSuAyZRuP~q$ z9E?~6nyAN&5i1FC`x2Nm8g zU0@#*_SRc&mS48MJu51P^fIZ*w4>NG8wG*Bp0b5?*D> zw58+zxXbA_+=2#5h9-t4&grca<=5h-3WpkNBfm;D1RIt9mVR6C%@H+EXZnSH7;9(! zlDC++d&)R$l8HTq$nD{me5+4+XQ%&D(0?L#t&d5{d4oMZ!b{%PM)y)QyEoVz)iqc; z`!25)<0ly#<;Ga5@+fJrFix9TXQT!Vx_b=aL0xn3TG}@42-WX?z;DnNtgkyQ5xoR) zQt8&{Oo$js(*uwN@eBfN`D{n+=CR|B@%w*eM!C5;Cf^(bp}9e3e(1))H*t|i5opem z#EYfy?Y@qG8DI5M`jZG-AY0-CA)n+mMi!@2WsM?ah2U2cUP}X7@cAQ^%tWL;2&eh4 z`evgrM=)p$9#V5@xyHK2&n2oKqihzlURS6r{d0%x!h zry39Gq|%H-z?AtA)0BIobULM6jB|clwpJJG%v-iWh}qAAM+`@L@ipa6Dl}gsX9YWh zCpDf&J=!2?7~7gmyOAp(BHO04n%`lSzbpDYtT}yf;WjZY8DQ{DPDB%v34feYp6qn) z3rb^P!ruD|W~eHvq5QY{Bh!-m0`QFdpVfWY6G$4GR4x9}j3PF@d{@D;rh!~T{-uUq zhwN9k=lz@5ohJ1yS#gh0U2_5S-C+=tB&vZ=LXw4Z3|T=#9d@I**0)&`w*g~+R$qkO z{SA?5fuw34Tet4rtX!-R;^}U{s~k40OWWOcyXI1v({!IUx7x4s_)3P|0s5t@P>owj z#$knT4umE4Bu2Gz9R#H|XI}@KcpBxRwr>A=Md26q`Qv)a_ax-ZepS~!8z-Oxe{~pm!QQjLavXx?5>iVfN7ImZJD0Lr7x)A70lqt=pH3=%P>H!4zHhpkMaZVv>&1yls6OkZM($_~J2~(ibQ0ki?f>KfRR)9U zU(o`m713|`0Znd#8n_N(C;nW=?JBj>YN88%qV|zB$n*|938%XT>gjTdd$OLvf)C+?sYJ|K$djh| zkmjw5JW%WIv0wN127* zx%_l8#%}JzQVw9CB2GgzOn+IOsgb`xeJeqlF0lS zk=H#RPK07}%F=J}Yvr|)RM~x8McZ8SwF!4LhzG80=t5X8oDlFlQx1{~G~e*L;CLoG zXZEKoi00}1x#Pb z{SH-Qp6j%`eek@Ow}dyvPqoByKk#$+@Yy;`yW++hY(k)^A*?ALr;pZHW=EbrSSc;mx7WBeh zpCi<8j~Lj6IMz~vtz-1??|0Ffr;m(Yhy7EHtEm7RmToyHsG(};6Wpcte>yAloeYA7 z3pTQ$2FViiQ>L*wv_GPiHulZmjjsKOfu87#1L7~JmAb*XBFE~)u%b(e`Cdhd=b%ua^6y1BGYGA#D? zs1nfQ@WICBu=le;A7;Be#ayebiYlvL#R#7RK~K#x%DxO)JG3X;Cz)z@1mbe&>hr!a z8n||SAPI7zTeZj&-Q0Pf*8~(|Hn>M^li4bpuaQmo0;z20#^Nx>2VE3DzTcCFTjo^+ z};qr0Ex!qp?yZdizxjR6>az2f0WHSCv2iGYBJ9DTeq(YF<2^z+U-mj)n ziYpJ)6CdTci3|ToN$`jS4@<_EUi`>_CR@=GWYmG*lX6V4o2Vn`g<=>Ko*TB=k5*KT ztDbA8XJOlOq~C+>0)m%71JGcgsk`m zEtYo5=mfg2(9P`x?3s6TZdGNlQ*fVCT<=?0bBgZLGG=yq&KK@z%$-ERg|U>0 zGS$_i1f0{JDlD;F8B6Y%X6C_}KJSb6=JO$fwE8H#Cha7Yueh~f6y_AuOe6XRdNlf|-MT3M?3(+_XN?g@x*Mx0 z%GG_kCG4WflwWR@ZW8a?(B?LWwRt*01n+Va9q%ojd3u+n-!4NBEMy^c{4<`Dclr75 z;=dNn0fuXHS-6pTi&L#`4)b(OuS)t)$bcm;*qs!J-yz)2Lka$cVe)}h{dII|qt9^s z(D5z&q-J^f55|3SFm>2C4GzX*0}*Oc=!=TLW)*DB^Zk$w? za@FC|G?w7eg4yvVZAA~is-do$3K`AiipyX$+DcGo0inJ?gW9R=!zG|kEBjFAR;HtG zHx_&PHJhea6@BtADL&_2`%y5Fbhizf&-@tE->yIBr!Aj z8Y_YO;L=8~tBRyLBGY11rLML7iMWfTEc~D*O6H4^LC$8$t!d5gyi;pF##swKa|UbQ ze|W0q$6YP7{EBQ)COm0$#mKa6QTwv{T*7e2ZdR!MUkckaem4N<;`3mnzxSsGgB->DD!P0lyDl}$Q<2|73iN4hq3ETUNq5gAAvGSt4W&+M4%cx zpi~0R*SD;EYqGy)By4|Wcc{xBnfuuf49p^KXCY7!c2dOyckzch?hC%)HAR+&_ox9^H@g4 zUrPZND>YXsSnNB=;ij$Uq&G&yjm?{6f3VfOR@{cP=PY8A38VeOj(5<6A1XD))I#+Up_4qY+qm(Hu zu>2Zyfk^xaKbbNg&HUlgT9U754GDmF#igKH5Pz26Ec+h6y|?#9Cg14KxG8~3_vbvs zI&)QdCx$dS=&^@SDJjH39vS#*4T`FyR3t{Ysg2oBg3CjGNofmQcx!j|yj#7tX#KMM z-Tj-_t3WEJn92y19#whA~3`)`Gr6#0(pU{Qgc=+@tUXTb}%%VkR4LN5cG zv`d?QEeYBWV(y!&0Uw2ueyA0fS3V z#{4~%T=JBuI)Z>m2entYHTd}UOC}g&d4%6g{E~WT_DZctM8ohV`)-JK9x!E}nM6?E zRqXC#f}5}do92p?tXTI7p~?dXHESZahRNLb72wMtc+3wz6=6J%;zEkuPS3B>M>*o` zSI+Z!;2Bcb!DJYm187IJwHWC7$xs^KQKE5zjkG9cVy#E4?DgS<~@M8xcd^@reH2a0>H~F0s3xb7|=rK zSPL%izg+dl7Z-CsV$xu<s_z{ahXD%s7{_5-O$7evF|KCLmrl)3;9i*e{He+Ge?-mUMd{2InVe{ zv{Eolu$_s=jiLu{?;n+S0SBa>G$Gz>$7hYsI}9L)_s=DHn9lr-@H1wyyM$S0ALV&j zGwpeHH-&d8JMteoh*O6(a|Jv#N6jmSg8PmqO8O{s>Fz;hOyj9RjyB0~ze~oz+e3zfowI%a#1J5~Ds=9}a17URw7sfM5GcsMhEzjw#o> z&%ICqEe9Qa9W-UUX^uF|Fe`3*ZC|Hwpx0pQnR9%n$8%N^y8JvOH~GcgJvCLT4u`DW zsXk5la+@k{0peX})&0Con*ZTk-mUORa==>V2B9M*QYuRpuf=zocC&%vd&P)UM@0U= z_5J4H4lBYm=^LnnbKTnU==L(u!4(}aB!9%cfo@HGUC^0J&6x|a-=R=-5>q}FI-+Jz zzk4CR2J4R%YYBuem_O;SIFG7);7oKPZ9%u9e6Z|k0q$FvXi0gBG9B2XqL=Ef1{-9^zU{c^ICvPfQSbM+*E!Pvzsp-bm?CyDJA195U{c? zc{A9ub>zEMau)h)Dc%2@E1<*SJRs#all2%J8;@$0A|K_*a=U1@2dL=usaWYBZ=W0t z9F|wSt~*zH_5YbR589Ri)qZua-wQTfKicq4ncn!TW|_2NG`g(N&KiLog8VvsGu$XC z6>!;&bXpoK`xvnf-$aOHT0xd!N);*K_RGZ&`Wt8Qj(A-e7y!Zeq`Zbl1*V~V>MB;; zua!5y?iHhScHi>=-52dVj+L^9%Y~gW&%GT7!UnEk^;Wr}4t}tyF)vc-%3-VfIuNvM z@QP=KuE?;og(pWb5ON?o zr~bmbf0Gm%H=DJ-Q@utowMV(NLg&fo{U5l@vJXcVD z28MLc68DBp5f8cMdnkAJNCA+;(XJMTs@AWu-8;>f0{phmdTkeBsLL zs2vBm8Hk%J?zogR4j84_9OzLn=spWtD9Zt$Wm{%9cm8E}7;kwjO_LjJP5XnYzJ$M0XW@XS{(x(Ic1KN}@boaD)cb9{@% z9Wkr+Nq-zVr_DyeKG<74hjf}@%EQaHXVtT&z_X10dSvV7mKw?bMy4ab^+61B)n>Pj zk(v$5@sb^0px&~8BX$)x>gL{?A^&8**&x=YYNa8312Qr&s5sDmv~pB!HUNC&*MSK{ zcAC;GAVysu9JV4OD&B|>uZ*ke6z^7^zz#cXP;>bNEgVs(tUYTyHACT*ck@c&--Q7C zV0~}%+g-u~CRo~mBLT=jcmAr~xU9so3KaF6TQVuKk;B_xg*_atwvg8Ecy0dH^H(n9 z4{Kkue0P9%U(cHszuB}8Yr>|w$-4@`npmfb%n;yS}ezV=ngv1ZYR$4G#&wpvNak?%3z_vHsO&q0+4 zSN4*`Uyfwczr;%7h}`Qub46*N($dt1;9JDh5&ak? zDE*W2jThFEuEl?B=#@8BChmj`QdN)z9|hBst+uAath;QCkY#dpl$F!9uqZDpT>`UC zbS|V>4Brp#Ofd%((XB|ONw1n0eSIpsA%IV|Vv;vJ-SZmdXVqn-%ROh(=K>XGSIx6sbY>!COID)r7CsY?%MBc3J6 z%Fdu0PztMLKOy3+&_=Yf8wjISA~=#`H`z0c8_N1)NK;B#gHHvL zfK;~U1~|LUqzG*?Lm%dB6ic8LlVOtc>~eClPk(MGT|76y^q&1(c#7tAb+SY6q3;c{ z6$ibcTt(bVqx6Z=jDYyaS=LfT9Q$%tl42eHCL4BCkS206?b-hvTtP`cQqHfWO+=}{ zk1iI~mIl1_@G;GACm@-&l7rn~MEb*_jYjD}E`!EkhXFrCf-quotj2UnZbkVYkYHc* z9Z}RE@6@Y5j^V-ypo-E#Q@juItt-H~dJnZ(77X1kvXXhWQ~;lB{sp}QF$O&dlZuA0 zd`0&}C&ngTZe=>AbmcidC{J+G?s)ke5w zG2{Eub5+_BqoieZhAEGbst6A)ze|_}B9kMPA;qVHlq6Q4V05cQ&D{fJ@-U1tdMu_g zp*-BYb9$?^rKtsFl*3^+DzoMM%$iVN=k=_T>!=t~5+_1Q+t1MjvpNu-0t{;ME-n6!LAX`<5A(ns&{ z<>*+veQlokT9sYpm*lCMx?$q6)`D^Yg3M|u`6h~O(x6lxD}Bb$_1;IU=jf zw}2*Ly(DHbW59E+D+@P=-6p^L!nxT_s4JS&G7COfNIE8O?M3G4^yy>0!Fc?rxE)s7 z@J`8$=0yxgOkpVMqcF{rJ;BYw?H|F$rTYYfTLG!%kJF3R_t3pQH+6w~N2Uy9DUeUf zK8lo94HBNY{|F#O5G;y~njyJsBOmv>Iblg@Z{quoCr*W;V%K!1z}54}&$ z!po1vM$z=$(-=i4y+6H8BQ+?xJbpt-MaY?GaWEbm^sVFTelt<+)Yd4pnTN2fIkPf@ zACpgGMb<~ZhW3$p`>#)4gAA*gckJc_iTQNNhm=oo6!U?b?BX2vjBk`ahY?=?%%v|i zr%}Sbj31{-e!pbLyzSxemdxwc5%*QtXp7{puE>0A8ZoZ(6oQGSFj`kLEHdXFPtW<9 zIXGK4wR~-1;WM%ZvhoN(q(Dv5XGYj%wH5s|dVXNcif*D$@*jxjnLAoG*H`4dz^fvX z&vZtd1k(cS?QIG5rQa%p0{o1)`Q*4|1%1S6? z#wHjYsvidLsugVNy5|wD|46MkLNmr5f)@7yPO@#n(9x8_oxYrG*{qDPPpLy-myZ3n zCOSo4XFpg-(#L*UfiX5aLi}gLPycldNsd19qS*`zYc$8E8fXiJ-4C} zcHo8(8x(m(g%BN(uiWCTt$I&|ocw#JOr1BMGo4cKE?ooXEb2c<6Eg`{5A1NQFQ3EQ z#yefTv&o`?@5VK+pl$Hm5a=#%W8rf^je=hC&-5C~RY$c~-rTyVMvgZ*blrmMw;nMN z2MFn`1ErA+62-qTO$nB$5U`UOKt+3EbJ`RtyCn8R$bDT-nJ3eYI%{55UKSBMGRNAP zDT5j%NA@BH&i#&c*+rB}zEfatee{c$G8l<9M}WO7$zC-2SSDN*XU<_pfM&p=*Wm3B1QvY{i4sH zvPC81X9~VT52AlUgBc)O6$o;rREgmVZ^z6?^9cNwI7+SeIDBh~%yku#rjGi$zo^^= z+6C9y$k3NpL8F}2_dz|clxDUjbp?Y_R*VGYI>(dT|O{yf%HY3$XTKG11kEyXA?Uv0eU^y zQCuAg3P8m!H>~j~*1tZqu}xLWY*_YDj*qZqnbSkpJoLvaT!XSz4;wT2TADg$5~f2t zx=7QOFJNH`qfHHN%U01CTCFk|oX)IF=$0kNye9xtz}A;{;KHYA)FADZ zU(#!Gm)~4B|I6;0?LDrOB46SUO-BS$!udwma+X8CfQHlUPC)N>xFKML`p#OZ9HKdCHkK5JXV{E1kT{N|BIOf;D^X{3=>B{kFUlAeYxj3QS9*9=>K8r`{Wun^AbBm+z`USiilDkDBzB)0;rQ$&{>=6cgB0mt-8vUkLGM9#rgxJet@m+r}26hTQFO=@o_~(ko;oBQ1?^g4O~F>i(KWYL$Ma>2QxKAAJc_0Mo30JDI(4?oSk-XP0k z>XIG4SbC<9N$H0%%8l(P$yA*i-SFwhouFP+k_J0SB5yvU!oTTiwv~MJ*_?#^^RerE zMI@Nklp{2Cjn?#;MPE#ek-$;sUhj`BOjFYz2LJfQJYLPMQYKO#a}kP?Jwo1my|1UA zWI8*RoAcxeejjaA^Lh}b{_>TwnAOGv&8G~mKO=$j&;N>R;j%chM74K1L~yYbI>2vZ zvX=#@Zvl_2q?ZN%lyA?XJ}hqirOo^ZeA@Wm)95ln#p+ObDAsBj$ema+t29uqg%gnj zs_~QXJKFK#x~lTGyzIvuS)hs=4jiTZ=`yn277`k z^KJ#g9SUIo?49PIUc7)U^k1_9MD;}?lpem=`L)9C6r9hQQ5em);W_v8=I6rdsK>ji)%kQ7Oi$da_uY;wa5*r z#1LJWrIIz?(!ZjixCOd6(3A$_<1SHF=rHExSM-^xbUQ-E(*<~@V%FeP$d{b-dMdwy zzY7kN`RRGYPm(o!5Pi$Aa`hx^+;Sw1k;*Ip3+f4x2Pv?|Vtyc3NWp48$DISl`|8Q( z;k6xQoJ6A9qx`1_aoDexE)#>aYrWBmQ4LYmm7rHMoJDK7q`|p5)BS-3Vpv?XD3oQETNQ*Ef)86!pkIA}@sCxIPfzlX`;5EeuhVbmIbL)EzO8P%T`2q5=+x3hT?z zYOGqFELRiix8NS2KhW?3@q18nOMu%-zw?`p>_8D{A(cRPFDtc^Io}$dL zA!7%PUht+Nal6@tVG3{NlC@tN|MBZ~8ADU5T>Eta$@+)poUTV+-)cgADvtc@g>7;N zO74}EcR`oa6iPinr^Nj}A*Cl@5S(u0;L|!wy-b^QoEZK`DD(ErGbwDI8i#{B?y17< z;^dV4?9x+&=`vi0P33V3Y`MJ&O~HuCCZ*#`j+ADyr385qstOHz(RH0y91i!rg7b9V zu@aeW=NI@T=nSzQcLf>Fh}Xa3!Q(f`D-T;dRgt*ShZCj)Y<+8b0^s9#V@8*IvR}uI z-1V&o54;O}GTt@3Q{3omy((n^{A2f$Tj9?baEXny8DtwelCV5gk8>BZWA!iDA0Isz zu89)eE?(VGiYId1UPpv4<*p9iChCw&y{Wcr;r~u7+Rf7mTL>TOZ($#%u=9SUxztR9 zc)&et&!~eJkd*#u#jFwRED=!tP8Xm1VB-&(fx-2@Q$#D`%CZlD2fNA4(P%1p<}(VL z(HFZNBc~L?$D}sFl}k@d^kbxFq+@uoon9Z;(3pXYmkF_Ko&m%5(M9|J$w@yu&eFFJZ`Jkg!6-KE}m&GZGT5^H}F zM5yt-GHZ7`M>R{Z(pfKG*4(QVS$n}jrfYx{2st3Y`g&~nKZP*j z`@-_#%V>GX>=Y7}0&|FyLR5o8eeOVtK&Y&x|8A_)jwstoo)z{CW;ImgJ_{ir$bK5xt3hZY zYJkYCrb*X}^OCI>=n(Y*uYBbONa*v)6bf^b_Qg)D;dbbQbyqZ1AmeMlgs4a1`eFpC z8r_mUOUdMLR?4U8VbVmsolkCtw`KXKN6Ds#0-<~=`-F@7q83JMkjwIoAB=jl&jA)~ z2mu!|%j9wuS~bcRuH{x^FZws#E*)u z@!a@JfKy6Pb}pz4T54JeF|pnVXG(FIPyaena9dr)9_YG7NrTgN$}w-$OC;s691pj5 zV`%y!yrv0l@mq!Z5%3Y$hCkdohr`VVk*?dNPk20U)nhQLC+HTAX53~tVMz&i(|^!r zs{4(Y6iu7sR@~ZWr*a)Bexrp168XK9gJ@wg)TqAr2t)xeEN2PA=4bOU?+C3nmUrpD z2%OFfkG5E}%L6lfN@fsg13yi24VL~miZpqV67>m57$xv3)EgOfH@e8kcWL$DAoEvcb zGD5d}yO1>h8_Awl49BJzFC@7(aOuCE=kVa5QCr`%K6ECro=k)>j}p(4$=5G3LU!4s zbt#+))F|QMUf{|$Qyb-5X7T_sl4jDS^FM;X(0llR3O&{lq4oE6)f;AIXkhh`%Fjaa zKdZxgh{*xYEx5I_`!eTnn{A@T8tc=q5Zce@SdNf3kx^FoiNqcC)qlC>*H*m2+M+ob zL!;`M`otGRheUyMPn-#VxUnsQLWqt!|NXu0UYa!tYuoDr3xrSlq`k&isjES)wB$7S zPp8+{3QW~aI}v6k+{5W&xclCUe$VTPo75lh;Qq2u`0dA2sjmq^6g*oZe@zP6@3YQ~ z5*;uh8B!SI1!ZL80=q|(ydH*-9T1=$c}2Ht%)QRmzt;J_XNl_;oVmIJSv9F$Tu>8xw$fg;q=9H?gM`mMF;j=UB|8CyF#u{G zR|;r_>G#-iSBb)|x_qf$4BgPP(y5?41eHUEw|6#gXTxWisAJ3_sasUl^b6fbAss0w%1r* zr5DHVcg&_&?8Vxc*6nT@)s=G)qm9y{#8a5l>CEd?gOgK}PQ9?CU%@L1g!>kf+) z>$AUwr(DR57A(adY+qL8+}zt^>94S!9^zbn77GCedqmGjgi#PH>fQ|7Te=lCG}v>+ z*o1ED1SzatA6XtOD|TkOJZd;--|rA#&e1YAZ9pZ+(bB#6cDfN*{tvt^kQn&B> z{khAl?p)DMO_UPlQIo3hXt^f4b=q z-0w15<*5$krzJRVzq{GrRlU0y8>C{AmH#qy-{zZ6XxS0_Sx}IX1oRKH2c6NL1lObM z5e1gp5!)Ffda(Fmy=~A!FO%%U1d!FK0*{(DqV__PEC%;6!Etz!W@AFTm&B zELy(7U0dYHf%HHE{nZ3D`~Z|BFs!OJn7xX8p&&S2E8#tR_TWgto=)!Z+@B`fZ+AbP z8pu7Z3XzRJPxLY!oHgvmVG;nck|-?sn_qDgDG90qx9kf#iPmj~$VHc`kM8MMy5G`M zOY4Vp&!Z+AabJd`)RUtU2!}HcAMz|RwbLe5`KWAcGp@HNO1b|)zBNq9{7l;vY^mI~ z9Ibb{C9*PHUK7YXtRNvp&n(9rY`D@WXv`z~ETL&Hw7P;lgWBmj_%+W`Y?kHLAwv<- zX%tr-{-NO!f|S0gy%H_&qovI|=c=~-T;~I|hn@@#>3LsyquN0h&vgb^+QIf`H6s+u zim@B5im4^c-^A%8l`W-BDi6u^VSds{4y}D*LUhW{lNFXr^WcmTy?1KbP9H zJ=$R}+`2R3)9$gl2f3T;u@Vf*KyF7(rLg?Ws*xK^2wyjrThK{^r$O`w&_u-A|TF7Tt&>lkdJv zk|XR$080>qdygg8Ct#peZ6MoPJa-fe^hJ{(9th(hwD-_FQhLbNkL+m{D=`{e(OCutfokrTit=cAjH{vrYv6Xzr^TNT{Mn z4dAVcY(75o{Q9>X69hi%NTq?1m8g5%F!X+!vQsI_vA@yIAz6(AOT?7-4=FhS2@P1QGIh@)Ba%f{@pFLM3*iCaDMpp{85F7 zv;B?l+3d&ccWDx`rl?JbhY~H5lJL2n4gC5S;;uW3W^Ejd+u*IF7nYu1^$ zHmrk%kyBEU(~W!a{c)P{FbGYRu2_jXF+RhKK59q658{RRZr8MgBL6DMJkiGTE&-GpftuY5*T$@=) zzk!+nEJ($>sSA4p$@NGo;voia60)F#gZF&x-IwLWUB5W6al1OzjZ223WM0ag=>aOz z@Pr5ko_aY$Lt!9WVL}G`w%*Z@CnMiqV4p%EC?4!eo0a5!-iB`2l2Y*r?F#6*v3wKb z(8Et)q`DX*dX#{Cn@P|hewkdIRI8_MlO;G);rWte3(wmIzi#}`!o(f`!cwD^zVk$# zy?8GStg4Nh?*g&>^x~F4=Bj3{C2XCO1#<yaLeQ);WrZOCh|Rx#8D>G)JVr z>@sc3`6pOp$1Bw=v1H5mUCGDF^}fgM=H>Pa4`<2arS%i;mV5y#8$ul=Jsz^<7y1}K z##u+LVYwxmPeA`Y%~j=ghK1AcRr}cwIJr?W+}}$z)0|-aJ3MhXOft-(%5#V#GsUH^ z`M;xXwZ1AoC~F^!IL?}FXqw2^WyMrU3A{wI--YI{k4mo%^q{Wc(EvxtJT>pwe#rK; z4xfb#M%O<#{L@?`P0k^&(dEztaIEa0@Er?05slLR%JS7$)}J-OXE>l-S#-eZ`2o zyEb{B((Q{*0Wh66;enJHh&3dTc zslepp4}Tmun6@+M6CKb3=XxjW-pFmhWg?%q#!)DU zy!?qE8YSuY8tQl|#l#*HjIdxu&qzlHG&Fa1-f^5Q$}r?DJ)yRr>Aj6Z%6dwSnvSR+ za@~p^<>J3gKbWzj3_VNl$XRq_)fy)lDq2K{Z`!`9R5En^wRJb2p96)5V>A65kYq|x z7o=ygeEmUBl|wx;cRO98bwU~X!II028Vc)eJcIg)YfCD^DqY=~Lr=>DzSMs9|1M?1 zzb7baZtYyAwPapRDNOx7MykY*7vKZ{k-Z?>Fjop~PO@1x-6XdfU2J```J_8^)gx(A zv_`KoDX93A^H7sO+@zB-n+s9Usb=3UqEAf%+*h!6dJ<+%sGbCtA?6&y1id=AP3&iV z8xVHK*)C#uE1BDpGR%+5XoAS~``QpV@F1-VQ`ic>U7{ZJS-*Aqx=3=@S#@6pWmMOOHp}@T3Wip7&uv>#ta7ejSc&T*D;;I0Y2-+^ zY!*FvJwhdw?w$m|04-C@5%k(2v<~MF*ywB6`^|@n>HlOpo-f`b_p6Vj&%RD@IoBV^ z5-c8}Gw)_NBj`Dr&rGOVUgxPIUvey80R8N(AMv;U3M-*ahV*YQQDi3J^^~JJ1wVQ) z)_K524tGCGfl9WUJ`j~5?Z8|ftg5xVCmW8kjZ{!yqisX%R-qfY5{*LW3mEAuyHGxw zN-LL1=b@~c@x)Rw{3Zc4UK;Y{Z1L8Hwb!XWURvaXRehne$Nm|H75q1FwZeuy??PdS22CL}dw$xjER2@nL9;d> z-AY;WdiIA@Hb!$YVRmwENx2HcX= zq!0Rm)>Tj=OQ`(G-%Ei}P@eMz?1vfO7v8Kj91A zgG{uB1;2@$GQLbHEPOE~K0{X1tHC+F_|#{Bd%@ik^^c*pq>nEhJu2OLZVEu+#Z@j$ z29h~z!>c1Dk=GK@>>bx6uOlEI{5G`FUNOgY*}<~$MvUy;Y)#vrvNqV@)Ij?SytG{y zcu};vLr@m_LaH0@ZIp+Po?+`t4sSG-x@7;BS`W=K2ZNB!$#Ipnq5N$tfX=j%=23}~ zp{kA;O+HxWbJ@6raeBQ@&x?E!1QTNUd}DPj(={M(#=T4Ortux-!MSTHZ#_+MCtZ`L z%Ep8hS3%Tx?~^%Q4rhLnx}f=g&cLkh>7G7!vPjDRsZ>WT#FfM@fcc&7;rwpyN2sAX zm@@zZq9e1aqb~y_FFvpHh&vWTq*q3}^{^88mjEAdMhRYw^xPjOLa;BKXQdphqiJco zwgEhPkxbEa%XItH$X?~rhVwe<2WogiAVV>-V3n#i$@@rU3iVxNhN?&dn0fpbc>cm8 z=Z=9uhq1DcwjcXxgS}wSqVtK*I8DLoTE~ucueE)LO&~zK4V(%-@DX1)PkA!`+Aray zW=IO~Kuf({>LuW9=AR)W(-42`El`L6f($z zHiiOfbW4c^^|}CeJrc91U^16BvnU6bo>T5dlAf@P5IZPfe+e19y1Q{ zz+=wvMQgwpjjcm5q>~|~V--nGw??Ykm4MUc1j zxsw392{+`FpT01iWRCV&b@re$omMZkzNYbZJ;Ygk2}`BTUs=yg&z_}5n=h?MFZ<1W z@WDF<^iy{JsJGg2ByBQ1MVR_r;=f1Gg5Az zH%G!CgV((6UE$$>w&WWf9_B+;7CFyarotOOJk;gitC*)7>`za)@lERIO~7hVEGCA* zx!1C{RD|ffi!|Ty)#CpWGs-{eR<+de1qQ6E2BHG=YFN#Oc%xJ}UNP=amTLBYYc!h<%tHipU#;=Dn; zBRg*MGD|&)V71?&p1L|G{IM|CamqPh%ISJxtspd}#@zkh%yxBdSiudkcR;2_7n7gO zo2Kcj#2_5Y;)C_&g;y{0L%Meu!DoZxo4Nc!Xt2P|7*M?8d@j2cc>-XC(0wb8FwY>@UFr(mwp(PAWK@UD7+#{ z%$D+kcWopCQR7?Pj_GBOr^^q__+ITT35$qNQ{dayrx3%#_t6%)5ai9u-aSkUapZ| z>3$c#QnV3$7xf#xln#5~o;H4cS3j%buEc{6ls7{x)C5ENUDwpkNGyR=#^@{U_wykh zKYp30I{W#`%H_MVHt5V<`b4Iwrr=MK8>Hl+mZ{&CNLsil5Lu`6_BXCdMEcpe%R8Ui z23U|;5*#d{(iV+H9}ymctPZ}HydhbEe0C#q@7c?*=}i0-GeKNpo8_79=bLh*$>EJd>m0gjLcTeWe&&%0 z#AhrBzVc;2^P0&f?c*eFV z<4N}+25mcGqh7;gLv~Os*`FsEZ=pd*P8WhQ*$6A*Xj|=5)Mb%V8_yi4_>#?sxrg2o zK6GF^-iW5ByxytlkeZz3IwW@>^Q=qtb}3vP@4?IAtqqn z*qw~k{tG<$j3xSIeg?Ey9msOmN+fu{S#yrk{wBNy&9B(Z<+)meTNA|Vt$7%0r9UYu zmKG!r_9{%St9-s~F|uu23S@}uKR7%2>7AbU?VOR#F7OmU9L*B-%rupBraZHsMzBL{8Cvo}1jXxv=uCJyPnX&laRFNDInP9XRI}+VEVANYJ7yjo{ zNCG3d9f$pU?Z2#E+Y{!dHU1;+eb-9~62ps~xvcaEow&!s!*wG(=eKwNMtui-xMBsIJESg$!yb9G5l{Dpc2g4pL#t;-VzNE+)7jui8sM}RAT z=hP;iTJ*a|mO8vU0^T;nCG19o8L{QC#1U*t_AwE6XBbf&Dx5d1hj^8dGfC1{(;^(H z7&ek4@}`om+O@tez9Qn_xNJBaJE1Guho^i;cua9-ItQ`R7I_O+tn+r))= z`^-Ho#=J$IJzQf4-ku(m#fH>|u0IMkUei}sWar@I^Z=fjd2u0<2JBsU^n}VO;nWAW z>(q$9WQCS!zwuD)d1W4RTL&XC86sBuz-2Zh^2h1^GjaN z&D^)~-F-HwedT|LT;^`BDTxt3*d!pORX35ZsO1|@B|(K5nf`0yg&4T=vU`IZBZhR^ z3ryN*W2D_s=8?_fEhF30D?^R8t1Gc^nBVJ4BrJE(;Wj%k*(R>X4x<#|)FGc*-3^xP zuovdn8$9&4<#KP8iX0L?hdEs^dvLaeofxONr(O1*MzIa~-?3&gnoh{ytll%*;2kF* z@2{r1q^rB22Xcs~%FwxgmLco_%Q<_KGAAeh+kTs4jYMR4ola> z>pw@^_(dZlo&dqCbQ=Ub>>de^yP_?Y6eD`52rls6`-1!O1Kwd?#61037UKzg*B|tK zNxC0)wWIRa#0_Az3LsEw#4iweOP1MwiwRd8)aHzlaHk-y8Y$e zPA7$ZIaHV){7^{#uC4fQe4|RFQWNHUtw#-%mg;D6{e&?6kvfts1;VhYi#*=VARU_1~$42Rt*}xwu4Mo%$6b(ZHTs z0)*)Jev~WhQ)s!r(P*qdXoCZbx-0Y)-Ph)|n$}lp7{tMpd=od?rX^E8T}920-D;Z( zcfAjeGo}+zG-lDK6^hMJ&lFtf3nh8zz9q0>vgD-N-*?0-Y*zrGubku+Zl|$Gv14hY z_Q{gVxZ!M%zXDj2cXXid4_8j++-4J{ol z2iT;I18QMu|D!7|wKGvP@iwAcav%|IunX^%LydMy^)>#Z{Y_az2}hC9VSjDhiUdp3 zJJ=IgQnhs?5V9c^qa&QKtPP_w3hr8&iuHpZh5fESa82{8d`q=E7cRkZsS>C4$GH#N z(~j=B84+epY1&7vdi;-_ zFKU~3xD|>FLJUsFlVii}OwUXRyE|votAFrF3a3kq4!BHjLY#46t;Bk2IkK~1K)F-m z?Dr0MIJL!D?HcDv4FM?+(He3kLQDfl4D&3a{An>dZfs5lK3!Wy#P(P25vFi{*F|qo z_u!!(Wbnbc`QA&oUJ)JFPXc9z5-zty!^)E!y||Ea3OST&f8(tkUZRxwGc43xL$jh9 z_@02cL}RX%gIES%BLBV{=gHB|^hHIJ+FBpGH?vCX7G~L+Vxx@Fo1wqHr5>u zkvB{p$*^mDUO_zyYZpGl_0bPav#KB~nk;$5HNQGmUTSzQ2^rC?LQ02t#;M6E#e`=F zGq0@48&Nc)9#Tuf2e1%QM=mHOQ4;|HCDn6Hbz_}BfsNvO{Pl$Czygh)GCK(As`4sT z3q^Q@5g*skQn}1*k{y3~-4-Qa`jLFm*7O7+vMu}3gRX_x8(@bG zgeu$*>b?6gy4B}ZcC7FhcH~^A)j|un7&VVr@au>FzW_)HxAu>PFYsmn21*D6y@$I4 zTm_G8H9*%5t9~4Oopa`P)ryJiJlWVsESIV4hp6iutGbzocGYcVfMKxAL=D`$Fu4_tS;T49Afs$?qXd27w}G3LENP+#y+nT{-tsSL+6r}d*^lzyxaz&ehR$6 zd%_oZQvd^}L3or^&aUHzIfnDDDs{kpXDNbM&M~0Sw#?!d&m5>f$m` z&ww~9ckb4uF*r{3?_xNX>tef(>tz6E`Z6)f&AMZE4t_O{TQ^zdmaMr~e>ILQ{h-F7 z+_P#Q&sn*6h>wrH++FN2k_9sx=}1V_F5%?h;&g5k&eYJyCy zs&Fow$Ds1weBSCFJ0PoAz(2I#Nu7d&TlZT5+c{O`mNS?-x9KLpocmOhXH{QA%CX1e z*pIs}mFt};`>S_{FYqA%2JY&H9eA8uRdw$5zH-Fz{0i*chOaNnBUgQLoVqTESXSqr zD^>2xwaH?ud}s!1x74fZ&&6e~HA`J^Jww}_KlYQ|+m)0Eg;dahTX8~gmNH0M^cKB^A{Ztt$ElWO376+7f6@s6tN(z5(!>_@@MxycOHopeK1 z=f<45*G{@YT@UDZryLIIqW}z?3SppzkE>@Gxd}N{-*wV}{(&ELjtbN)I-)C~#)b zt-zG!T-6%k7@Mt7aQ(P(X6>@^tF4OZmIL@q_yQja;Gr9)Bvgz7u>-TJbD&mkwQ{rS zn{n0HGI;Vg<9OeVL&a6)XUIWDIZ&>1&e_38L5-p3z&eiIxgDfu!K>UnUx(_0HJx$* zJ{P{ghXWY6yBl_|+#L{CDS-@dSwEwXDp%|3vkx8yeg$4N{uQk_vzgcGEPdfzF}JT) zA7oI>`m4q{Gm*&GP{nl10em)ihdv&_z##~$a`*aNfw%&*T7%2m43z4;Du%x)r^c?v z?cnK-SDmjLOZ70%KqlLdWtn>h9Xr_ZR;^A@=N$Xh(l;K5>WAB_{#49N*@ZTI|E~?; zpp#P)S$W)_1#u@u!Jt*neCA6P9p?^ltj^u}aLVNBU9Oka1+|M+pk+X1E|cROxE&y~ zrDs)oq#N(X;Nm*vf3@NJuQq^5H*mw<^2(WV43IBJi*4L_RJ$r&QN_42K3}J-+m^NZ zfM@W@Aj)mCuP>`O9s{3;f$m(k>Zg;!z(fqkb;<#3@G5Np8=VN^3`QLgtG3Ej&Nyl1 zqWL^7r(C5RxUGtv1@LT6xZ{R1h-5BOl{?q$zKYyAr%FY*9}ePkKNWa^4PU1X;6w)@ z%yqLMUU8W!t&xFtY}rYxady%k&bh1pRQYON*r}6l=s=~)muAbiDtO0Z1?TJsb-2tq z?^wrU$j0R2s`9_u;LWuGT&M|QU>-0X=Qz}v6mxxNj#@$1t^e&DXHHqES{J+u-lz<+ z9OufiZ@;Qmga14})3f&guZVTL)mnx1$ZLPQpu{`@h zomuBvIb_$aQhdl~^TSl-hHp_*LEzton;9a6i z8&s)-Se~tpaDA-0co$!_amwO54}S%o84!>CZob!TyLskr-)fv$dl#FPUuc7OP8+}r zI>8Ocx+9Jl(5`rtAMIzxU1y-r)VY@{KhV=nJ&f2+KOM*G`f|Su;Xuffa6Fc54B0ql z^So6ZfDPVNZ2%w8i6HJe#%dyO)&W<*bk29Eo1$=qEf{Z1|p~4d9b? zCr8X}XIChUvh2r$&iat(^gjdUGamd-ADvhE?n(t0GgDXf%k4IJUqBncH_{zJ9NTx& z0$JPHl^C6K9L)u<=GkW^;JQHWxZIURxAUk63 zJ=t~?CbR8lQX4ZVgW3M4uX}^{IkW-%WI6z1VE&bVWfj9pT46Q*?DkPBV4H>3%mg3z zf7(ihs14rd(gyGo>m(Q-aiJ@Ky*HGd?)8NYj$KVzblNUo(+2NzY6JKMbP&YA8jR0u zdqlSaH0ucbX44S2==(|=y3el-;1|;gFb39s-Z5&$>BhE?)T6)3+^Ih_#tq)r(FX7f z>m(Q-fobfcQ#RYjif#d)vtYU6fLq$oeNAluzllzSvD!b<&slm@D&iI^D^7vshVJWY z1NaSf0~mM8SNnUEZV9iIb-pca=)RXWfImPdPU4*%yAt2kJwdhlRp*vAbl+DSz#phP z1No?)#W~;1)v`8lKSvwDTdxM>M`#0g>n8f|qX)3{cqsr(LYdpYGLUZ$!wuZ6p$*_I zDF=xrm{r?ngYsPmOR#oVV=-0C=1w$Gr-GAQT4B+4~e9wnssXDLN-?Eh-MvEVtLrRvlNveV> z6iA8(rqOd?0L^~<_@V!ES^g6r*=#nmxRmEEd!B5!+x^IW7c0L7fDm}5PGBAj#}st$ z^UY?n=Wo9Qkc$BTq211Lo>g)0zGzt`>AihpFI^6dF9Q&Qv(C}Zi{Jc=1R>QI{0+x5 z{I^Sz{3NiXf%3(j}#__f`ucut$m z=46#P34lWQ9O-pCHvJ6%TZ3f~2*5i8v0!fy{22hewDV;zE-EN1Z2^U(;Im741nqWjP^y+V{2FKn)~yFcTy#ef-nidi10LaD}5L#3jM7e zUk3nJ0FNHRg1aTfEx3=@4Fs#yvR$94V~IWk!YBX}!mrd>WeZQseWN}o2Fs&w5T+Pl z7QE^U5T^EI?kN)0{@7noYJ6{6?s(}S30A_$)UK%_DaIbpw&7>-nmRi76 zv0wl|5#*Tm27m$1U8~>K4``?k1iJI1U{?jgm@6?a#Y#41Y{XUM`OdU<_{t^Jchr*iy7QPoEs~T7cqET|Yj>eKL<0XB9P-h%s__Tff- z+7bX#SL#oCUfcKV1{qqj&vc; z8N<0$x<0eOBY3T0@Z)0(&H%{wavs3xag`*Y+R^?{1qtwNe9wKjiSJ%%$e_7non%0E zg45jVs8#qorT52jf_Xf~6y^))E}vQ-+&X@!?9YJ(Qz~HElFBrORtx(2ocUEougct1 zY4Ze&Mv?*3Q}n}=Fb|q%jhUP50l)+WnZN|cI$AR!g{QwRKRN<}h2(GZ`0c%Y!@_eA z$Ue7ZGwsj81urA+&+s=}GJzg~_f_t0YV=tumB_H%ZjuI?cE(XFGgMXdI7@_Gh*Sc? z>1YK^CHSerS3u;HJmZt9U(2{JjeC!c74;3mJYLQOCqGur%raQ{jPMm0shXLDtp{xgeP9wy-L6`>t)9D7sX)#FVt=ask20XT$?FN7LB;3pkFQAq#Fz@?NAqKub$QW{1!D&F9N|;H z$NDffFli(YWsVFfX`aF|%i?1%S9t-GBS1D(mUv9)F{@qW04y~7^o%wck$uv3yWM*_ zd`KJPgQR-}g6HDb>Zh)&Ne7u`_cc~HAht(jAQwxsQh4qqNG2TAJyXp7FzNOZ)yq`Q z06l3q?PLJrZ;S;?2}l~_v_%yD2`v{<$&_ku(VlEFSFq5cKo2>ygQSgtJY4X z#VX-5*H896Mtx{4neYIxxSM1U6U?Q<4y($y?leT3AHQ$aop9@W-SM;y=`r#;M=%#i zAC6Q4K?B`mLA5TBD)6dq1Al{FTni)+#f^$Xvi{dcvWpDI6bBJG5hF!ESOd9m!v-dgw@b3Re+J;Ug~e7 zs}@I-1qR_s{VYrxys;6?gF!JeNb zj6CTA>3Z)`83>&;`XvAW!Ny4%1~C4OQ_{+BSNjDM0I9E|xzue2&<$qn@qqg%yx)7) zHo3Iwv*P-c-{$&ZE~bpBfIWb%_gE1206=o&Y5AwJLDK+06{OA{BtQuOg?A|JrK+)= zqJF>MXWiu3;4JV${gJJLy7m!vobJCubb>lZ8JD zzz7HqYu#}h8oNCDZyG-@wNdvMc(2>s=#(HNAepQw1D>-1C_oTCL>74F=+5QpY;JSQ zASzj4AgUw?sm@8(r-VNlfC7ZQhAz;%y4*=ll(<%xf0&T^xyV!nGQsDs#l44#&S(BH zGCSv=qs1R6a@E!oB!vmNZh}mamq;op`=}~7n3jpcte~pbTtz|Sxbx33T9`_yc zd*{e;HUKUs{BMvs0RHA@q#*;SS_w=qdHS#YZ_vdZz*IVg^2{;;QgLqz$ROsO_g?Cs wqhDq~RW9}4;W++p|96-rI=bKdhyOkPHv+x>4op1J82|tP07*qoM6N<$f(ezScK`qY literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_96.dmi b/icons/effects/light_overlays/light_96.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b689a137016322424accea3488b7cd02c6c846ac GIT binary patch literal 4643 zcmV+;65Q>HP)V=-0C=1w$Gr-GAQT4B+4~e9x<^3-4K87XL%lA_yF)-*iP5(>IAa2*)crl z?fAbUlphg50G|8%aBg(Hngh!HSNpqH@54_CWcOVZGyt9JZrhLX9$SFd@gvS3?RZsv zzaY*ofEC~q=)P3g9yJFx?T^mAweJwdSt-cCCy0AHw!^V~jRnKD;CAdMpkKrKwI)lN z2}S)sry$NEfC2ChxbIU4RaqEYnrrqe_64}^x5x2h3CEk8o87sD@Z|yk_#y$~)=+lO$jbKXbWP8y$<=Ww3)rj?w{8a^!m1K+uoARg=( z_b=?+MJ>VSy{eW1nDKV~)%v8>Pp9pRnhW9u%MSN-$Nlz8^L#w_qKnis;io7{sHGZ z>e6$MVVhbnpd|=``&^S1Jf4m{o$e)pJmYz1v4jr^U;zH1=5#}#1?1&v|Jts(wCm{) z+$!{JHVWXSmb4;`f3dY&fdt{X1IPU0&;FzO0FEr2Pc{632Dl z%gT;9HIIC#@!WqpZELOV!)Yz;ubKq#V*8A$sy--$cL`tv_yWnPguq|aUw|c$1NJX! zE|4UEE(}fFUo`5ouW76{^2tCua|5HNPEP##RJB3KA1?pw}1zVbb z70zpsAn7~Q-(&>>zG@!#JKbE?r1=-8?aQiq!2Uzcg{@~kR<^zm3*o&K)Md2<+&P`v z{_Aw^x+Veeyi<}#NGUH+zo_-197R780-Y@dK>E@BDFlIkS#yg}2)nSxtwPu&fF{fJ zD2LSJRCA5>mF-h7`kM<|{5eiR3=tXcYhP4zT@&D>9f7T9-JkABfv`#72OL{OM++cB zTNS`cxJhm%SPriCDFAI#AOv6AOw2|C@XVKvSHO$!pXx90*Yy|d%hUdS&9$DE#`vGl z>)tce7Ax3FL0zoxJg|;BoHD3NEni;J6>qz`3UL)tWxw@zg&# zTlHJo?|#NDpnK17z;$dNvw)_+#%PCeJL7sT0$)ID(Y_0c4%vNx3xF1&fs%$uL2|sJ zIf3uOrG*JluQU0xj;DJ(;~XofLn>OMpf2iRhN=OON<=XP{C8y`{Hi%!F(h?bU|oos zDUg^Xxdkxsdc<=mV6W8HY3*6@=$*qJ+i!jBgb)SLyvJp!!8Mb>3E1B?fllyc5j@6l zl(~VdjFvY_!~_zHZ=|5-nrl93&aG>2_a=CvxvT2mBe;KvZDav!n(yFuPM5&{s;d9h zWFfz6=`$n*f=`<8ez`U>92M|%#JcZ8W#Fr_aMMeh4)oWW>Pos_w1O>BP)fQyNpk9O z;0Zp3KtDh$kajxwvVf|k6V||43%abiAJBan{rH$P&Q7qtu&jNk34Bk`w)ub!B?nr8 zJ5B8~*1~E7AojTpe%dq{?Q5?@6G}| z^6`>G%6bJLX@wT?yXO3_3BUcVjKB_1blL~x~Eea1>r?KS%4M^ z{(yV%-ZLxk8iy_%-g1oiM!E=fQycC6=~HkL;iOET_g_cFwJ} zOBg+1nBh!CA30&q2pL5=qE zI2ZSMe67lHxeylADTUvf38z6&`+ae$@eZ#Q+gOKT$43^h))?zo&8wHv{;QgJTtz#+ z%~Kg$kOQ`rFEF0h zYexy;(bf;xS0w1*Yh0S@qWi0FZ$eme!c}uXx^U04VuJ5Z+l4mDa;xTGCSbdKpu1jU z(pmzztSOUaA7u$X9v?r~n%YA8aY0m_E~W!^pFpRgjMN1oEua%7Cpz79v@=S!wor^( zN_hP51qQQLj*~T`ZXB|7_gxIxwf3njZx)aeFCK0Lx+|UCu)3(^9ejbdk^?N zhArb7Iq0N3vUE?ld~7M)ogKTmx!I*OJaMpdw1cMnz%{@Hk+Q@j=+A=hV@lge0X*2~ z_BCEAn6BB?5}Sl`m7PePccBniZ8P*r+MnY46k(mKjkK_f@)Bi|<2hz3UKd7p)Y?jh z7k2#2jI}C*?zGj>&N;N7ZREVWaC;!sw8rIB)rs_p9EfQ)Gu1RzdJ~+^DAVRs;Z*| z&`HYY!0-X1honKd3BI?AdCs<`Bx#Im5f25{w$2H6b8Y;!9cPB6Sz<|mw2*&6^V!(X zG+rNjI@c*}RJtSp??5`{4@_UBzf>N?+P%FW=WGeAPSKLmjgEEWD(;WM(5^#?2VcT5 z3Ff7igBW%0T&;7AX`CJCYZl-6zoc+gwJb%9I+duT(*#<;XaMem)Xwb-e4MTvouYM% zvq04nuS(l%VW@Y;XNT#-2d()T5U=ssWr;J-*^>5kRO8c8{4-Y{m+wm$jFQ?hIt5W9 zw02G4&6D&wm?VTwgF3(P*_QZsP0PFapng8Fz;ig(vB2D7;P2Xen&_VXhkzgiA zodlFDxuYBB`O!FhE@%QhIptaFrlq{rG-H4rCE#Tp^$zoUTxt~OPHLi3)f~`7jSl#l zH6(xH*6m+XCJIf|>T^Yt^>h|J>vysMY1}IYoveVrI^rg(*<$(v-RB2&b#*pY8XfFW zn7YRM&g-uEu0R^klPzx5q9a*Fa=?o|CJS)QadYK#Y=W)N|2diI(YDuK(0k)Kr=qSU z%}-H|J63|L-;dBX_n++e$e(!>$$nK8Ox+x@Ym0}V?6@KzbxI#WYx^FZeYESkoMA0m z8bvcHx=G+Ct{2b`wG_k?&OJ7N@BYET7j?hk-T8nnOw%GOpk`~{q^51$*F-z~834XZ zuF9ou`JZF;FS)yxBB!MJq77;@_wQ>0+kvM5sEG8DNqH8nqabqszOn{sLaL-rD&jAY za9&OK&X^jaIhqod`m^;l9|xO4W=3&NF%LBdUV?bEW3*xl#2Le_vdRQ8vH(RwDFofu zTmxhU_ccvkN*_XVs!9S(+p?TvWnbZzFmk*}^R>8!bN{}o{%g)r5Gf2N1$m!lZ5Hl@ z-!e$r<37MUBn`SdZF9Lh4eAcp`2gu3y84objVXqA$LbE$pMPilV;}EAKj|a*OyNaq znBm%fri#X7hi2r7l;V0#$JPvLpS+spO!8SNf?GMc6)n!#B_DtV0XH)1oCnMLw=x6Yf;f%0F8hVH1{uZ;@Wm0jGVCx zGbLM$?MXM(_Pd&EzWW75M4k`$vlkBdJ--#<&RF1k2|+>-_&R0@HDN%$HI}N7$ly!>$Qoum!kq}&~1#F@mI%E$&S&r`NKdtsx4Fq6TP&IeJqMoWr z^A!no^JBV;9_nQJH=ujofY@Q?l&=6V+G;WDkuE1aoj3j= z`5*q-N(0XKUz+QZ_ors6!`C$jNc6)JhUXKP)n~*>xL!J8{fE|YkF_U-UYsKZxe%Os zhV)alK>&e@3WKFn77&HwPCZPHo@)M!wt8>iKLMbh#&I7Y3y@!O3-HJ!g^rJd<-X?c z0(g$J(?vZ)>QUQd0Y*htlQ3ijJ8UQIe+k=O%I4>ve1RijsK2BjJwt&32hS*oG(_!v zz}hRL4>kEE9)GcWZz?%-Z7T(-r5kFn=^Q~JPm1rA?P`DtcyYg%G-zddy;)c%3t&zl zC+eXo&yj9e?|1EgH}$A(7C=Kq8gTj=+_}GM0^}M4&^u!#baKF~FF6I#3Yev*Qh-M( z-OH4&0GRkb#r*H09<_H_z&nJ{y_veez6R&NEukcjKLxO>DJ!m;>Q8!B3VEF-2wbuP zuN8HbS5nTWz^{5g1+598o9pTEzv?~GbpOdR*ZQs+%5wUvZS#5BPo-<+3th?EwLTTv zJ_LT%2LzypG(uqMRcmQJ_eDJtf`sQkf+4{5_jJNl%RE5OV6??3#erprs4g=^aw|DX78s%q+t2}0nc(ge!~{vyX;?zrP!dn4vF(S^k> zl%(xnuJvrA?*l&6(7EIkrHx!XG)$GtwD=2^G;hZ<*_3D{$NS~ZwrgMZAGK2({BQZa z9dnxD`SeoX@2lp)z-!p%I&r(xSXF&J@M>Rf0c>HuDXoBJ?`b~kHqvHKo|2WY%IVj1 z_jgCkex`AJX*;V0ur>derfRMPU6$)U!0+P#Ekeapi`s3+-`Y8WSNk>runmOa&UFoV zZ(9YiaI9+I0Xo}{2tX|eLaqBkCS9K_plS)a+G{xW?ZB)3r~teT1hV$7dDJ4XKLxnA Z{{vX6W?B4;ZxR3i002ovPDHLkV1k{4F%AF# literal 0 HcmV?d00001 diff --git a/icons/effects/light_overlays/light_cone.dmi b/icons/effects/light_overlays/light_cone.dmi new file mode 100644 index 0000000000000000000000000000000000000000..75f322a9371748a733958ba34c81728cb2b5bc32 GIT binary patch literal 19272 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 OB?sXAJzG5@bN>P3h2ZZ1 literal 0 HcmV?d00001 diff --git a/icons/effects/lighting_object.dmi b/icons/effects/lighting_object.dmi new file mode 100644 index 0000000000000000000000000000000000000000..4b75e0f6c9ab349fce66aa876e37f3ea214bddb0 GIT binary patch literal 7562 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 C9i%n@ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index 75ba00f026d35529e5182fd9d91b9d6e7f4d488f..00dc3f02a6f6fa15c25b89409692b34cb5ca85d4 100644 GIT binary patch literal 956 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 z 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 diff --git a/vorestation.dme b/vorestation.dme index 4d850a9a724..1e8a6a776cb 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -132,6 +132,7 @@ #include "code\_helpers\global_lists_vr.dm" #include "code\_helpers\icons.dm" #include "code\_helpers\icons_vr.dm" +#include "code\_helpers\lighting.dm" #include "code\_helpers\logging.dm" #include "code\_helpers\logging_vr.dm" #include "code\_helpers\matrices.dm" @@ -296,6 +297,7 @@ #include "code\controllers\subsystems\time_track.dm" #include "code\controllers\subsystems\timer.dm" #include "code\controllers\subsystems\transcore_vr.dm" +#include "code\controllers\subsystems\vis_overlays.dm" #include "code\controllers\subsystems\vote.dm" #include "code\controllers\subsystems\webhooks.dm" #include "code\controllers\subsystems\xenoarch.dm" @@ -351,12 +353,14 @@ #include "code\datums\autolathe\tools_vr.dm" #include "code\datums\components\_component.dm" #include "code\datums\components\material_container.dm" +#include "code\datums\components\overlay_lighting.dm" #include "code\datums\components\resize_guard.dm" #include "code\datums\components\crafting\crafting.dm" #include "code\datums\components\crafting\crafting_external.dm" #include "code\datums\components\crafting\recipes.dm" #include "code\datums\components\crafting\tool_quality.dm" #include "code\datums\elements\_element.dm" +#include "code\datums\elements\light_blocking.dm" #include "code\datums\game_masters\_common.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" @@ -2450,6 +2454,7 @@ #include "code\modules\library\hardcode_library\reference\PortedBooks.dm" #include "code\modules\library\hardcode_library\reference\Schnayy.dm" #include "code\modules\library\hardcode_library\religious\PortedBooks.dm" +#include "code\modules\lighting\emissive_blocker.dm" #include "code\modules\lighting\lighting_area.dm" #include "code\modules\lighting\lighting_atom.dm" #include "code\modules\lighting\lighting_corner.dm" @@ -3332,6 +3337,7 @@ #include "code\modules\persistence\storage\smartfridge.dm" #include "code\modules\persistence\storage\storage.dm" #include "code\modules\planet\planet.dm" +#include "code\modules\planet\sun.dm" #include "code\modules\planet\time.dm" #include "code\modules\planet\virgo3b_vr.dm" #include "code\modules\planet\virgo4_vr.dm"