diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index b54b291843e..ac49c0e3a7f 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -120,6 +120,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define NO_ALERTS (1<<12) /// If blood cultists can draw runes or build structures on this AREA. #define CULT_PERMITTED (1<<13) +///Whther this area is iluminated by starlight +#define AREA_USES_STARLIGHT (1<<14) /* These defines are used specifically with the atom/pass_flags bitmask diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index ff9fd72e99c..fd068074672 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -127,6 +127,11 @@ #define ABOVE_LIGHTING_PLANE 120 #define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE" +#define LIGHTING_PRIMARY_LAYER 15 //The layer for the main lights of the station +#define LIGHTING_PRIMARY_DIMMER_LAYER 15.1 //The layer that dims the main lights of the station +#define LIGHTING_SECONDARY_LAYER 16 //The colourful, usually small lights that go on top + + ///visibility + hiding of things outside of light source range #define BYOND_LIGHTING_PLANE 130 #define BYOND_LIGHTING_RENDER_TARGET "BYOND_LIGHTING_PLANE" diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 9336ac5f789..10b40ea10ca 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -53,17 +53,6 @@ #define LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE 128 #define LIGHTING_PLANE_ALPHA_INVISIBLE 0 -//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 - //code assumes higher numbers override lower numbers. #define LIGHTING_NO_UPDATE 0 diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm index b8707e95304..5bdbbd60186 100644 --- a/code/__HELPERS/areas.dm +++ b/code/__HELPERS/areas.dm @@ -82,7 +82,6 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engineerin return newA = new area_choice newA.setup(str) - newA.set_dynamic_lighting() newA.has_gravity = oldA.has_gravity else newA = area_choice diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 6622d34b840..f4c041e845a 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -65,6 +65,7 @@ DEFINE_BITFIELD(area_flags, list( "VALID_TERRITORY" = VALID_TERRITORY, "XENOBIOLOGY_COMPATIBLE" = XENOBIOLOGY_COMPATIBLE, "NO_ALERTS" = NO_ALERTS, + "AREA_USES_STARLIGHT" = AREA_USES_STARLIGHT, )) DEFINE_BITFIELD(turf_flags, list( diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index f38bea2b1ad..29999a8ff46 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -14,12 +14,6 @@ SUBSYSTEM_DEF(lighting) /datum/controller/subsystem/lighting/Initialize(timeofday) if(!initialized) - if (CONFIG_GET(flag/starlight)) - for(var/I in GLOB.sortedAreas) - var/area/A = I - if (A.dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT) - A.luminosity = 0 - create_all_lighting_objects() initialized = TRUE @@ -57,7 +51,7 @@ SUBSYSTEM_DEF(lighting) 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) diff --git a/code/datums/mapgen/JungleGenerator.dm b/code/datums/mapgen/JungleGenerator.dm index f2536c7d1b5..0a3b3f01399 100644 --- a/code/datums/mapgen/JungleGenerator.dm +++ b/code/datums/mapgen/JungleGenerator.dm @@ -87,5 +87,7 @@ /area/mine/planetgeneration name = "planet generation area" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE map_generator = /datum/map_generator/jungle_generator diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 26631536619..3a7526ec60e 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -150,6 +150,10 @@ GLOBAL_LIST_EMPTY(teleportlocs) icon_state = "" if(!ambientsounds) ambientsounds = GLOB.ambience_assoc[ambience_index] + + if(area_flags & AREA_USES_STARLIGHT) + static_lighting = CONFIG_GET(flag/starlight) + if(requires_power) luminosity = 0 else @@ -157,20 +161,13 @@ GLOBAL_LIST_EMPTY(teleportlocs) power_equip = TRUE power_environ = TRUE - if(dynamic_lighting == DYNAMIC_LIGHTING_FORCED) - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + if(static_lighting) luminosity = 0 - else if(dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT) - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - if(dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT) - dynamic_lighting = CONFIG_GET(flag/starlight) ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED - . = ..() - if(!IS_DYNAMIC_LIGHTING(src)) + if(!static_lighting) blend_mode = BLEND_MULTIPLY - add_overlay(/obj/effect/fullbright) reg_in_areas_in_z() @@ -179,6 +176,8 @@ GLOBAL_LIST_EMPTY(teleportlocs) network_root_id = STATION_NETWORK_ROOT // default to station root because this might be created with a blueprint SSnetworks.assign_area_network_id(src) + update_base_lighting() + return INITIALIZE_HINT_LATELOAD /** diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm index 30cc59cba18..f805e21b999 100644 --- a/code/game/area/areas/away_content.dm +++ b/code/game/area/areas/away_content.dm @@ -15,21 +15,15 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30" /area/awaymission/beach name = "Beach" icon_state = "away" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE requires_power = FALSE has_gravity = STANDARD_GRAVITY ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg','sound/ambience/ambiodd.ogg','sound/ambience/ambinice.ogg') /area/awaymission/errorroom name = "Super Secret Room" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE has_gravity = STANDARD_GRAVITY -/area/awaymission/vr - name = "Virtual Reality" - icon_state = "awaycontent1" - requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED - var/pacifist = TRUE // if when you enter this zone, you become a pacifist or not - var/death = FALSE // if when you enter this zone, you die - network_root_id = "VR" diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm index 52b5b5f330f..b3f06dd1576 100644 --- a/code/game/area/areas/centcom.dm +++ b/code/game/area/areas/centcom.dm @@ -8,7 +8,9 @@ /area/centcom name = "CentCom" icon_state = "centcom" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 requires_power = FALSE has_gravity = STANDARD_GRAVITY area_flags = UNIQUE_AREA | NOTELEPORT @@ -39,7 +41,6 @@ /area/centcom/supplypod name = "Supplypod Facility" icon_state = "supplypod" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED /area/centcom/supplypod/pod_storage name = "Supplypod Storage" @@ -82,7 +83,9 @@ /area/tdome name = "Thunderdome" icon_state = "yellow" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE requires_power = FALSE has_gravity = STANDARD_GRAVITY flags_1 = NONE @@ -90,12 +93,10 @@ /area/tdome/arena name = "Thunderdome Arena" icon_state = "thunder" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED /area/tdome/arena_source name = "Thunderdome Arena Template" icon_state = "thunder" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED /area/tdome/tdome1 name = "Thunderdome (Team 1)" @@ -120,7 +121,9 @@ /area/wizard_station name = "Wizard's Den" icon_state = "yellow" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 requires_power = FALSE has_gravity = STANDARD_GRAVITY area_flags = UNIQUE_AREA | NOTELEPORT @@ -133,6 +136,8 @@ icon_state = "yellow" requires_power = FALSE area_flags = UNIQUE_AREA | NOTELEPORT + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 has_gravity = STANDARD_GRAVITY flags_1 = NONE network_root_id = "ALIENS" @@ -151,7 +156,9 @@ /area/syndicate_mothership/control name = "Syndicate Control Room" icon_state = "syndie-control" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE network_root_id = SYNDICATE_NETWORK_ROOT /area/syndicate_mothership/elite_squad @@ -164,6 +171,9 @@ name = "Capture the Flag" icon_state = "yellow" requires_power = FALSE + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 has_gravity = STANDARD_GRAVITY flags_1 = NONE diff --git a/code/game/area/areas/holodeck.dm b/code/game/area/areas/holodeck.dm index 4b6934799c0..a0a99e81dca 100644 --- a/code/game/area/areas/holodeck.dm +++ b/code/game/area/areas/holodeck.dm @@ -1,7 +1,9 @@ /area/holodeck name = "Holodeck" icon_state = "Holodeck" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 flags_1 = NONE sound_environment = SOUND_ENVIRONMENT_PADDED_CELL diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index 42241bfb118..d4d0c8d9db1 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -5,7 +5,7 @@ icon_state = "away" has_gravity = STANDARD_GRAVITY area_flags = HIDDEN_AREA | BLOBS_ALLOWED | UNIQUE_AREA | NO_ALERTS - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = TRUE ambience_index = AMBIENCE_RUINS flags_1 = CAN_BE_DIRTY_1 sound_environment = SOUND_ENVIRONMENT_STONEROOM diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 35476eb97f6..fadeaa219a5 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -5,7 +5,7 @@ /area/shuttle name = "Shuttle" requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = TRUE has_gravity = STANDARD_GRAVITY always_unpowered = FALSE // Loading the same shuttle map at a different time will produce distinct area instances. @@ -63,7 +63,7 @@ /area/shuttle/hunter name = "Hunter Shuttle" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE ////////////////////////////White Ship//////////////////////////// @@ -97,7 +97,7 @@ /area/shuttle/transit name = "Hyperspace" desc = "Weeeeee" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/shuttle/arrival @@ -167,7 +167,7 @@ name = "Medieval Reality Simulation Dome" icon_state = "shuttlectf" area_flags = NOTELEPORT - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/shuttle/escape/arena name = "The Arena" diff --git a/code/game/area/space_station_13_areas.dm b/code/game/area/space_station_13_areas.dm index 961b0ccd8e6..0de6713a918 100644 --- a/code/game/area/space_station_13_areas.dm +++ b/code/game/area/space_station_13_areas.dm @@ -25,7 +25,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station icon_state = "space" requires_power = TRUE always_unpowered = TRUE - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 power_light = FALSE power_equip = FALSE power_environ = FALSE @@ -37,13 +39,13 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/space/nearstation icon_state = "space_near" - dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT + area_flags = UNIQUE_AREA | NO_ALERTS | AREA_USES_STARLIGHT /area/start name = "start area" icon_state = "start" requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE has_gravity = STANDARD_GRAVITY @@ -68,7 +70,9 @@ NOTE: there are two lists of areas in the end of this file: centcom and station max_ambience_cooldown = 220 SECONDS /area/asteroid/nearstation - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE ambience_index = AMBIENCE_RUINS always_unpowered = FALSE requires_power = TRUE @@ -923,8 +927,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area/solars requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT - area_flags = UNIQUE_AREA + area_flags = UNIQUE_AREA | AREA_USES_STARLIGHT flags_1 = NONE ambience_index = AMBIENCE_ENGI airlock_wires = /datum/wires/airlock/engineering diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 9a3441c9994..ea034dd7611 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -77,7 +77,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( if(flags & CHANGETURF_SKIP) return new path(src) - var/old_dynamic_lighting = dynamic_lighting + var/old_always_lit = always_lit var/old_lighting_object = lighting_object var/old_lighting_corner_NE = lighting_corner_NE var/old_lighting_corner_SE = lighting_corner_SE @@ -137,18 +137,19 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( dynamic_lumcount = old_dynamic_lumcount + if(always_lit != old_always_lit) + if(always_lit) + add_overlay(GLOB.fullbright_overlay) + else + cut_overlay(GLOB.fullbright_overlay) + if(SSlighting.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) + if(lighting_object && !lighting_object.needs_update) lighting_object.update() for(var/turf/open/space/space_tile in RANGE_TURFS(1, src)) diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 559a93af1a1..922bb81577d 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -16,7 +16,7 @@ plane = PLANE_SPACE layer = SPACE_LAYER light_power = 0.25 - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + always_lit = TRUE bullet_bounce_sound = null vis_flags = VIS_INHERIT_ID //when this be added to vis_contents of something it be associated with something on clicking, important for visualisation of turf in openspace and interraction with openspace that show you turf. @@ -28,7 +28,7 @@ /turf/open/space/mirage blocks_air = TRUE light_power = 0 - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + always_lit = TRUE //SKYRAT EDIT END /** @@ -56,9 +56,6 @@ smoothing_flags |= SMOOTH_OBJ SET_BITFLAG_LIST(canSmoothWith) - var/area/A = loc - if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) - add_overlay(/obj/effect/fullbright) if(requires_activation) SSair.add_to_active(src, TRUE) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 39d8447ffd5..efa18f99e86 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -42,7 +42,8 @@ GLOBAL_LIST_EMPTY(station_turfs) ///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component. var/dynamic_lumcount = 0 - var/dynamic_lighting = TRUE + ///Bool, whether this turf will always be illuminated no matter what area it is in + var/always_lit = FALSE var/tmp/lighting_corners_initialised = FALSE @@ -108,9 +109,8 @@ GLOBAL_LIST_EMPTY(station_turfs) for(var/atom/movable/content as anything in src) Entered(content, null) - var/area/A = loc - if(!IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A)) - add_overlay(/obj/effect/fullbright) + if(always_lit) + add_overlay(GLOB.fullbright_overlay) if(requires_activation) CALCULATE_ADJACENT_TURFS(src, KILL_EXCITED) diff --git a/code/modules/awaymissions/mission_code/Cabin.dm b/code/modules/awaymissions/mission_code/Cabin.dm index 7feec49d6d6..c79b6e454f2 100644 --- a/code/modules/awaymissions/mission_code/Cabin.dm +++ b/code/modules/awaymissions/mission_code/Cabin.dm @@ -4,12 +4,12 @@ name = "Cabin" icon_state = "away2" requires_power = TRUE - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE /area/awaymission/cabin/snowforest name = "Snow Forest" icon_state = "away" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/awaymission/cabin/snowforest/sovietsurface name = "Snow Forest" @@ -20,7 +20,7 @@ name = "Lumbermill" icon_state = "away3" requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/awaymission/cabin/caves/sovietcave name = "Soviet Bunker" @@ -29,7 +29,9 @@ /area/awaymission/cabin/caves name = "North Snowdin Caves" icon_state = "awaycontent15" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE /area/awaymission/cabin/caves/mountain name = "North Snowdin Mountains" @@ -41,7 +43,7 @@ icon = 'icons/obj/fireplace.dmi' icon_state = "firepit-active" density = FALSE - var/active = 1 + var/active = TRUE /obj/structure/firepit/Initialize() . = ..() diff --git a/code/modules/awaymissions/mission_code/caves.dm b/code/modules/awaymissions/mission_code/caves.dm index 478f80ca682..28a38cf5c97 100644 --- a/code/modules/awaymissions/mission_code/caves.dm +++ b/code/modules/awaymissions/mission_code/caves.dm @@ -19,7 +19,7 @@ /area/awaymission/caves/research name = "Research Outpost" icon_state = "awaycontent5" - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE /area/awaymission/caves/northblock //engineering, bridge (not really north but it doesnt really need its own APC) diff --git a/code/modules/awaymissions/mission_code/murderdome.dm b/code/modules/awaymissions/mission_code/murderdome.dm index 695692ed331..01eb33179e1 100644 --- a/code/modules/awaymissions/mission_code/murderdome.dm +++ b/code/modules/awaymissions/mission_code/murderdome.dm @@ -1,7 +1,3 @@ -/area/awaymission/vr/murderdome - name = "Murderdome" - icon_state = "awaycontent8" - pacifist = FALSE /obj/structure/window/reinforced/fulltile/indestructable name = "robust window" diff --git a/code/modules/awaymissions/mission_code/research.dm b/code/modules/awaymissions/mission_code/research.dm index 666ee7909e1..a075818ca80 100644 --- a/code/modules/awaymissions/mission_code/research.dm +++ b/code/modules/awaymissions/mission_code/research.dm @@ -3,7 +3,7 @@ /area/awaymission/research name = "Research Outpost" icon_state = "away" - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE /area/awaymission/research/interior name = "Research Inside" diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index f9aa22f913e..d6b2d9fb163 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -4,7 +4,7 @@ name = "Snowdin" icon_state = "awaycontent1" requires_power = FALSE - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/awaymission/snowdin/outside name = "Snowdin Tundra Plains" @@ -14,7 +14,7 @@ name = "Snowdin Outpost" icon_state = "awaycontent2" requires_power = TRUE - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE /area/awaymission/snowdin/post/medbay name = "Snowdin Outpost - Medbay" @@ -96,12 +96,16 @@ /area/awaymission/snowdin/igloo name = "Snowdin Igloos" icon_state = "awaycontent14" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE /area/awaymission/snowdin/cave name = "Snowdin Caves" icon_state = "awaycontent15" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 /area/awaymission/snowdin/cave/cavern name = "Snowdin Depths" @@ -115,18 +119,18 @@ /area/awaymission/snowdin/base name = "Snowdin Main Base" icon_state = "awaycontent16" - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE requires_power = TRUE /area/awaymission/snowdin/dungeon1 name = "Snowdin Depths" icon_state = "awaycontent17" - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE /area/awaymission/snowdin/sekret name = "Snowdin Operations" icon_state = "awaycontent18" - dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + static_lighting = TRUE requires_power = TRUE /area/shuttle/snowdin/elevator1 diff --git a/code/modules/events/aurora_caelus.dm b/code/modules/events/aurora_caelus.dm index a27cda10dff..d065d4c8cbe 100644 --- a/code/modules/events/aurora_caelus.dm +++ b/code/modules/events/aurora_caelus.dm @@ -29,7 +29,7 @@ /datum/round_event/aurora_caelus/start() for(var/area in GLOB.sortedAreas) var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) + if(A.area_flags & AREA_USES_STARLIGHT) for(var/turf/open/space/S in A) S.set_light(S.light_range * 3, S.light_power * 0.5) @@ -39,14 +39,14 @@ var/aurora_color = aurora_colors[aurora_progress] for(var/area in GLOB.sortedAreas) var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) + if(A.area_flags & AREA_USES_STARLIGHT) for(var/turf/open/space/S in A) S.set_light(l_color = aurora_color) /datum/round_event/aurora_caelus/end() for(var/area in GLOB.sortedAreas) var/area/A = area - if(initial(A.dynamic_lighting) == DYNAMIC_LIGHTING_IFSTARLIGHT) + if(A.area_flags & AREA_USES_STARLIGHT) for(var/turf/open/space/S in A) fade_to_black(S) priority_announce("The aurora caelus event is now ending. Starlight conditions will slowly return to normal. When this has concluded, please return to your workplace and continue work as normal. Have a pleasant shift, [station_name()], and thank you for watching with us.", diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm index 497a7e857ed..caf7ed244fd 100644 --- a/code/modules/lighting/lighting_area.dm +++ b/code/modules/lighting/lighting_area.dm @@ -1,32 +1,59 @@ /area - luminosity = TRUE - var/dynamic_lighting = DYNAMIC_LIGHTING_ENABLED + luminosity = 1 + ///The mutable appearance we underlay to show light + var/mutable_appearance/lighting_effect = null + ///Whether this area has a currently active base lighting, bool + var/area_has_base_lighting = FALSE + ///alpha 0-255 of lighting_effect and thus baselighting intensity + var/base_lighting_alpha = 0 + ///The colour of the light acting on this area + var/base_lighting_color = null -/area/proc/set_dynamic_lighting(new_dynamic_lighting = DYNAMIC_LIGHTING_ENABLED) - if (new_dynamic_lighting == dynamic_lighting) +/area/proc/set_base_lighting(new_base_lighting_color = -1, new_alpha = -1) + if(base_lighting_alpha == new_alpha && base_lighting_color == new_base_lighting_color) return FALSE - - dynamic_lighting = new_dynamic_lighting - - if (IS_DYNAMIC_LIGHTING(src)) - cut_overlay(/obj/effect/fullbright) - blend_mode = BLEND_DEFAULT - for (var/turf/T in src) - if (IS_DYNAMIC_LIGHTING(T)) - T.lighting_build_overlay() - - else - add_overlay(/obj/effect/fullbright) - blend_mode = BLEND_MULTIPLY - for (var/turf/T in src) - if (T.lighting_object) - T.lighting_clear_overlay() - + if(new_alpha != -1) + base_lighting_alpha = new_alpha + if(new_base_lighting_color != -1) + base_lighting_color = new_base_lighting_color + update_base_lighting() return TRUE /area/vv_edit_var(var_name, var_value) switch(var_name) - if(NAMEOF(src, dynamic_lighting)) - set_dynamic_lighting(var_value) + if("base_lighting_color") + set_base_lighting(new_base_lighting_color = var_value) + return TRUE + if("base_lighting_alpha") + set_base_lighting(new_alpha = var_value) return TRUE return ..() + +/area/proc/update_base_lighting() + if(!area_has_base_lighting && (!base_lighting_alpha || !base_lighting_color)) + return + + if(!area_has_base_lighting) + add_base_lighting() + return + remove_base_lighting() + if(base_lighting_alpha && base_lighting_color) + add_base_lighting() + +/area/proc/remove_base_lighting() + for(var/turf/T in src) + T.cut_overlay(lighting_effect) + QDEL_NULL(lighting_effect) + area_has_base_lighting = FALSE + +/area/proc/add_base_lighting() + lighting_effect = mutable_appearance('icons/effects/alphacolors.dmi', "white") + lighting_effect.plane = LIGHTING_PLANE + lighting_effect.layer = LIGHTING_PRIMARY_LAYER + lighting_effect.blend_mode = BLEND_ADD + lighting_effect.alpha = base_lighting_alpha + lighting_effect.color = base_lighting_color + for(var/turf/T in src) + T.add_overlay(lighting_effect) + T.luminosity = 1 + area_has_base_lighting = TRUE diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index bc44e863978..78fde88899e 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -1,14 +1,12 @@ /proc/create_all_lighting_objects() for(var/area/A in world) - if(!IS_DYNAMIC_LIGHTING(A)) + if(!A.static_lighting) continue for(var/turf/T in A) - - if(!IS_DYNAMIC_LIGHTING(T)) + if(T.always_lit) continue - new/datum/lighting_object(T) CHECK_TICK CHECK_TICK diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index ebe4b1b6bb3..a4bddc0c433 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -15,7 +15,7 @@ qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death var/area/our_area = loc - if (!IS_DYNAMIC_LIGHTING(our_area) && !light_sources) + if (!our_area.static_lighting && !light_sources) return new/datum/lighting_object(src) @@ -97,11 +97,16 @@ /turf/proc/change_area(area/old_area, area/new_area) if(SSlighting.initialized) - if (new_area.dynamic_lighting != old_area.dynamic_lighting) - if (new_area.dynamic_lighting) + if (new_area.static_lighting != old_area.static_lighting) + if (new_area.static_lighting) lighting_build_overlay() else lighting_clear_overlay() + //Inherit overlay of new area + if(old_area.lighting_effect) + cut_overlay(old_area.lighting_effect) + if(new_area.lighting_effect) + add_overlay(new_area.lighting_effect) /turf/proc/generate_missing_corners() if (!lighting_corner_NE) diff --git a/code/modules/lighting/static_lighting_area.dm b/code/modules/lighting/static_lighting_area.dm new file mode 100644 index 00000000000..150ee669e54 --- /dev/null +++ b/code/modules/lighting/static_lighting_area.dm @@ -0,0 +1,17 @@ + +GLOBAL_DATUM_INIT(fullbright_overlay, /mutable_appearance, create_fullbright_overlay()) + +/proc/create_fullbright_overlay() + var/mutable_appearance/lighting_effect = mutable_appearance('icons/effects/alphacolors.dmi', "white") + lighting_effect.plane = LIGHTING_PLANE + lighting_effect.layer = LIGHTING_PRIMARY_LAYER + lighting_effect.blend_mode = BLEND_ADD + return lighting_effect + +/area + ///Whether this area allows static lighting and thus loads the lighting objects + var/static_lighting = TRUE + +//Non static lighting areas. +//Any lighting area that wont support static lights. +//These areas will NOT have corners generated. diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm index c367acc2a84..a2342847b09 100644 --- a/code/modules/mafia/map_pieces.dm +++ b/code/modules/mafia/map_pieces.dm @@ -29,7 +29,9 @@ /area/mafia name = "Mafia Minigame" icon_state = "mafia" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 requires_power = FALSE has_gravity = STANDARD_GRAVITY flags_1 = NONE diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 93ad499d6c4..467adc11c0a 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -2,7 +2,7 @@ /area/survivalpod name = "\improper Emergency Shelter" icon_state = "away" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = TRUE requires_power = FALSE has_gravity = STANDARD_GRAVITY area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index 2d9234fae6a..5e35bd80d19 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -91,7 +91,9 @@ /area/ai_multicam_room name = "ai_multicam_room" icon_state = "ai_camera_room" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE + base_lighting_color = COLOR_WHITE + base_lighting_alpha = 255 area_flags = NOTELEPORT | HIDDEN_AREA | UNIQUE_AREA ambientsounds = null flags_1 = NONE diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm deleted file mode 100644 index d15b51c4aa3..00000000000 --- a/code/modules/power/lighting.dm +++ /dev/null @@ -1,1274 +0,0 @@ -// The lighting system -// -// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/light) - -#define LIGHT_EMERGENCY_POWER_USE 0.2 //How much power emergency lights will consume per tick -// status values shared between lighting fixtures and items -#define LIGHT_OK 0 -#define LIGHT_EMPTY 1 -#define LIGHT_BROKEN 2 -#define LIGHT_BURNED 3 - -#define BROKEN_SPARKS_MIN (3 MINUTES) -#define BROKEN_SPARKS_MAX (9 MINUTES) - -#define LIGHT_DRAIN_TIME 25 -#define LIGHT_POWER_GAIN 35 - -//How many reagents the lights can hold -#define LIGHT_REAGENT_CAPACITY 5 - -/obj/item/wallframe/light_fixture - name = "light fixture frame" - desc = "Used for building lights." - icon = 'icons/obj/lighting.dmi' - icon_state = "tube-construct-item" - result_path = /obj/structure/light_construct - inverse = TRUE - -/obj/item/wallframe/light_fixture/small - name = "small light fixture frame" - icon_state = "bulb-construct-item" - result_path = /obj/structure/light_construct/small - custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT) - -/obj/item/wallframe/light_fixture/try_build(turf/on_wall, user) - if(!..()) - return - var/area/A = get_area(user) - if(!IS_DYNAMIC_LIGHTING(A)) - to_chat(user, span_warning("You cannot place [src] in this area!")) - return - return TRUE - - -/obj/structure/light_construct - name = "light fixture frame" - desc = "A light fixture under construction." - icon = 'icons/obj/lighting.dmi' - icon_state = "tube-construct-stage1" - anchored = TRUE - layer = WALL_OBJ_LAYER - max_integrity = 200 - armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50) - - var/stage = 1 - var/fixture_type = "tube" - var/sheets_refunded = 2 - var/obj/machinery/light/newlight = null - var/obj/item/stock_parts/cell/cell - - var/cell_connectors = TRUE - -/obj/structure/light_construct/Initialize(mapload, ndir, building) - . = ..() - if(building) - setDir(ndir) - -/obj/structure/light_construct/Destroy() - QDEL_NULL(cell) - return ..() - -/obj/structure/light_construct/get_cell() - return cell - -/obj/structure/light_construct/examine(mob/user) - . = ..() - switch(stage) - if(1) - . += "It's an empty frame." - if(2) - . += "It's wired." - if(3) - . += "The casing is closed." - if(cell_connectors) - if(cell) - . += "You see [cell] inside the casing." - else - . += "The casing has no power cell for backup power." - else - . += span_danger("This casing doesn't support power cells for backup power.") - -/obj/structure/light_construct/attack_hand(mob/user, list/modifiers) - if(cell) - user.visible_message(span_notice("[user] removes [cell] from [src]!"), span_notice("You remove [cell].")) - user.put_in_hands(cell) - cell.update_appearance() - cell = null - add_fingerprint(user) - - -/obj/structure/light_construct/attack_tk(mob/user) - if(!cell) - return - to_chat(user, span_notice("You telekinetically remove [cell].")) - var/obj/item/stock_parts/cell/cell_reference = cell - cell = null - cell_reference.forceMove(drop_location()) - return cell_reference.attack_tk(user) - - -/obj/structure/light_construct/attackby(obj/item/W, mob/user, params) - add_fingerprint(user) - if(istype(W, /obj/item/stock_parts/cell)) - if(!cell_connectors) - to_chat(user, span_warning("This [name] can't support a power cell!")) - return - if(HAS_TRAIT(W, TRAIT_NODROP)) - to_chat(user, span_warning("[W] is stuck to your hand!")) - return - if(cell) - to_chat(user, span_warning("There is a power cell already installed!")) - else if(user.temporarilyRemoveItemFromInventory(W)) - user.visible_message(span_notice("[user] hooks up [W] to [src]."), \ - span_notice("You add [W] to [src].")) - playsound(src, 'sound/machines/click.ogg', 50, TRUE) - W.forceMove(src) - cell = W - add_fingerprint(user) - return - else if (istype(W, /obj/item/light)) - to_chat(user, span_warning("This [name] isn't finished being setup!")) - return - - switch(stage) - if(1) - if(W.tool_behaviour == TOOL_WRENCH) - if(cell) - to_chat(user, span_warning("You have to remove the cell first!")) - return - else - to_chat(user, span_notice("You begin deconstructing [src]...")) - if (W.use_tool(src, user, 30, volume=50)) - new /obj/item/stack/sheet/iron(drop_location(), sheets_refunded) - user.visible_message(span_notice("[user.name] deconstructs [src]."), \ - span_notice("You deconstruct [src]."), span_hear("You hear a ratchet.")) - playsound(src, 'sound/items/deconstruct.ogg', 75, TRUE) - qdel(src) - return - - if(istype(W, /obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/coil = W - if(coil.use(1)) - icon_state = "[fixture_type]-construct-stage2" - stage = 2 - user.visible_message(span_notice("[user.name] adds wires to [src]."), \ - span_notice("You add wires to [src].")) - else - to_chat(user, span_warning("You need one length of cable to wire [src]!")) - return - if(2) - if(W.tool_behaviour == TOOL_WRENCH) - to_chat(usr, span_warning("You have to remove the wires first!")) - return - - if(W.tool_behaviour == TOOL_WIRECUTTER) - stage = 1 - icon_state = "[fixture_type]-construct-stage1" - new /obj/item/stack/cable_coil(drop_location(), 1, "red") - user.visible_message(span_notice("[user.name] removes the wiring from [src]."), \ - span_notice("You remove the wiring from [src]."), span_hear("You hear clicking.")) - W.play_tool_sound(src, 100) - return - - if(W.tool_behaviour == TOOL_SCREWDRIVER) - user.visible_message(span_notice("[user.name] closes [src]'s casing."), \ - span_notice("You close [src]'s casing."), span_hear("You hear screwing.")) - W.play_tool_sound(src, 75) - switch(fixture_type) - if("tube") - newlight = new /obj/machinery/light/built(loc) - if("bulb") - newlight = new /obj/machinery/light/small/built(loc) - newlight.setDir(dir) - transfer_fingerprints_to(newlight) - if(cell) - newlight.cell = cell - cell.forceMove(newlight) - cell = null - qdel(src) - return - return ..() - -/obj/structure/light_construct/blob_act(obj/structure/blob/B) - if(B && B.loc == loc) - qdel(src) - - -/obj/structure/light_construct/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - new /obj/item/stack/sheet/iron(loc, sheets_refunded) - qdel(src) - -/obj/structure/light_construct/small - name = "small light fixture frame" - icon_state = "bulb-construct-stage1" - fixture_type = "bulb" - sheets_refunded = 1 - -// the standard tube light fixture -/obj/machinery/light - name = "light fixture" - icon = 'icons/obj/lighting.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE - var/overlayicon = 'icons/obj/lighting_overlay.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE - var/base_state = "tube" // base description and icon_state - icon_state = "tube" - desc = "A lighting fixture." - layer = WALL_OBJ_LAYER - max_integrity = 100 - use_power = ACTIVE_POWER_USE - idle_power_usage = 2 - active_power_usage = 20 - power_channel = AREA_USAGE_LIGHT //Lights are calc'd via area so they dont need to be in the machine list - var/on = FALSE // 1 if on, 0 if off - var/on_gs = FALSE - var/static_power_used = 0 - var/brightness = 8 // luminosity when on, also used in power calculation - var/bulb_power = 1 // basically the alpha of the emitted light source - var/bulb_colour = "#f3fffa" // befault colour of the light. - var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN - var/flickering = FALSE - var/light_type = /obj/item/light/tube // the type of light item - var/fitting = "tube" - var/switchcount = 0 // count of number of times switched on/off - // this is used to calc the probability the light burns out - - var/rigged = FALSE // true if rigged to explode - - var/obj/item/stock_parts/cell/cell - var/start_with_cell = TRUE // if true, this fixture generates a very weak cell at roundstart - - var/nightshift_enabled = FALSE //Currently in night shift mode? - var/nightshift_allowed = TRUE //Set to FALSE to never let this light get switched to night mode. - var/nightshift_brightness = 8 - var/nightshift_light_power = 0.45 - var/nightshift_light_color = "#FFDDCC" - - var/emergency_mode = FALSE // if true, the light is in emergency mode - var/no_emergency = FALSE // if true, this light cannot ever have an emergency mode - var/bulb_emergency_brightness_mul = 0.25 // multiplier for this light's base brightness in emergency power mode - var/bulb_emergency_colour = "#FF3232" // determines the colour of the light while it's in emergency mode - var/bulb_emergency_pow_mul = 0.75 // the multiplier for determining the light's power in emergency mode - var/bulb_emergency_pow_min = 0.5 // the minimum value for the light's power in emergency mode - -/obj/machinery/light/broken - status = LIGHT_BROKEN - icon_state = "tube-broken" - -/obj/machinery/light/built - icon_state = "tube-empty" - start_with_cell = FALSE - -/obj/machinery/light/built/Initialize() - . = ..() - status = LIGHT_EMPTY - update(0) - -/obj/machinery/light/no_nightlight - nightshift_enabled = FALSE - -/obj/machinery/light/warm - bulb_colour = "#fae5c1" - -/obj/machinery/light/warm/no_nightlight - nightshift_allowed = FALSE - -/obj/machinery/light/cold - bulb_colour = "#deefff" - nightshift_light_color = "#deefff" - -/obj/machinery/light/cold/no_nightlight - nightshift_allowed = FALSE - -/obj/machinery/light/red - bulb_colour = "#FF3232" - nightshift_allowed = FALSE - no_emergency = TRUE - brightness = 2 - bulb_power = 0.7 - -/obj/machinery/light/blacklight - bulb_colour = "#A700FF" - nightshift_allowed = FALSE - brightness = 2 - bulb_power = 0.8 - -/obj/machinery/light/dim - nightshift_allowed = FALSE - bulb_colour = "#FFDDCC" - bulb_power = 0.6 - -// the smaller bulb light fixture - -/obj/machinery/light/small - icon_state = "bulb" - base_state = "bulb" - fitting = "bulb" - brightness = 4 - nightshift_brightness = 4 - bulb_colour = "#FFD6AA" - desc = "A small lighting fixture." - light_type = /obj/item/light/bulb - -/obj/machinery/light/small/broken - status = LIGHT_BROKEN - icon_state = "bulb-broken" - -/obj/machinery/light/small/built - icon_state = "bulb-empty" - start_with_cell = FALSE - -/obj/machinery/light/small/built/Initialize() - . = ..() - status = LIGHT_EMPTY - update(0) - -/obj/machinery/light/small/red - bulb_colour = "#FF3232" - no_emergency = TRUE - nightshift_allowed = FALSE - brightness = 1 - bulb_power = 0.8 - -/obj/machinery/light/small/blacklight - bulb_colour = "#A700FF" - nightshift_allowed = FALSE - brightness = 1 - bulb_power = 0.9 - -/obj/machinery/light/Move() - if(status != LIGHT_BROKEN) - break_light_tube(1) - return ..() - -// create a new lighting fixture -/obj/machinery/light/Initialize(mapload) - . = ..() - - if(!mapload) //sync up nightshift lighting for player made lights - var/area/A = get_area(src) - var/obj/machinery/power/apc/temp_apc = A.get_apc() - nightshift_enabled = temp_apc?.nightshift_lights - - if(start_with_cell && !no_emergency) - cell = new/obj/item/stock_parts/cell/emergency_light(src) - - RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, .proc/on_light_eater) - AddElement(/datum/element/atmos_sensitive, mapload) - return INITIALIZE_HINT_LATELOAD - -/obj/machinery/light/LateInitialize() - . = ..() - switch(fitting) - if("tube") - brightness = 8 - if(prob(2)) - break_light_tube(1) - if("bulb") - brightness = 4 - if(prob(5)) - break_light_tube(1) - addtimer(CALLBACK(src, .proc/update, 0), 1) - -/obj/machinery/light/Destroy() - var/area/A = get_area(src) - if(A) - on = FALSE -// A.update_lights() - QDEL_NULL(cell) - return ..() - -/obj/machinery/light/update_icon_state() - switch(status) // set icon_states - if(LIGHT_OK) - //var/area/A = get_area(src) //SKYRAT EDIT REMOVAL - if(emergency_mode || firealarm) //SKYRAT EDIT CHANGE - icon_state = "[base_state]_emergency" - else - icon_state = "[base_state]" - if(LIGHT_EMPTY) - icon_state = "[base_state]-empty" - if(LIGHT_BURNED) - icon_state = "[base_state]-burned" - if(LIGHT_BROKEN) - icon_state = "[base_state]-broken" - return ..() - -/obj/machinery/light/update_overlays() - . = ..() - if(!on || status != LIGHT_OK) - return - - // var/area/A = get_area(src) SKYRAT EDIT REMOVAL - if(emergency_mode || firealarm) //SKYRAT EDIT CHANGE - . += mutable_appearance(overlayicon, "[base_state]_emergency", layer, plane) - return - if(nightshift_enabled) - . += mutable_appearance(overlayicon, "[base_state]_nightshift", layer, plane) - return - . += mutable_appearance(overlayicon, base_state, layer, plane) - -//SKYRAT EDIT ADDITION BEGIN - AESTHETICS -#define LIGHT_ON_DELAY_UPPER 3 SECONDS -#define LIGHT_ON_DELAY_LOWER 1 SECONDS -//SKYRAT EDIT END - -// update the icon_state and luminosity of the light depending on its state -/obj/machinery/light/proc/update(trigger = TRUE, instant = FALSE, play_sound = TRUE) //SKYRAT EDIT CHANGE - switch(status) - if(LIGHT_BROKEN,LIGHT_BURNED,LIGHT_EMPTY) - on = FALSE - emergency_mode = FALSE - if(on) - /* SKYRAT EDIT ORIGINAL - var/BR = brightness - var/PO = bulb_power - var/CO = bulb_colour - if(color) - CO = color - var/area/A = get_area(src) - if (A?.fire) - CO = bulb_emergency_colour - else if (nightshift_enabled) - BR = nightshift_brightness - PO = nightshift_light_power - if(!color) - CO = nightshift_light_color - var/matching = light && BR == light.light_range && PO == light.light_power && CO == light.light_color - if(!matching) - switchcount++ - if(rigged) - if(status == LIGHT_OK && trigger) - explode() - else if( prob( min(60, (switchcount**2)*0.01) ) ) - if(trigger) - burn_out() - else - use_power = ACTIVE_POWER_USE - set_light(BR, PO, CO) - */ - //SKYRAT EDIT CHANGE BEGIN - AESTHETICS - if(instant) - turn_on(trigger, play_sound) - else if(maploaded) - turn_on(trigger, play_sound) - maploaded = FALSE - else if(!turning_on) - turning_on = TRUE - addtimer(CALLBACK(src, .proc/turn_on, trigger, play_sound), rand(LIGHT_ON_DELAY_LOWER, LIGHT_ON_DELAY_UPPER)) - //SKYRAT EDIT END - else if(has_emergency_power(LIGHT_EMERGENCY_POWER_USE) && !turned_off()) - use_power = IDLE_POWER_USE - emergency_mode = TRUE - START_PROCESSING(SSmachines, src) - else - use_power = IDLE_POWER_USE - set_light(0) - update_appearance() - - active_power_usage = (brightness * 10) - if(on != on_gs) - on_gs = on - if(on) - static_power_used = brightness * 20 //20W per unit luminosity - addStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) - else - removeStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) - - broken_sparks(start_only=TRUE) - -//SKYRAT EDIT ADDITION BEGIN - AESTHETICS -#undef LIGHT_ON_DELAY_UPPER -#undef LIGHT_ON_DELAY_LOWER -//SKYRAT EDIT END - -/obj/machinery/light/update_atom_colour() - ..() - update() - -/obj/machinery/light/proc/broken_sparks(start_only=FALSE) - if(!QDELETED(src) && status == LIGHT_BROKEN && has_power() && Master.current_runlevel) - if(!start_only) - do_sparks(3, TRUE, src) - var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX) - addtimer(CALLBACK(src, .proc/broken_sparks), delay, TIMER_UNIQUE | TIMER_NO_HASH_WAIT) - -/obj/machinery/light/process() - if (!cell) - return PROCESS_KILL - if(has_power()) - if (cell.charge == cell.maxcharge) - return PROCESS_KILL - cell.charge = min(cell.maxcharge, cell.charge + LIGHT_EMERGENCY_POWER_USE) //Recharge emergency power automatically while not using it - if(emergency_mode && !use_emergency_power(LIGHT_EMERGENCY_POWER_USE)) - update(FALSE) //Disables emergency mode and sets the color to normal - -/obj/machinery/light/proc/burn_out() - if(status == LIGHT_OK) - status = LIGHT_BURNED - icon_state = "[base_state]-burned" - on = FALSE - set_light(0) - -// attempt to set the light's on/off status -// will not switch on if broken/burned/empty -/obj/machinery/light/proc/seton(s) - on = (s && status == LIGHT_OK) - update() - -/obj/machinery/light/get_cell() - return cell - -// examine verb -/obj/machinery/light/examine(mob/user) - . = ..() - switch(status) - if(LIGHT_OK) - . += "It is turned [on? "on" : "off"]." - if(LIGHT_EMPTY) - . += "The [fitting] has been removed." - if(LIGHT_BURNED) - . += "The [fitting] is burnt out." - if(LIGHT_BROKEN) - . += "The [fitting] has been smashed." - if(cell) - . += "Its backup power charge meter reads [round((cell.charge / cell.maxcharge) * 100, 0.1)]%." - - //SKYRAT EDIT ADDITION - if(constant_flickering) - . += span_danger("The lighting ballast appears to be damaged, this could be fixed with a multitool.") - //SKYRAT EDIT END - - -// attack with item - insert light (if right type), otherwise try to break the light - -/obj/machinery/light/attackby(obj/item/W, mob/living/user, params) - - //Light replacer code - if(istype(W, /obj/item/lightreplacer)) - var/obj/item/lightreplacer/LR = W - LR.ReplaceLight(src, user) - return //SKYRAT EDIT ADDITION - Fix Light Replacer - - //SKYRAT EDIT ADDITION - if(istype(W, /obj/item/multitool) && constant_flickering) - to_chat(user, span_notice("You start repairing the ballast of [src] with [W].")) - if(do_after(user, 2 SECONDS, src)) - stop_flickering() - to_chat(user, span_notice("You repair the ballast of [src]!")) - return - - //SKYRAT EDTI END - - // attempt to insert light - else if(istype(W, /obj/item/light)) - if(status == LIGHT_OK) - to_chat(user, span_warning("There is a [fitting] already inserted!")) - else - src.add_fingerprint(user) - var/obj/item/light/L = W - if(istype(L, light_type)) - if(!user.temporarilyRemoveItemFromInventory(L)) - return - - src.add_fingerprint(user) - if(status != LIGHT_EMPTY) - drop_light_tube(user) - to_chat(user, span_notice("You replace [L].")) - else - to_chat(user, span_notice("You insert [L].")) - status = L.status - switchcount = L.switchcount - rigged = L.rigged - brightness = L.brightness - on = has_power() - update() - - qdel(L) - - if(on && rigged) - explode() - else - to_chat(user, span_warning("This type of light requires a [fitting]!")) - - // attempt to stick weapon into light socket - else if(status == LIGHT_EMPTY) - if(W.tool_behaviour == TOOL_SCREWDRIVER) //If it's a screwdriver open it. - W.play_tool_sound(src, 75) - user.visible_message(span_notice("[user.name] opens [src]'s casing."), \ - span_notice("You open [src]'s casing."), span_hear("You hear a noise.")) - deconstruct() - else - to_chat(user, span_userdanger("You stick \the [W] into the light socket!")) - if(has_power() && (W.flags_1 & CONDUCT_1)) - do_sparks(3, TRUE, src) - if (prob(75)) - electrocute_mob(user, get_area(src), src, (rand(7,10) * 0.1), TRUE) - else - return ..() - -/obj/machinery/light/deconstruct(disassembled = TRUE) - if(!(flags_1 & NODECONSTRUCT_1)) - var/obj/structure/light_construct/newlight = null - var/cur_stage = 2 - if(!disassembled) - cur_stage = 1 - switch(fitting) - if("tube") - newlight = new /obj/structure/light_construct(src.loc) - newlight.icon_state = "tube-construct-stage[cur_stage]" - - if("bulb") - newlight = new /obj/structure/light_construct/small(src.loc) - newlight.icon_state = "bulb-construct-stage[cur_stage]" - newlight.setDir(src.dir) - newlight.stage = cur_stage - if(!disassembled) - newlight.take_damage(newlight.max_integrity * 0.5, sound_effect=FALSE) - if(status != LIGHT_BROKEN) - break_light_tube() - if(status != LIGHT_EMPTY) - drop_light_tube() - new /obj/item/stack/cable_coil(loc, 1, "red") - transfer_fingerprints_to(newlight) - if(!QDELETED(cell)) - newlight.cell = cell - cell.forceMove(newlight) - cell = null - qdel(src) - -/obj/machinery/light/attacked_by(obj/item/I, mob/living/user) - ..() - if(status == LIGHT_BROKEN || status == LIGHT_EMPTY) - if(on && (I.flags_1 & CONDUCT_1)) - if(prob(12)) - electrocute_mob(user, get_area(src), src, 0.3, TRUE) - -/obj/machinery/light/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) - . = ..() - if(. && !QDELETED(src)) - if(prob(damage_amount * 5)) - break_light_tube() - -/obj/machinery/light/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - switch(status) - if(LIGHT_EMPTY) - playsound(loc, 'sound/weapons/smash.ogg', 50, TRUE) - if(LIGHT_BROKEN) - playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, TRUE) - else - playsound(loc, 'sound/effects/glasshit.ogg', 90, TRUE) - if(BURN) - playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE) - -// returns if the light has power /but/ is manually turned off -// if a light is turned off, it won't activate emergency power -/obj/machinery/light/proc/turned_off() - var/area/A = get_area(src) - return !A.lightswitch && A.power_light || flickering || constant_flickering //SKYRAT EDIT CHANGE - -// returns whether this light has power -// true if area has power and lightswitch is on -/obj/machinery/light/proc/has_power() - var/area/A = get_area(src) - //SKYRAT EDIT ADDITION BEGIN - if(isnull(A)) - return FALSE - //SKYRAT EDIT END - return A.lightswitch && A.power_light - -// returns whether this light has emergency power -// can also return if it has access to a certain amount of that power -/obj/machinery/light/proc/has_emergency_power(pwr) - if(no_emergency || !cell) - return FALSE - if(pwr ? cell.charge >= pwr : cell.charge) - return status == LIGHT_OK - -// attempts to use power from the installed emergency cell, returns true if it does and false if it doesn't -/obj/machinery/light/proc/use_emergency_power(pwr = LIGHT_EMERGENCY_POWER_USE) - if(!has_emergency_power(pwr)) - return FALSE - if(cell.charge > 300) //it's meant to handle 120 W, ya doofus - visible_message(span_warning("[src] short-circuits from too powerful of a power cell!")) - burn_out() - return FALSE - cell.use(pwr) - set_light(brightness * bulb_emergency_brightness_mul, max(bulb_emergency_pow_min, bulb_emergency_pow_mul * (cell.charge / cell.maxcharge)), bulb_emergency_colour) - return TRUE - - -/obj/machinery/light/proc/flicker(amount = rand(10, 20)) - set waitfor = FALSE - if(flickering) - return - flickering = TRUE - if(on && status == LIGHT_OK) - for(var/i = 0; i < amount; i++) - if(status != LIGHT_OK) - break - on = !on - update(FALSE, TRUE) //SKYRAT EDIT CHANGE - sleep(rand(5, 15)) - on = (status == LIGHT_OK) - update(FALSE, TRUE) //SKYRAT EDIT CHANGE - flickering = FALSE - -// ai attack - make lights flicker, because why not - -/obj/machinery/light/attack_ai(mob/user) - no_emergency = !no_emergency - to_chat(user, span_notice("Emergency lights for this fixture have been [no_emergency ? "disabled" : "enabled"].")) - update(FALSE) - return - -// attack with hand - remove tube/bulb -// if hands aren't protected and the light is on, burn the player - -/obj/machinery/light/attack_hand(mob/living/carbon/human/user, list/modifiers) - . = ..() - if(.) - return - user.changeNext_move(CLICK_CD_MELEE) - add_fingerprint(user) - - if(status == LIGHT_EMPTY) - to_chat(user, span_warning("There is no [fitting] in this light!")) - return - - // make it burn hands unless you're wearing heat insulated gloves or have the RESISTHEAT/RESISTHEATHANDS traits - if(on) - var/prot = 0 - var/mob/living/carbon/human/H = user - - if(istype(H)) - var/obj/item/organ/stomach/maybe_stomach = H.getorganslot(ORGAN_SLOT_STOMACH) - if(istype(maybe_stomach, /obj/item/organ/stomach/ethereal)) - var/obj/item/organ/stomach/ethereal/stomach = maybe_stomach - if(stomach.drain_time > world.time) - return - to_chat(H, span_notice("You start channeling some power through the [fitting] into your body.")) - stomach.drain_time = world.time + LIGHT_DRAIN_TIME - if(do_after(user, LIGHT_DRAIN_TIME, target = src)) - if(istype(stomach)) - to_chat(H, span_notice("You receive some charge from the [fitting].")) - stomach.adjust_charge(LIGHT_POWER_GAIN) - else - to_chat(H, span_warning("You can't receive charge from the [fitting]!")) - return - - if(H.gloves) - var/obj/item/clothing/gloves/G = H.gloves - if(G.max_heat_protection_temperature) - prot = (G.max_heat_protection_temperature > 360) - else - prot = 1 - - if(prot > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS)) - to_chat(user, span_notice("You remove the light [fitting].")) - else if(istype(user) && user.dna.check_mutation(TK)) - to_chat(user, span_notice("You telekinetically remove the light [fitting].")) - else - var/obj/item/bodypart/affecting = H.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") - if(affecting?.receive_damage( 0, 5 )) // 5 burn damage - H.update_damage_overlays() - if(HAS_TRAIT(user, TRAIT_LIGHTBULB_REMOVER)) - to_chat(user, span_notice("You feel like you're burning, but you can push through.")) - if(!do_after(user, 5 SECONDS, target = src)) - return - if(affecting?.receive_damage( 0, 10 )) // 10 more burn damage - H.update_damage_overlays() - to_chat(user, span_notice("You manage to remove the light [fitting], shattering it in process.")) - break_light_tube() - else - to_chat(user, span_warning("You try to remove the light [fitting], but you burn your hand on it!")) - return - else - to_chat(user, span_notice("You remove the light [fitting].")) - // create a light tube/bulb item and put it in the user's hand - drop_light_tube(user) - -/obj/machinery/light/proc/drop_light_tube(mob/user) - var/obj/item/light/L = new light_type() - L.status = status - L.rigged = rigged - L.brightness = brightness - - // light item inherits the switchcount, then zero it - L.switchcount = switchcount - switchcount = 0 - - L.update() - L.forceMove(loc) - - if(user) //puts it in our active hand - L.add_fingerprint(user) - user.put_in_active_hand(L) - - status = LIGHT_EMPTY - update() - return L - -/obj/machinery/light/attack_tk(mob/user) - if(status == LIGHT_EMPTY) - to_chat(user, span_warning("There is no [fitting] in this light!")) - return - - to_chat(user, span_notice("You telekinetically remove the light [fitting].")) - // create a light tube/bulb item and put it in the user's hand - var/obj/item/light/light_tube = drop_light_tube() - return light_tube.attack_tk(user) - - -// break the light and make sparks if was on - -/obj/machinery/light/proc/break_light_tube(skip_sound_and_sparks = 0) - if(status == LIGHT_EMPTY || status == LIGHT_BROKEN) - return - - if(!skip_sound_and_sparks) - if(status == LIGHT_OK || status == LIGHT_BURNED) - playsound(src.loc, 'sound/effects/glasshit.ogg', 75, TRUE) - if(on) - do_sparks(3, TRUE, src) - status = LIGHT_BROKEN - update() - -/obj/machinery/light/proc/fix() - if(status == LIGHT_OK) - return - status = LIGHT_OK - brightness = initial(brightness) - on = TRUE - update() - -/obj/machinery/light/zap_act(power, zap_flags) - var/explosive = zap_flags & ZAP_MACHINE_EXPLOSIVE - zap_flags &= ~(ZAP_MACHINE_EXPLOSIVE | ZAP_OBJ_DAMAGE) - . = ..() - if(explosive) - explosion(src, flame_range = 5, adminlog = FALSE) - qdel(src) - -// called when area power state changes -/obj/machinery/light/power_change() - SHOULD_CALL_PARENT(FALSE) - var/area/A = get_area(src) - seton(A.lightswitch && A.power_light) - -// called when heated - -/obj/machinery/light/should_atmos_process(datum/gas_mixture/air, exposed_temperature) - return exposed_temperature > 673 - -/obj/machinery/light/atmos_expose(datum/gas_mixture/air, exposed_temperature) - if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C - break_light_tube() - -// explode the light - -/obj/machinery/light/proc/explode() - set waitfor = 0 - break_light_tube() // break it first to give a warning - sleep(2) - explosion(src, light_impact_range = 2, flash_range = -1) - sleep(1) - qdel(src) - -/obj/machinery/light/proc/on_light_eater(obj/machinery/light/source, datum/light_eater) - SIGNAL_HANDLER - . = COMPONENT_BLOCK_LIGHT_EATER - if(status == LIGHT_EMPTY) - return - var/obj/item/light/tube = drop_light_tube() - tube?.burn() - return - -// the light item -// can be tube or bulb subtypes -// will fit into empty /obj/machinery/light of the corresponding type - -/obj/item/light - icon = 'icons/obj/lighting.dmi' - force = 2 - throwforce = 5 - w_class = WEIGHT_CLASS_TINY - var/status = LIGHT_OK // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN - var/base_state - var/switchcount = 0 // number of times switched - custom_materials = list(/datum/material/glass=100) - grind_results = list(/datum/reagent/silicon = 5, /datum/reagent/nitrogen = 10) //Nitrogen is used as a cheaper alternative to argon in incandescent lighbulbs - var/rigged = FALSE // true if rigged to explode - var/brightness = 2 //how much light it gives off - -/obj/item/light/suicide_act(mob/living/carbon/user) - if (status == LIGHT_BROKEN) - user.visible_message(span_suicide("[user] begins to stab [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) - return BRUTELOSS - else - user.visible_message(span_suicide("[user] begins to eat \the [src]! It looks like [user.p_theyre()] not very bright!")) - shatter() - return BRUTELOSS - -/obj/item/light/tube - name = "light tube" - desc = "A replacement light tube." - icon_state = "ltube" - base_state = "ltube" - inhand_icon_state = "c_tube" - brightness = 8 - custom_price = PAYCHECK_EASY * 0.5 - -/obj/item/light/tube/broken - status = LIGHT_BROKEN - -/obj/item/light/bulb - name = "light bulb" - desc = "A replacement light bulb." - icon_state = "lbulb" - base_state = "lbulb" - inhand_icon_state = "contvapour" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - brightness = 4 - custom_price = PAYCHECK_EASY * 0.4 - -/obj/item/light/bulb/broken - status = LIGHT_BROKEN - -/obj/item/light/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) - if(!..()) //not caught by a mob - shatter() - -// update the icon state and description of the light - -/obj/item/light/proc/update() - switch(status) - if(LIGHT_OK) - icon_state = base_state - desc = "A replacement [name]." - if(LIGHT_BURNED) - icon_state = "[base_state]-burned" - desc = "A burnt-out [name]." - if(LIGHT_BROKEN) - icon_state = "[base_state]-broken" - desc = "A broken [name]." - -/obj/item/light/Initialize() - . = ..() - create_reagents(LIGHT_REAGENT_CAPACITY, INJECTABLE | DRAINABLE) - AddComponent(/datum/component/caltrop, min_damage = force) - update() - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = .proc/on_entered, - ) - AddElement(/datum/element/connect_loc, loc_connections) - -/obj/item/light/proc/on_entered(datum/source, atom/movable/AM) - SIGNAL_HANDLER - if(!isliving(AM)) - return - var/mob/living/L = AM - if(!(L.movement_type & (FLYING|FLOATING)) || L.buckled) - playsound(src, 'sound/effects/glass_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 30 : 50, TRUE) - if(status == LIGHT_BURNED || status == LIGHT_OK) - shatter() - -/obj/item/light/create_reagents(max_vol, flags) - . = ..() - RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) - RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) - -/** - * Handles rigging the cell if it contains enough plasma. - */ -/obj/item/light/proc/on_reagent_change(datum/reagents/holder, ...) - SIGNAL_HANDLER - rigged = (reagents.has_reagent(/datum/reagent/toxin/plasma, LIGHT_REAGENT_CAPACITY)) ? TRUE : FALSE //has_reagent returns the reagent datum, we don't want to hold a reference to prevent hard dels - return NONE - -/** - * Handles the reagent holder datum being deleted for some reason. Probably someone making pizza lights. - */ -/obj/item/light/proc/on_reagents_del(datum/reagents/holder) - SIGNAL_HANDLER - UnregisterSignal(holder, list( - COMSIG_PARENT_QDELETING, - COMSIG_REAGENTS_NEW_REAGENT, - COMSIG_REAGENTS_ADD_REAGENT, - COMSIG_REAGENTS_REM_REAGENT, - COMSIG_REAGENTS_DEL_REAGENT, - )) - return NONE - -#undef LIGHT_REAGENT_CAPACITY - -/obj/item/light/attack(mob/living/M, mob/living/user, def_zone) - ..() - shatter() - -/obj/item/light/attack_obj(obj/O, mob/living/user, params) - ..() - shatter() - -/obj/item/light/proc/shatter() - if(status == LIGHT_OK || status == LIGHT_BURNED) - visible_message(span_danger("[src] shatters."),span_hear("You hear a small glass object shatter.")) - status = LIGHT_BROKEN - force = 5 - playsound(src.loc, 'sound/effects/glasshit.ogg', 75, TRUE) - if(rigged) - atmos_spawn_air("plasma=5") //5u of plasma are required to rig a light bulb/tube - update() - - -/obj/machinery/light/floor - name = "floor light" - icon = 'icons/obj/lighting.dmi' - base_state = "floor" // base description and icon_state - icon_state = "floor" - brightness = 4 - layer = 2.5 - light_type = /obj/item/light/bulb - fitting = "bulb" - -// -------- Directional presets -// The directions are backwards on the lights we have now -/obj/machinery/light/directional/north - dir = NORTH - -/obj/machinery/light/directional/south - dir = SOUTH - -/obj/machinery/light/directional/east - dir = EAST - -/obj/machinery/light/directional/west - dir = WEST - -// ---- Broken tube -/obj/machinery/light/broken/directional/north - dir = NORTH - -/obj/machinery/light/broken/directional/south - dir = SOUTH - -/obj/machinery/light/broken/directional/east - dir = EAST - -/obj/machinery/light/broken/directional/west - dir = WEST - -// ---- Tube construct -/obj/structure/light_construct/directional/north - dir = NORTH - -/obj/structure/light_construct/directional/south - dir = SOUTH - -/obj/structure/light_construct/directional/east - dir = EAST - -/obj/structure/light_construct/directional/west - dir = WEST - -// ---- Tube frames -/obj/machinery/light/built/directional/north - dir = NORTH - -/obj/machinery/light/built/directional/south - dir = SOUTH - -/obj/machinery/light/built/directional/east - dir = EAST - -/obj/machinery/light/built/directional/west - dir = WEST - -// ---- No nightlight tubes -/obj/machinery/light/no_nightlight/directional/north - dir = NORTH - -/obj/machinery/light/no_nightlight/directional/south - dir = SOUTH - -/obj/machinery/light/no_nightlight/directional/east - dir = EAST - -/obj/machinery/light/no_nightlight/directional/west - dir = WEST - -// ---- Warm light tubes -/obj/machinery/light/warm/directional/north - dir = NORTH - -/obj/machinery/light/warm/directional/south - dir = SOUTH - -/obj/machinery/light/warm/directional/east - dir = EAST - -/obj/machinery/light/warm/directional/west - dir = WEST - -// ---- No nightlight warm light tubes -/obj/machinery/light/warm/no_nightlight/directional/north - dir = NORTH - -/obj/machinery/light/warm/no_nightlight/directional/south - dir = SOUTH - -/obj/machinery/light/warm/no_nightlight/directional/east - dir = EAST - -/obj/machinery/light/warm/no_nightlight/directional/west - dir = WEST - -// ---- Cold light tubes -/obj/machinery/light/cold/directional/north - dir = NORTH - -/obj/machinery/light/cold/directional/south - dir = SOUTH - -/obj/machinery/light/cold/directional/east - dir = EAST - -/obj/machinery/light/cold/directional/west - dir = WEST - -// ---- No nightlight cold light tubes -/obj/machinery/light/cold/no_nightlight/directional/north - dir = NORTH - -/obj/machinery/light/cold/no_nightlight/directional/south - dir = SOUTH - -/obj/machinery/light/cold/no_nightlight/directional/east - dir = EAST - -/obj/machinery/light/cold/no_nightlight/directional/west - dir = WEST - -// ---- Red tubes -/obj/machinery/light/red/directional/north - dir = NORTH - -/obj/machinery/light/red/directional/south - dir = SOUTH - -/obj/machinery/light/red/directional/east - dir = EAST - -/obj/machinery/light/red/directional/west - dir = WEST - -// ---- Blacklight tubes -/obj/machinery/light/blacklight/directional/north - dir = NORTH - -/obj/machinery/light/blacklight/directional/south - dir = SOUTH - -/obj/machinery/light/blacklight/directional/east - dir = EAST - -/obj/machinery/light/blacklight/directional/west - dir = WEST - -// ---- Dim tubes -/obj/machinery/light/dim/directional/north - dir = NORTH - -/obj/machinery/light/dim/directional/south - dir = SOUTH - -/obj/machinery/light/dim/directional/east - dir = EAST - -/obj/machinery/light/dim/directional/west - dir = WEST - - -// -------- Bulb lights -/obj/machinery/light/small/directional/north - dir = NORTH - -/obj/machinery/light/small/directional/south - dir = SOUTH - -/obj/machinery/light/small/directional/east - dir = EAST - -/obj/machinery/light/small/directional/west - dir = WEST - -// ---- Bulb construct -/obj/structure/light_construct/small/directional/north - dir = NORTH - -/obj/structure/light_construct/small/directional/south - dir = SOUTH - -/obj/structure/light_construct/small/directional/east - dir = EAST - -/obj/structure/light_construct/small/directional/west - dir = WEST - -// ---- Bulb frames -/obj/machinery/light/small/built/directional/north - dir = NORTH - -/obj/machinery/light/small/built/directional/south - dir = SOUTH - -/obj/machinery/light/small/built/directional/east - dir = EAST - -/obj/machinery/light/small/built/directional/west - dir = WEST - -// ---- Broken bulbs -/obj/machinery/light/small/broken/directional/north - dir = NORTH - -/obj/machinery/light/small/broken/directional/south - dir = SOUTH - -/obj/machinery/light/small/broken/directional/east - dir = EAST - -/obj/machinery/light/small/broken/directional/west - dir = WEST - -// ---- Red bulbs -/obj/machinery/light/small/red/directional/north - dir = NORTH - -/obj/machinery/light/small/red/directional/south - dir = SOUTH - -/obj/machinery/light/small/red/directional/east - dir = EAST - -/obj/machinery/light/small/red/directional/west - dir = WEST - -// ---- Blacklight bulbs -/obj/machinery/light/small/blacklight/directional/north - dir = NORTH - -/obj/machinery/light/small/blacklight/directional/south - dir = SOUTH - -/obj/machinery/light/small/blacklight/directional/east - dir = EAST - -/obj/machinery/light/small/blacklight/directional/west - dir = WEST - -#undef LIGHT_DRAIN_TIME -#undef LIGHT_POWER_GAIN diff --git a/code/modules/power/lighting/_light_defines.dm b/code/modules/power/lighting/_light_defines.dm new file mode 100644 index 00000000000..5bc4762db5e --- /dev/null +++ b/code/modules/power/lighting/_light_defines.dm @@ -0,0 +1,25 @@ +///How much power emergency lights will consume per tick +#define LIGHT_EMERGENCY_POWER_USE 0.2 +// status values shared between lighting fixtures and items +#define LIGHT_OK 0 +#define LIGHT_EMPTY 1 +#define LIGHT_BROKEN 2 +#define LIGHT_BURNED 3 + +///Min time for a spark to happen in a broken light +#define BROKEN_SPARKS_MIN (3 MINUTES) +///Max time for a spark to happen in a broken light +#define BROKEN_SPARKS_MAX (9 MINUTES) + +///Amount of time that takes an ethereal to take energy from the lights +#define LIGHT_DRAIN_TIME 2.5 SECONDS +///Amount of charge the ethereal gain after the drain +#define LIGHT_POWER_GAIN 35 + +///How many reagents the lights can hold +#define LIGHT_REAGENT_CAPACITY 5 + +//Status for light constructs +#define LIGHT_CONSTRUCT_EMPTY 1 +#define LIGHT_CONSTRUCT_WIRED 2 +#define LIGHT_CONSTRUCT_CLOSED 3 diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm new file mode 100644 index 00000000000..4d1e0dceff5 --- /dev/null +++ b/code/modules/power/lighting/light.dm @@ -0,0 +1,640 @@ +// the standard tube light fixture +/obj/machinery/light + name = "light fixture" + icon = 'icons/obj/lighting.dmi' + icon_state = "tube" + desc = "A lighting fixture." + layer = WALL_OBJ_LAYER + max_integrity = 100 + use_power = ACTIVE_POWER_USE + idle_power_usage = 2 + active_power_usage = 20 + power_channel = AREA_USAGE_LIGHT //Lights are calc'd via area so they dont need to be in the machine list + ///What overlay the light should use + var/overlay_icon = 'icons/obj/lighting_overlay.dmi' + ///base description and icon_state + var/base_state = "tube" + ///Is the light on? + var/on = FALSE + ///compared to the var/on for static calculations + var/on_gs = FALSE + ///Amount of power used + var/static_power_used = 0 + ///Luminosity when on, also used in power calculation + var/brightness = 8 + ///Basically the alpha of the emitted light source + var/bulb_power = 1 + ///Default colour of the light. + var/bulb_colour = "#f3fffa" + ///LIGHT_OK, _EMPTY, _BURNED or _BROKEN + var/status = LIGHT_OK + ///Should we flicker? + var/flickering = FALSE + ///The type of light item + var/light_type = /obj/item/light/tube + ///String of the light type, used in descriptions and in examine + var/fitting = "tube" + ///Count of number of times switched on/off, this is used to calculate the probability the light burns out + var/switchcount = 0 + ///True if rigged to explode + var/rigged = FALSE + ///Cell reference + var/obj/item/stock_parts/cell/cell + ///If true, this fixture generates a very weak cell at roundstart + var/start_with_cell = TRUE + ///Currently in night shift mode? + var/nightshift_enabled = FALSE + ///Set to FALSE to never let this light get switched to night mode. + var/nightshift_allowed = TRUE + ///Brightness of the nightshift light + var/nightshift_brightness = 8 + ///Alpha of the nightshift light + var/nightshift_light_power = 0.45 + ///Basecolor of the nightshift light + var/nightshift_light_color = "#FFDDCC" + ///If true, the light is in emergency mode + var/emergency_mode = FALSE + ///If true, this light cannot ever have an emergency mode + var/no_emergency = FALSE + ///Multiplier for this light's base brightness in emergency power mode + var/bulb_emergency_brightness_mul = 0.25 + ///Determines the colour of the light while it's in emergency mode + var/bulb_emergency_colour = "#FF3232" + ///The multiplier for determining the light's power in emergency mode + var/bulb_emergency_pow_mul = 0.75 + ///The minimum value for the light's power in emergency mode + var/bulb_emergency_pow_min = 0.5 + +/obj/machinery/light/Move() + if(status != LIGHT_BROKEN) + break_light_tube(TRUE) + return ..() + +// create a new lighting fixture +/obj/machinery/light/Initialize(mapload) + . = ..() + + if(!mapload) //sync up nightshift lighting for player made lights + var/area/local_area = get_area(src) + var/obj/machinery/power/apc/temp_apc = local_area.get_apc() + nightshift_enabled = temp_apc?.nightshift_lights + + if(start_with_cell && !no_emergency) + cell = new/obj/item/stock_parts/cell/emergency_light(src) + + RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, .proc/on_light_eater) + AddElement(/datum/element/atmos_sensitive, mapload) + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/light/LateInitialize() + . = ..() + switch(fitting) + if("tube") + brightness = 8 + if(prob(2)) + break_light_tube(TRUE) + if("bulb") + brightness = 4 + if(prob(5)) + break_light_tube(TRUE) + addtimer(CALLBACK(src, .proc/update, FALSE), 0.1 SECONDS) + +/obj/machinery/light/Destroy() + var/area/local_area = get_area(src) + if(local_area) + on = FALSE + QDEL_NULL(cell) + return ..() + +/obj/machinery/light/update_icon_state() + switch(status) // set icon_states + if(LIGHT_OK) + //var/area/A = get_area(src) //SKYRAT EDIT REMOVAL + if(emergency_mode || firealarm) //SKYRAT EDIT CHANGE + icon_state = "[base_state]_emergency" + else + icon_state = "[base_state]" + if(LIGHT_EMPTY) + icon_state = "[base_state]-empty" + if(LIGHT_BURNED) + icon_state = "[base_state]-burned" + if(LIGHT_BROKEN) + icon_state = "[base_state]-broken" + return ..() + +/obj/machinery/light/update_overlays() + . = ..() + if(!on || status != LIGHT_OK) + return + + // var/area/A = get_area(src) SKYRAT EDIT REMOVAL + if(emergency_mode || firealarm) //SKYRAT EDIT CHANGE + . += mutable_appearance(overlay_icon, "[base_state]_emergency", layer, plane) + return + if(nightshift_enabled) + . += mutable_appearance(overlay_icon, "[base_state]_nightshift", layer, plane) + return + . += mutable_appearance(overlay_icon, base_state, layer, plane) + +//SKYRAT EDIT ADDITION BEGIN - AESTHETICS +#define LIGHT_ON_DELAY_UPPER 3 SECONDS +#define LIGHT_ON_DELAY_LOWER 1 SECONDS +//SKYRAT EDIT END + +// update the icon_state and luminosity of the light depending on its state +/obj/machinery/light/proc/update(trigger = TRUE, instant = FALSE, play_sound = TRUE) //SKYRAT EDIT CHANGE + switch(status) + if(LIGHT_BROKEN,LIGHT_BURNED,LIGHT_EMPTY) + on = FALSE + emergency_mode = FALSE + if(on) + /* SKYRAT EDIT ORIGINAL + var/brightness_set = brightness + var/power_set = bulb_power + var/color_set = bulb_colour + if(color) + color_set = color + var/area/local_area = get_area(src) + if (local_area?.fire) + color_set = bulb_emergency_colour + else if (nightshift_enabled) + brightness_set = nightshift_brightness + power_set = nightshift_light_power + if(!color) + color_set = nightshift_light_color + var/matching = light && brightness_set == light.light_range && power_set == light.light_power && color_set == light.light_color + if(!matching) + switchcount++ + if(rigged) + if(status == LIGHT_OK && trigger) + explode() + else if( prob( min(60, (switchcount**2)*0.01) ) ) + if(trigger) + burn_out() + else + use_power = ACTIVE_POWER_USE + set_light( + l_range = brightness_set, + l_power = power_set, + l_color = color_set + ) + */ + //SKYRAT EDIT CHANGE BEGIN - AESTHETICS + if(instant) + turn_on(trigger, play_sound) + else if(maploaded) + turn_on(trigger, play_sound) + maploaded = FALSE + else if(!turning_on) + turning_on = TRUE + addtimer(CALLBACK(src, .proc/turn_on, trigger, play_sound), rand(LIGHT_ON_DELAY_LOWER, LIGHT_ON_DELAY_UPPER)) + //SKYRAT EDIT END + else if(has_emergency_power(LIGHT_EMERGENCY_POWER_USE) && !turned_off()) + use_power = IDLE_POWER_USE + emergency_mode = TRUE + START_PROCESSING(SSmachines, src) + else + use_power = IDLE_POWER_USE + set_light(l_range = 0) + update_appearance() + + active_power_usage = (brightness * 10) + if(on != on_gs) + on_gs = on + if(on) + static_power_used = brightness * 20 //20W per unit luminosity + addStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) + else + removeStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) + + broken_sparks(start_only=TRUE) + +//SKYRAT EDIT ADDITION BEGIN - AESTHETICS +#undef LIGHT_ON_DELAY_UPPER +#undef LIGHT_ON_DELAY_LOWER +//SKYRAT EDIT END + +/obj/machinery/light/update_atom_colour() + ..() + update() + +/obj/machinery/light/proc/broken_sparks(start_only=FALSE) + if(!QDELETED(src) && status == LIGHT_BROKEN && has_power() && Master.current_runlevel) + if(!start_only) + do_sparks(3, TRUE, src) + var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX) + addtimer(CALLBACK(src, .proc/broken_sparks), delay, TIMER_UNIQUE | TIMER_NO_HASH_WAIT) + +/obj/machinery/light/process() + if (!cell) + return PROCESS_KILL + if(has_power()) + if (cell.charge == cell.maxcharge) + return PROCESS_KILL + cell.charge = min(cell.maxcharge, cell.charge + LIGHT_EMERGENCY_POWER_USE) //Recharge emergency power automatically while not using it + if(emergency_mode && !use_emergency_power(LIGHT_EMERGENCY_POWER_USE)) + update(FALSE) //Disables emergency mode and sets the color to normal + +/obj/machinery/light/proc/burn_out() + if(status == LIGHT_OK) + status = LIGHT_BURNED + icon_state = "[base_state]-burned" + on = FALSE + set_light(l_range = 0) + +// attempt to set the light's on/off status +// will not switch on if broken/burned/empty +/obj/machinery/light/proc/set_on(turn_on) + on = (turn_on && status == LIGHT_OK) + update() + +/obj/machinery/light/get_cell() + return cell + +// examine verb +/obj/machinery/light/examine(mob/user) + . = ..() + switch(status) + if(LIGHT_OK) + . += "It is turned [on? "on" : "off"]." + if(LIGHT_EMPTY) + . += "The [fitting] has been removed." + if(LIGHT_BURNED) + . += "The [fitting] is burnt out." + if(LIGHT_BROKEN) + . += "The [fitting] has been smashed." + if(cell) + . += "Its backup power charge meter reads [round((cell.charge / cell.maxcharge) * 100, 0.1)]%." + //SKYRAT EDIT ADDITION + if(constant_flickering) + . += span_danger("The lighting ballast appears to be damaged, this could be fixed with a multitool.") + //SKYRAT EDIT END + + + +// attack with item - insert light (if right type), otherwise try to break the light + +/obj/machinery/light/attackby(obj/item/tool, mob/living/user, params) + + //Light replacer code + if(istype(tool, /obj/item/lightreplacer)) + var/obj/item/lightreplacer/replacer = tool + replacer.ReplaceLight(src, user) + return + + //SKYRAT EDIT ADDITION + if(istype(tool, /obj/item/multitool) && constant_flickering) + to_chat(user, span_notice("You start repairing the ballast of [src] with [tool].")) + if(do_after(user, 2 SECONDS, src)) + stop_flickering() + to_chat(user, span_notice("You repair the ballast of [src]!")) + return + + //SKYRAT EDTI END + + // attempt to insert light + if(istype(tool, /obj/item/light)) + if(status == LIGHT_OK) + to_chat(user, span_warning("There is a [fitting] already inserted!")) + return + add_fingerprint(user) + var/obj/item/light/light_object = tool + if(!istype(light_object, light_type)) + to_chat(user, span_warning("This type of light requires a [fitting]!")) + return + if(!user.temporarilyRemoveItemFromInventory(light_object)) + return + + add_fingerprint(user) + if(status != LIGHT_EMPTY) + drop_light_tube(user) + to_chat(user, span_notice("You replace [light_object].")) + else + to_chat(user, span_notice("You insert [light_object].")) + status = light_object.status + switchcount = light_object.switchcount + rigged = light_object.rigged + brightness = light_object.brightness + on = has_power() + update() + + qdel(light_object) + + if(on && rigged) + explode() + return + + // attempt to stick weapon into light socket + if(status != LIGHT_EMPTY) + return ..() + if(tool.tool_behaviour == TOOL_SCREWDRIVER) //If it's a screwdriver open it. + tool.play_tool_sound(src, 75) + user.visible_message(span_notice("[user.name] opens [src]'s casing."), \ + span_notice("You open [src]'s casing."), span_hear("You hear a noise.")) + deconstruct() + return + to_chat(user, span_userdanger("You stick \the [tool] into the light socket!")) + if(has_power() && (tool.flags_1 & CONDUCT_1)) + do_sparks(3, TRUE, src) + if (prob(75)) + electrocute_mob(user, get_area(src), src, (rand(7,10) * 0.1), TRUE) + +/obj/machinery/light/deconstruct(disassembled = TRUE) + if(flags_1 & NODECONSTRUCT_1) + qdel(src) + return + var/obj/structure/light_construct/new_light = null + var/current_stage = 2 + if(!disassembled) + current_stage = 1 + switch(fitting) + if("tube") + new_light = new /obj/structure/light_construct(loc) + new_light.icon_state = "tube-construct-stage[current_stage]" + + if("bulb") + new_light = new /obj/structure/light_construct/small(loc) + new_light.icon_state = "bulb-construct-stage[current_stage]" + new_light.setDir(dir) + new_light.stage = current_stage + if(!disassembled) + new_light.take_damage(new_light.max_integrity * 0.5, sound_effect=FALSE) + if(status != LIGHT_BROKEN) + break_light_tube() + if(status != LIGHT_EMPTY) + drop_light_tube() + new /obj/item/stack/cable_coil(loc, 1, "red") + transfer_fingerprints_to(new_light) + if(!QDELETED(cell)) + new_light.cell = cell + cell.forceMove(new_light) + cell = null + qdel(src) + +/obj/machinery/light/attacked_by(obj/item/attacking_object, mob/living/user) + ..() + if(status != LIGHT_BROKEN && status != LIGHT_EMPTY) + return + if(!on || !(attacking_object.flags_1 & CONDUCT_1)) + return + if(prob(12)) + electrocute_mob(user, get_area(src), src, 0.3, TRUE) + +/obj/machinery/light/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) + . = ..() + if(. && !QDELETED(src)) + if(prob(damage_amount * 5)) + break_light_tube() + +/obj/machinery/light/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + switch(damage_type) + if(BRUTE) + switch(status) + if(LIGHT_EMPTY) + playsound(loc, 'sound/weapons/smash.ogg', 50, TRUE) + if(LIGHT_BROKEN) + playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, TRUE) + else + playsound(loc, 'sound/effects/glasshit.ogg', 90, TRUE) + if(BURN) + playsound(loc, 'sound/items/welder.ogg', 100, TRUE) + +// returns if the light has power /but/ is manually turned off +// if a light is turned off, it won't activate emergency power +/obj/machinery/light/proc/turned_off() + var/area/local_area = get_area(src) + return !local_area.lightswitch && local_area.power_light || flickering || constant_flickering //SKYRAT EDIT CHANGE + +// returns whether this light has power +// true if area has power and lightswitch is on +/obj/machinery/light/proc/has_power() + var/area/local_area = get_area(src) + //SKYRAT EDIT ADDITION BEGIN + if(isnull(local_area)) + return FALSE + //SKYRAT EDIT END + return local_area.lightswitch && local_area.power_light + +// returns whether this light has emergency power +// can also return if it has access to a certain amount of that power +/obj/machinery/light/proc/has_emergency_power(power_usage_amount) + if(no_emergency || !cell) + return FALSE + if(power_usage_amount ? cell.charge >= power_usage_amount : cell.charge) + return status == LIGHT_OK + +// attempts to use power from the installed emergency cell, returns true if it does and false if it doesn't +/obj/machinery/light/proc/use_emergency_power(power_usage_amount = LIGHT_EMERGENCY_POWER_USE) + if(!has_emergency_power(power_usage_amount)) + return FALSE + if(cell.charge > 300) //it's meant to handle 120 W, ya doofus + visible_message(span_warning("[src] short-circuits from too powerful of a power cell!")) + burn_out() + return FALSE + cell.use(power_usage_amount) + set_light( + l_range = brightness * bulb_emergency_brightness_mul, + l_power = max(bulb_emergency_pow_min, bulb_emergency_pow_mul * (cell.charge / cell.maxcharge)), + l_color = bulb_emergency_colour + ) + return TRUE + + +/obj/machinery/light/proc/flicker(amount = rand(10, 20)) + set waitfor = FALSE + if(flickering) + return + flickering = TRUE + if(on && status == LIGHT_OK) + for(var/i = 0; i < amount; i++) + if(status != LIGHT_OK) + break + on = !on + update(FALSE, TRUE) //SKYRAT EDIT CHANGE + sleep(rand(5, 15)) + on = (status == LIGHT_OK) + update(FALSE, TRUE) //SKYRAT EDIT CHANGE + flickering = FALSE + +// ai attack - make lights flicker, because why not + +/obj/machinery/light/attack_ai(mob/user) + no_emergency = !no_emergency + to_chat(user, span_notice("Emergency lights for this fixture have been [no_emergency ? "disabled" : "enabled"].")) + update(FALSE) + return + +// attack with hand - remove tube/bulb +// if hands aren't protected and the light is on, burn the player + +/obj/machinery/light/attack_hand(mob/living/carbon/human/user, list/modifiers) + . = ..() + if(.) + return + user.changeNext_move(CLICK_CD_MELEE) + add_fingerprint(user) + + if(status == LIGHT_EMPTY) + to_chat(user, span_warning("There is no [fitting] in this light!")) + return + + // make it burn hands unless you're wearing heat insulated gloves or have the RESISTHEAT/RESISTHEATHANDS traits + if(!on) + to_chat(user, span_notice("You remove the light [fitting].")) + // create a light tube/bulb item and put it in the user's hand + drop_light_tube(user) + return + var/protection_amount = 0 + var/mob/living/carbon/human/electrician = user + + if(istype(electrician)) + var/obj/item/organ/stomach/maybe_stomach = electrician.getorganslot(ORGAN_SLOT_STOMACH) + if(istype(maybe_stomach, /obj/item/organ/stomach/ethereal)) + var/obj/item/organ/stomach/ethereal/stomach = maybe_stomach + if(stomach.drain_time > world.time) + return + to_chat(electrician, span_notice("You start channeling some power through the [fitting] into your body.")) + stomach.drain_time = world.time + LIGHT_DRAIN_TIME + if(do_after(user, LIGHT_DRAIN_TIME, target = src)) + if(istype(stomach)) + to_chat(electrician, span_notice("You receive some charge from the [fitting].")) + stomach.adjust_charge(LIGHT_POWER_GAIN) + else + to_chat(electrician, span_warning("You can't receive charge from the [fitting]!")) + return + + if(electrician.gloves) + var/obj/item/clothing/gloves/electrician_gloves = electrician.gloves + if(electrician_gloves.max_heat_protection_temperature) + protection_amount = (electrician_gloves.max_heat_protection_temperature > 360) + else + protection_amount = 1 + + if(protection_amount > 0 || HAS_TRAIT(user, TRAIT_RESISTHEAT) || HAS_TRAIT(user, TRAIT_RESISTHEATHANDS)) + to_chat(user, span_notice("You remove the light [fitting].")) + else if(istype(user) && user.dna.check_mutation(TK)) + to_chat(user, span_notice("You telekinetically remove the light [fitting].")) + else + var/obj/item/bodypart/affecting = electrician.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") + if(affecting?.receive_damage( 0, 5 )) // 5 burn damage + electrician.update_damage_overlays() + if(HAS_TRAIT(user, TRAIT_LIGHTBULB_REMOVER)) + to_chat(user, span_notice("You feel like you're burning, but you can push through.")) + if(!do_after(user, 5 SECONDS, target = src)) + return + if(affecting?.receive_damage( 0, 10 )) // 10 more burn damage + electrician.update_damage_overlays() + to_chat(user, span_notice("You manage to remove the light [fitting], shattering it in process.")) + break_light_tube() + else + to_chat(user, span_warning("You try to remove the light [fitting], but you burn your hand on it!")) + return + // create a light tube/bulb item and put it in the user's hand + drop_light_tube(user) + +/obj/machinery/light/proc/drop_light_tube(mob/user) + var/obj/item/light/light_object = new light_type() + light_object.status = status + light_object.rigged = rigged + light_object.brightness = brightness + + // light item inherits the switchcount, then zero it + light_object.switchcount = switchcount + switchcount = 0 + + light_object.update() + light_object.forceMove(loc) + + if(user) //puts it in our active hand + light_object.add_fingerprint(user) + user.put_in_active_hand(light_object) + + status = LIGHT_EMPTY + update() + return light_object + +/obj/machinery/light/attack_tk(mob/user) + if(status == LIGHT_EMPTY) + to_chat(user, span_warning("There is no [fitting] in this light!")) + return + + to_chat(user, span_notice("You telekinetically remove the light [fitting].")) + // create a light tube/bulb item and put it in the user's hand + var/obj/item/light/light_tube = drop_light_tube() + return light_tube.attack_tk(user) + +// break the light and make sparks if was on +/obj/machinery/light/proc/break_light_tube(skip_sound_and_sparks = FALSE) + if(status == LIGHT_EMPTY || status == LIGHT_BROKEN) + return + + if(!skip_sound_and_sparks) + if(status == LIGHT_OK || status == LIGHT_BURNED) + playsound(loc, 'sound/effects/glasshit.ogg', 75, TRUE) + if(on) + do_sparks(3, TRUE, src) + status = LIGHT_BROKEN + update() + +/obj/machinery/light/proc/fix() + if(status == LIGHT_OK) + return + status = LIGHT_OK + brightness = initial(brightness) + on = TRUE + update() + +/obj/machinery/light/zap_act(power, zap_flags) + var/explosive = zap_flags & ZAP_MACHINE_EXPLOSIVE + zap_flags &= ~(ZAP_MACHINE_EXPLOSIVE | ZAP_OBJ_DAMAGE) + . = ..() + if(explosive) + explosion(src, flame_range = 5, adminlog = FALSE) + qdel(src) + +// called when area power state changes +/obj/machinery/light/power_change() + SHOULD_CALL_PARENT(FALSE) + var/area/local_area = get_area(src) + set_on(local_area.lightswitch && local_area.power_light) + +// called when heated + +/obj/machinery/light/should_atmos_process(datum/gas_mixture/air, exposed_temperature) + return exposed_temperature > 673 + +/obj/machinery/light/atmos_expose(datum/gas_mixture/air, exposed_temperature) + if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C + break_light_tube() + +// explode the light + +/obj/machinery/light/proc/explode() + set waitfor = 0 + break_light_tube() // break it first to give a warning + sleep(2) + explosion(src, light_impact_range = 2, flash_range = -1) + sleep(1) + qdel(src) + +/obj/machinery/light/proc/on_light_eater(obj/machinery/light/source, datum/light_eater) + SIGNAL_HANDLER + . = COMPONENT_BLOCK_LIGHT_EATER + if(status == LIGHT_EMPTY) + return + var/obj/item/light/tube = drop_light_tube() + tube?.burn() + return + + + + +/obj/machinery/light/floor + name = "floor light" + icon = 'icons/obj/lighting.dmi' + base_state = "floor" // base description and icon_state + icon_state = "floor" + brightness = 4 + layer = 2.5 + light_type = /obj/item/light/bulb + fitting = "bulb" diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm new file mode 100644 index 00000000000..09131ebc9d9 --- /dev/null +++ b/code/modules/power/lighting/light_construct.dm @@ -0,0 +1,166 @@ +/obj/structure/light_construct + name = "light fixture frame" + desc = "A light fixture under construction." + icon = 'icons/obj/lighting.dmi' + icon_state = "tube-construct-stage1" + anchored = TRUE + layer = WALL_OBJ_LAYER + max_integrity = 200 + armor = list(MELEE = 50, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50) + + ///Light construction stage (LIGHT_CONSTRUCT_EMPTY, LIGHT_CONSTRUCT_WIRED, LIGHT_CONSTRUCT_CLOSED) + var/stage = LIGHT_CONSTRUCT_EMPTY + ///Type of fixture for icon state + var/fixture_type = "tube" + ///Amount of sheets gained on deconstruction + var/sheets_refunded = 2 + ///Reference for light object + var/obj/machinery/light/new_light = null + ///Reference for the internal cell + var/obj/item/stock_parts/cell/cell + ///Can we support a cell? + var/cell_connectors = TRUE + +/obj/structure/light_construct/Initialize(mapload, ndir, building) + . = ..() + if(building) + setDir(ndir) + +/obj/structure/light_construct/Destroy() + QDEL_NULL(cell) + return ..() + +/obj/structure/light_construct/get_cell() + return cell + +/obj/structure/light_construct/examine(mob/user) + . = ..() + switch(stage) + if(LIGHT_CONSTRUCT_EMPTY) + . += "It's an empty frame." + if(LIGHT_CONSTRUCT_WIRED) + . += "It's wired." + if(LIGHT_CONSTRUCT_CLOSED) + . += "The casing is closed." + if(cell_connectors) + if(cell) + . += "You see [cell] inside the casing." + else + . += "The casing has no power cell for backup power." + else + . += span_danger("This casing doesn't support power cells for backup power.") + +/obj/structure/light_construct/attack_hand(mob/user, list/modifiers) + if(!cell) + return + user.visible_message(span_notice("[user] removes [cell] from [src]!"), span_notice("You remove [cell].")) + user.put_in_hands(cell) + cell.update_appearance() + cell = null + add_fingerprint(user) + +/obj/structure/light_construct/attack_tk(mob/user) + if(!cell) + return + to_chat(user, span_notice("You telekinetically remove [cell].")) + var/obj/item/stock_parts/cell/cell_reference = cell + cell = null + cell_reference.forceMove(drop_location()) + return cell_reference.attack_tk(user) + +/obj/structure/light_construct/attackby(obj/item/tool, mob/user, params) + add_fingerprint(user) + if(istype(tool, /obj/item/stock_parts/cell)) + if(!cell_connectors) + to_chat(user, span_warning("This [name] can't support a power cell!")) + return + if(HAS_TRAIT(tool, TRAIT_NODROP)) + to_chat(user, span_warning("[tool] is stuck to your hand!")) + return + if(cell) + to_chat(user, span_warning("There is a power cell already installed!")) + return + if(user.temporarilyRemoveItemFromInventory(tool)) + user.visible_message(span_notice("[user] hooks up [tool] to [src]."), \ + span_notice("You add [tool] to [src].")) + playsound(src, 'sound/machines/click.ogg', 50, TRUE) + tool.forceMove(src) + cell = tool + add_fingerprint(user) + return + if(istype(tool, /obj/item/light)) + to_chat(user, span_warning("This [name] isn't finished being setup!")) + return + + switch(stage) + if(LIGHT_CONSTRUCT_EMPTY) + if(tool.tool_behaviour == TOOL_WRENCH) + if(cell) + to_chat(user, span_warning("You have to remove the cell first!")) + return + to_chat(user, span_notice("You begin deconstructing [src]...")) + if (tool.use_tool(src, user, 30, volume=50)) + new /obj/item/stack/sheet/iron(drop_location(), sheets_refunded) + user.visible_message(span_notice("[user.name] deconstructs [src]."), \ + span_notice("You deconstruct [src]."), span_hear("You hear a ratchet.")) + playsound(src, 'sound/items/deconstruct.ogg', 75, TRUE) + qdel(src) + return + + if(istype(tool, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/coil = tool + if(coil.use(1)) + icon_state = "[fixture_type]-construct-stage2" + stage = LIGHT_CONSTRUCT_WIRED + user.visible_message(span_notice("[user.name] adds wires to [src]."), \ + span_notice("You add wires to [src].")) + else + to_chat(user, span_warning("You need one length of cable to wire [src]!")) + return + if(LIGHT_CONSTRUCT_WIRED) + if(tool.tool_behaviour == TOOL_WRENCH) + to_chat(usr, span_warning("You have to remove the wires first!")) + return + + if(tool.tool_behaviour == TOOL_WIRECUTTER) + stage = LIGHT_CONSTRUCT_EMPTY + icon_state = "[fixture_type]-construct-stage1" + new /obj/item/stack/cable_coil(drop_location(), 1, "red") + user.visible_message(span_notice("[user.name] removes the wiring from [src]."), \ + span_notice("You remove the wiring from [src]."), span_hear("You hear clicking.")) + tool.play_tool_sound(src, 100) + return + + if(tool.tool_behaviour == TOOL_SCREWDRIVER) + user.visible_message(span_notice("[user.name] closes [src]'s casing."), \ + span_notice("You close [src]'s casing."), span_hear("You hear screwing.")) + tool.play_tool_sound(src, 75) + switch(fixture_type) + if("tube") + new_light = new /obj/machinery/light/built(loc) + if("bulb") + new_light = new /obj/machinery/light/small/built(loc) + new_light.setDir(dir) + transfer_fingerprints_to(new_light) + if(cell) + new_light.cell = cell + cell.forceMove(new_light) + cell = null + qdel(src) + return + return ..() + +/obj/structure/light_construct/blob_act(obj/structure/blob/attacking_blob) + if(attacking_blob && attacking_blob.loc == loc) + qdel(src) + +/obj/structure/light_construct/deconstruct(disassembled = TRUE) + if(!(flags_1 & NODECONSTRUCT_1)) + new /obj/item/stack/sheet/iron(loc, sheets_refunded) + qdel(src) + +/obj/structure/light_construct/small + name = "small light fixture frame" + icon_state = "bulb-construct-stage1" + fixture_type = "bulb" + sheets_refunded = 1 diff --git a/code/modules/power/lighting/light_items.dm b/code/modules/power/lighting/light_items.dm new file mode 100644 index 00000000000..393a8a18f45 --- /dev/null +++ b/code/modules/power/lighting/light_items.dm @@ -0,0 +1,139 @@ +// the light item +// can be tube or bulb subtypes +// will fit into empty /obj/machinery/light of the corresponding type + +/obj/item/light + icon = 'icons/obj/lighting.dmi' + force = 2 + throwforce = 5 + w_class = WEIGHT_CLASS_TINY + custom_materials = list(/datum/material/glass=100) + grind_results = list(/datum/reagent/silicon = 5, /datum/reagent/nitrogen = 10) //Nitrogen is used as a cheaper alternative to argon in incandescent lighbulbs + ///True if rigged to explode + var/rigged = FALSE + ///How much light it gives off + var/brightness = 2 + ///LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN + var/status = LIGHT_OK + ///Base icon state for each bulb types + var/base_state + ///Number of times switched on and off + var/switchcount = 0 + +/obj/item/light/suicide_act(mob/living/carbon/user) + if (status == LIGHT_BROKEN) + user.visible_message(span_suicide("[user] begins to stab [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) + return BRUTELOSS + else + user.visible_message(span_suicide("[user] begins to eat \the [src]! It looks like [user.p_theyre()] not very bright!")) + shatter() + return BRUTELOSS + +/obj/item/light/tube + name = "light tube" + desc = "A replacement light tube." + icon_state = "ltube" + base_state = "ltube" + inhand_icon_state = "c_tube" + brightness = 8 + custom_price = PAYCHECK_EASY * 0.5 + +/obj/item/light/tube/broken + status = LIGHT_BROKEN + +/obj/item/light/bulb + name = "light bulb" + desc = "A replacement light bulb." + icon_state = "lbulb" + base_state = "lbulb" + inhand_icon_state = "contvapour" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + brightness = 4 + custom_price = PAYCHECK_EASY * 0.4 + +/obj/item/light/bulb/broken + status = LIGHT_BROKEN + +/obj/item/light/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + if(!..()) //not caught by a mob + shatter() + +// update the icon state and description of the light + +/obj/item/light/proc/update() + switch(status) + if(LIGHT_OK) + icon_state = base_state + desc = "A replacement [name]." + if(LIGHT_BURNED) + icon_state = "[base_state]-burned" + desc = "A burnt-out [name]." + if(LIGHT_BROKEN) + icon_state = "[base_state]-broken" + desc = "A broken [name]." + +/obj/item/light/Initialize() + . = ..() + create_reagents(LIGHT_REAGENT_CAPACITY, INJECTABLE | DRAINABLE) + AddComponent(/datum/component/caltrop, min_damage = force) + update() + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = .proc/on_entered, + ) + AddElement(/datum/element/connect_loc, loc_connections) + +/obj/item/light/proc/on_entered(datum/source, atom/movable/moving_atom) + SIGNAL_HANDLER + if(!isliving(moving_atom)) + return + var/mob/living/moving_mob = moving_atom + if(!(moving_mob.movement_type & (FLYING|FLOATING)) || moving_mob.buckled) + playsound(src, 'sound/effects/glass_step.ogg', HAS_TRAIT(moving_mob, TRAIT_LIGHT_STEP) ? 30 : 50, TRUE) + if(status == LIGHT_BURNED || status == LIGHT_OK) + shatter() + +/obj/item/light/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/** + * Handles rigging the cell if it contains enough plasma. + */ +/obj/item/light/proc/on_reagent_change(datum/reagents/holder, ...) + SIGNAL_HANDLER + rigged = (reagents.has_reagent(/datum/reagent/toxin/plasma, LIGHT_REAGENT_CAPACITY)) ? TRUE : FALSE //has_reagent returns the reagent datum, we don't want to hold a reference to prevent hard dels + return NONE + +/** + * Handles the reagent holder datum being deleted for some reason. Probably someone making pizza lights. + */ +/obj/item/light/proc/on_reagents_del(datum/reagents/holder) + SIGNAL_HANDLER + UnregisterSignal(holder, list( + COMSIG_PARENT_QDELETING, + COMSIG_REAGENTS_NEW_REAGENT, + COMSIG_REAGENTS_ADD_REAGENT, + COMSIG_REAGENTS_REM_REAGENT, + COMSIG_REAGENTS_DEL_REAGENT, + )) + return NONE + +/obj/item/light/attack(mob/living/M, mob/living/user, def_zone) + ..() + shatter() + +/obj/item/light/attack_obj(obj/O, mob/living/user, params) + ..() + shatter() + +/obj/item/light/proc/shatter() + if(status == LIGHT_OK || status == LIGHT_BURNED) + visible_message(span_danger("[src] shatters."),span_hear("You hear a small glass object shatter.")) + status = LIGHT_BROKEN + force = 5 + playsound(src.loc, 'sound/effects/glasshit.ogg', 75, TRUE) + if(rigged) + atmos_spawn_air("plasma=5") //5u of plasma are required to rig a light bulb/tube + update() diff --git a/code/modules/power/lighting/light_mapping_helpers.dm b/code/modules/power/lighting/light_mapping_helpers.dm new file mode 100644 index 00000000000..69de3b9368b --- /dev/null +++ b/code/modules/power/lighting/light_mapping_helpers.dm @@ -0,0 +1,320 @@ +/obj/machinery/light/broken + status = LIGHT_BROKEN + icon_state = "tube-broken" + +/obj/machinery/light/built + icon_state = "tube-empty" + start_with_cell = FALSE + +/obj/machinery/light/built/Initialize() + . = ..() + status = LIGHT_EMPTY + update(0) + +/obj/machinery/light/no_nightlight + nightshift_enabled = FALSE + +/obj/machinery/light/warm + bulb_colour = "#fae5c1" + +/obj/machinery/light/warm/no_nightlight + nightshift_allowed = FALSE + +/obj/machinery/light/cold + bulb_colour = "#deefff" + nightshift_light_color = "#deefff" + +/obj/machinery/light/cold/no_nightlight + nightshift_allowed = FALSE + +/obj/machinery/light/red + bulb_colour = "#FF3232" + nightshift_allowed = FALSE + no_emergency = TRUE + brightness = 2 + bulb_power = 0.7 + +/obj/machinery/light/blacklight + bulb_colour = "#A700FF" + nightshift_allowed = FALSE + brightness = 2 + bulb_power = 0.8 + +/obj/machinery/light/dim + nightshift_allowed = FALSE + bulb_colour = "#FFDDCC" + bulb_power = 0.6 + +// the smaller bulb light fixture + +/obj/machinery/light/small + icon_state = "bulb" + base_state = "bulb" + fitting = "bulb" + brightness = 4 + nightshift_brightness = 4 + bulb_colour = "#FFD6AA" + desc = "A small lighting fixture." + light_type = /obj/item/light/bulb + +/obj/machinery/light/small/broken + status = LIGHT_BROKEN + icon_state = "bulb-broken" + +/obj/machinery/light/small/built + icon_state = "bulb-empty" + start_with_cell = FALSE + +/obj/machinery/light/small/built/Initialize() + . = ..() + status = LIGHT_EMPTY + update(0) + +/obj/machinery/light/small/red + bulb_colour = "#FF3232" + no_emergency = TRUE + nightshift_allowed = FALSE + brightness = 1 + bulb_power = 0.8 + +/obj/machinery/light/small/blacklight + bulb_colour = "#A700FF" + nightshift_allowed = FALSE + brightness = 1 + bulb_power = 0.9 + +// -------- Directional presets +// The directions are backwards on the lights we have now +/obj/machinery/light/directional/north + dir = NORTH + +/obj/machinery/light/directional/south + dir = SOUTH + +/obj/machinery/light/directional/east + dir = EAST + +/obj/machinery/light/directional/west + dir = WEST + +// ---- Broken tube +/obj/machinery/light/broken/directional/north + dir = NORTH + +/obj/machinery/light/broken/directional/south + dir = SOUTH + +/obj/machinery/light/broken/directional/east + dir = EAST + +/obj/machinery/light/broken/directional/west + dir = WEST + +// ---- Tube construct +/obj/structure/light_construct/directional/north + dir = NORTH + +/obj/structure/light_construct/directional/south + dir = SOUTH + +/obj/structure/light_construct/directional/east + dir = EAST + +/obj/structure/light_construct/directional/west + dir = WEST + +// ---- Tube frames +/obj/machinery/light/built/directional/north + dir = NORTH + +/obj/machinery/light/built/directional/south + dir = SOUTH + +/obj/machinery/light/built/directional/east + dir = EAST + +/obj/machinery/light/built/directional/west + dir = WEST + +// ---- No nightlight tubes +/obj/machinery/light/no_nightlight/directional/north + dir = NORTH + +/obj/machinery/light/no_nightlight/directional/south + dir = SOUTH + +/obj/machinery/light/no_nightlight/directional/east + dir = EAST + +/obj/machinery/light/no_nightlight/directional/west + dir = WEST + +// ---- Warm light tubes +/obj/machinery/light/warm/directional/north + dir = NORTH + +/obj/machinery/light/warm/directional/south + dir = SOUTH + +/obj/machinery/light/warm/directional/east + dir = EAST + +/obj/machinery/light/warm/directional/west + dir = WEST + +// ---- No nightlight warm light tubes +/obj/machinery/light/warm/no_nightlight/directional/north + dir = NORTH + +/obj/machinery/light/warm/no_nightlight/directional/south + dir = SOUTH + +/obj/machinery/light/warm/no_nightlight/directional/east + dir = EAST + +/obj/machinery/light/warm/no_nightlight/directional/west + dir = WEST + +// ---- Cold light tubes +/obj/machinery/light/cold/directional/north + dir = NORTH + +/obj/machinery/light/cold/directional/south + dir = SOUTH + +/obj/machinery/light/cold/directional/east + dir = EAST + +/obj/machinery/light/cold/directional/west + dir = WEST + +// ---- No nightlight cold light tubes +/obj/machinery/light/cold/no_nightlight/directional/north + dir = NORTH + +/obj/machinery/light/cold/no_nightlight/directional/south + dir = SOUTH + +/obj/machinery/light/cold/no_nightlight/directional/east + dir = EAST + +/obj/machinery/light/cold/no_nightlight/directional/west + dir = WEST + +// ---- Red tubes +/obj/machinery/light/red/directional/north + dir = NORTH + +/obj/machinery/light/red/directional/south + dir = SOUTH + +/obj/machinery/light/red/directional/east + dir = EAST + +/obj/machinery/light/red/directional/west + dir = WEST + +// ---- Blacklight tubes +/obj/machinery/light/blacklight/directional/north + dir = NORTH + +/obj/machinery/light/blacklight/directional/south + dir = SOUTH + +/obj/machinery/light/blacklight/directional/east + dir = EAST + +/obj/machinery/light/blacklight/directional/west + dir = WEST + +// ---- Dim tubes +/obj/machinery/light/dim/directional/north + dir = NORTH + +/obj/machinery/light/dim/directional/south + dir = SOUTH + +/obj/machinery/light/dim/directional/east + dir = EAST + +/obj/machinery/light/dim/directional/west + dir = WEST + + +// -------- Bulb lights +/obj/machinery/light/small/directional/north + dir = NORTH + +/obj/machinery/light/small/directional/south + dir = SOUTH + +/obj/machinery/light/small/directional/east + dir = EAST + +/obj/machinery/light/small/directional/west + dir = WEST + +// ---- Bulb construct +/obj/structure/light_construct/small/directional/north + dir = NORTH + +/obj/structure/light_construct/small/directional/south + dir = SOUTH + +/obj/structure/light_construct/small/directional/east + dir = EAST + +/obj/structure/light_construct/small/directional/west + dir = WEST + +// ---- Bulb frames +/obj/machinery/light/small/built/directional/north + dir = NORTH + +/obj/machinery/light/small/built/directional/south + dir = SOUTH + +/obj/machinery/light/small/built/directional/east + dir = EAST + +/obj/machinery/light/small/built/directional/west + dir = WEST + +// ---- Broken bulbs +/obj/machinery/light/small/broken/directional/north + dir = NORTH + +/obj/machinery/light/small/broken/directional/south + dir = SOUTH + +/obj/machinery/light/small/broken/directional/east + dir = EAST + +/obj/machinery/light/small/broken/directional/west + dir = WEST + +// ---- Red bulbs +/obj/machinery/light/small/red/directional/north + dir = NORTH + +/obj/machinery/light/small/red/directional/south + dir = SOUTH + +/obj/machinery/light/small/red/directional/east + dir = EAST + +/obj/machinery/light/small/red/directional/west + dir = WEST + +// ---- Blacklight bulbs +/obj/machinery/light/small/blacklight/directional/north + dir = NORTH + +/obj/machinery/light/small/blacklight/directional/south + dir = SOUTH + +/obj/machinery/light/small/blacklight/directional/east + dir = EAST + +/obj/machinery/light/small/blacklight/directional/west + dir = WEST diff --git a/code/modules/power/lighting/light_wallframes.dm b/code/modules/power/lighting/light_wallframes.dm new file mode 100644 index 00000000000..653de771652 --- /dev/null +++ b/code/modules/power/lighting/light_wallframes.dm @@ -0,0 +1,22 @@ +/obj/item/wallframe/light_fixture + name = "light fixture frame" + desc = "Used for building lights." + icon = 'icons/obj/lighting.dmi' + icon_state = "tube-construct-item" + result_path = /obj/structure/light_construct + inverse = TRUE + +/obj/item/wallframe/light_fixture/small + name = "small light fixture frame" + icon_state = "bulb-construct-item" + result_path = /obj/structure/light_construct/small + custom_materials = list(/datum/material/iron=MINERAL_MATERIAL_AMOUNT) + +/obj/item/wallframe/light_fixture/try_build(turf/on_wall, user) + if(!..()) + return + var/area/local_area = get_area(user) + if(!local_area.static_lighting) + to_chat(user, span_warning("You cannot place [src] in this area!")) + return + return TRUE diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm index 9bd0cf4eaec..c36cd2f9f30 100644 --- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm @@ -352,7 +352,9 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) requires_power = FALSE has_gravity = TRUE area_flags = NOTELEPORT | HIDDEN_AREA - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE ambientsounds = list('sound/ambience/servicebell.ogg') var/roomnumber = 0 var/obj/item/hilbertshotel/parentSphere diff --git a/modular_skyrat/master_files/code/modules/awaymission/mission_code/black_mesa.dm b/modular_skyrat/master_files/code/modules/awaymission/mission_code/black_mesa.dm index 98698806279..9e7b9a42528 100644 --- a/modular_skyrat/master_files/code/modules/awaymission/mission_code/black_mesa.dm +++ b/modular_skyrat/master_files/code/modules/awaymission/mission_code/black_mesa.dm @@ -3,7 +3,7 @@ /area/awaymission/black_mesa/outside name = "Black Mesa Outside" - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /obj/structure/fluff/server_rack name = "Server Rack" diff --git a/modular_skyrat/modules/advanced_shuttles/code/areas.dm b/modular_skyrat/modules/advanced_shuttles/code/areas.dm index c42777915fe..1791e88b346 100644 --- a/modular_skyrat/modules/advanced_shuttles/code/areas.dm +++ b/modular_skyrat/modules/advanced_shuttles/code/areas.dm @@ -14,17 +14,17 @@ name = "NLV Consign Cockpit" /area/shuttle/escape/no_light - dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT + area_flags = UNIQUE_AREA | NO_ALERTS | AREA_USES_STARLIGHT /area/shuttle/arrival/no_light - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/shuttle/mining/no_light - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/shuttle/supply/no_light - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE /area/shuttle/transport/no_light - dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + static_lighting = FALSE diff --git a/modular_skyrat/modules/aesthetics/lights/code/lighting.dm b/modular_skyrat/modules/aesthetics/lights/code/lighting.dm index fdee83eea2f..df0c5769972 100644 --- a/modular_skyrat/modules/aesthetics/lights/code/lighting.dm +++ b/modular_skyrat/modules/aesthetics/lights/code/lighting.dm @@ -1,6 +1,6 @@ /obj/machinery/light icon = 'modular_skyrat/modules/aesthetics/lights/icons/lighting.dmi' - overlayicon = 'modular_skyrat/modules/aesthetics/lights/icons/lighting_overlay.dmi' + overlay_icon = 'modular_skyrat/modules/aesthetics/lights/icons/lighting_overlay.dmi' var/maploaded = FALSE //So we don't have a lot of stress on startup. var/turning_on = FALSE //More stress stuff. var/constant_flickering = FALSE // Are we always flickering? diff --git a/modular_skyrat/modules/awaymissions_skyrat/mission_code/mothership_astrum.dm b/modular_skyrat/modules/awaymissions_skyrat/mission_code/mothership_astrum.dm index 687fd2ab362..894ceb87427 100644 --- a/modular_skyrat/modules/awaymissions_skyrat/mission_code/mothership_astrum.dm +++ b/modular_skyrat/modules/awaymissions_skyrat/mission_code/mothership_astrum.dm @@ -22,14 +22,16 @@ /area/awaymission/mothership_astrum/deck4 name = "Mothership Astrum Xeno Studies Holodeck" icon_state = "away4" - dynamic_lighting = DYNAMIC_LIGHTING_FORCED + static_lighting = FALSE + base_lighting_alpha = 255 + base_lighting_color = COLOR_WHITE requires_power = FALSE /area/awaymission/mothership_astrum/deck5 name = "Mothership Astrum Beach Holodeck" icon_state = "away5" requires_power = FALSE - dynamic_lighting = FALSE + static_lighting = FALSE //Fluff Notes /obj/item/paper/fluff/awaymissions/astrum1 diff --git a/modular_skyrat/modules/cme/code/cme.dm b/modular_skyrat/modules/cme/code/cme.dm index d69ee8b627c..e3133c9ebd2 100644 --- a/modular_skyrat/modules/cme/code/cme.dm +++ b/modular_skyrat/modules/cme/code/cme.dm @@ -270,7 +270,6 @@ Armageddon is truly going to fuck the station, use it sparingly. /obj/effect/cme/proc/anomalyNeutralize() playsound(src,'sound/weapons/resonator_blast.ogg',100,TRUE) new /obj/effect/particle_effect/smoke/bad(loc) - var/turf/open/T = get_turf(src) color = COLOR_WHITE light_color = COLOR_WHITE neutralized = TRUE diff --git a/tgstation.dme b/tgstation.dme index 3bd63112234..999e006bd6b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2618,6 +2618,7 @@ #include "code\modules\lighting\lighting_setup.dm" #include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" +#include "code\modules\lighting\static_lighting_area.dm" #include "code\modules\mafia\_defines.dm" #include "code\modules\mafia\controller.dm" #include "code\modules\mafia\map_pieces.dm" @@ -3147,7 +3148,6 @@ #include "code\modules\power\floodlight.dm" #include "code\modules\power\generator.dm" #include "code\modules\power\gravitygenerator.dm" -#include "code\modules\power\lighting.dm" #include "code\modules\power\monitor.dm" #include "code\modules\power\multiz.dm" #include "code\modules\power\pipecleaners.dm" @@ -3160,6 +3160,12 @@ #include "code\modules\power\terminal.dm" #include "code\modules\power\tracker.dm" #include "code\modules\power\turbine.dm" +#include "code\modules\power\lighting\_light_defines.dm" +#include "code\modules\power\lighting\light.dm" +#include "code\modules\power\lighting\light_construct.dm" +#include "code\modules\power\lighting\light_items.dm" +#include "code\modules\power\lighting\light_mapping_helpers.dm" +#include "code\modules\power\lighting\light_wallframes.dm" #include "code\modules\power\singularity\boh_tear.dm" #include "code\modules\power\singularity\collector.dm" #include "code\modules\power\singularity\containment_field.dm"