diff --git a/_maps/RandomRuins/SpaceRuins/bigape.dmm b/_maps/RandomRuins/SpaceRuins/bigape.dmm index 09e85e129d9d..973da4e447ca 100644 --- a/_maps/RandomRuins/SpaceRuins/bigape.dmm +++ b/_maps/RandomRuins/SpaceRuins/bigape.dmm @@ -31,7 +31,7 @@ /area/ruin/powered) "g" = ( /obj/item/flashlight/lamp/bananalamp{ - brightness_on = 10 + light_range = 10 }, /obj/structure/table/wood, /obj/structure/fans/tiny/invisible, diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index b7389061fba6..f393e916f481 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -107,8 +107,12 @@ #define RAD_TEXT_LAYER 15.1 -#define ABOVE_LIGHTING_PLANE 16 -#define ABOVE_LIGHTING_LAYER 16 +#define O_LIGHTING_VISUAL_PLANE 16 +#define O_LIGHTING_VISUAL_LAYER 16 +#define O_LIGHTING_VISUAL_RENDER_TARGET "O_LIGHT_VISUAL_PLANE" + +#define ABOVE_LIGHTING_PLANE 17 +#define ABOVE_LIGHTING_LAYER 17 #define ABOVE_LIGHTING_RENDER_TARGET "ABOVE_LIGHTING_PLANE" #define FLOOR_OPENSPACE_PLANE 17 diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 1549afd6c5c8..05b2b9a13013 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -1,3 +1,16 @@ +///Object doesn't use any of the light systems. Should be changed to add a light source to the object. +#define NO_LIGHT_SUPPORT 0 +///Light made with the lighting datums, applying a matrix. +#define STATIC_LIGHT 1 +///Light made by masking the lighting darkness plane. +#define MOVABLE_LIGHT 2 + +///Is a movable light source attached to another movable (its loc), meaning that the lighting component should go one level deeper. +#define LIGHT_ATTACHED (1<<0) + +///This light doesn't affect turf's lumcount calculations. Set to 1<<15 to ignore conflicts +#define LIGHT_NO_LUMCOUNT (1<<15) + //Bay lighting engine shit, not in /code/modules/lighting because BYOND is being shit about it /// frequency, in 1/10ths of a second, of the lighting process #define LIGHTING_INTERVAL 5 diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 28f8d9c72679..0f8f0e07cf2c 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -1,11 +1,20 @@ -// channel numbers for power -#define EQUIP 1 -#define LIGHT 2 -#define ENVIRON 3 -#define TOTAL 4 //for total power used only -#define STATIC_EQUIP 5 -#define STATIC_LIGHT 6 -#define STATIC_ENVIRON 7 +// These are indexes in a list, and indexes for "dynamic" and static channels should be kept contiguous +#define AREA_USAGE_EQUIP 1 +#define AREA_USAGE_LIGHT 2 +#define AREA_USAGE_ENVIRON 3 +#define AREA_USAGE_TOTAL 4 +#define AREA_USAGE_STATIC_EQUIP 5 +#define AREA_USAGE_STATIC_LIGHT 6 +#define AREA_USAGE_STATIC_ENVIRON 7 +#define AREA_USAGE_LEN AREA_USAGE_STATIC_ENVIRON // largest idx +/// Index of the first dynamic usage channel +#define AREA_USAGE_DYNAMIC_START AREA_USAGE_EQUIP +/// Index of the last dynamic usage channel +#define AREA_USAGE_DYNAMIC_END AREA_USAGE_ENVIRON +/// Index of the first static usage channel +#define AREA_USAGE_STATIC_START AREA_USAGE_STATIC_EQUIP +/// Index of the last static usage channel +#define AREA_USAGE_STATIC_END AREA_USAGE_STATIC_ENVIRON //Power use #define NO_POWER_USE 0 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 3928b4630398..d8d983ef20d8 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -381,3 +381,6 @@ ///Define for spawning megafauna instead of a mob for cave gen #define SPAWN_MEGAFAUNA "bluh bluh huge boss" + +///Swarmer flags +#define SWARMER_LIGHT_ON (1<<0) diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 41f08d57c275..b283837a499a 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -76,8 +76,9 @@ /atom/movable/screen/plane_master/lighting/Initialize() . = ..() - filters += filter(type="alpha", render_source=EMISSIVE_RENDER_TARGET, flags=MASK_INVERSE) - filters += filter(type="alpha", render_source=EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags=MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE) + filters += filter(type="alpha", render_source = O_LIGHTING_VISUAL_RENDER_TARGET, flags = MASK_INVERSE) /** * Things placed on this mask the lighting plane. Doesn't render directly. @@ -155,3 +156,11 @@ filters = list() if(istype(mymob) && mymob.client?.prefs?.ambientocclusion) filters += AMBIENT_OCCLUSION + +/atom/movable/screen/plane_master/o_light_visual + name = "overlight light visual plane master" + layer = O_LIGHTING_VISUAL_LAYER + plane = O_LIGHTING_VISUAL_PLANE + render_target = O_LIGHTING_VISUAL_RENDER_TARGET + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + blend_mode = BLEND_MULTIPLY diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 229e8482a839..623520f8e7a0 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -1,17 +1,16 @@ -GLOBAL_LIST_EMPTY(lighting_update_lights) // List of lighting sources queued for update. -GLOBAL_LIST_EMPTY(lighting_update_corners) // List of lighting corners queued for update. -GLOBAL_LIST_EMPTY(lighting_update_objects) // List of lighting objects queued for update. - SUBSYSTEM_DEF(lighting) name = "Lighting" wait = 2 init_order = INIT_ORDER_LIGHTING flags = SS_TICKER + var/static/list/sources_queue = list() // List of lighting sources queued for update. + var/static/list/corners_queue = list() // List of lighting corners queued for update. + var/static/list/objects_queue = list() // List of lighting objects queued for update. loading_points = 6 SECONDS // Yogs -- loading times /datum/controller/subsystem/lighting/stat_entry(msg) - msg = "L:[GLOB.lighting_update_lights.len]|C:[GLOB.lighting_update_corners.len]|O:[GLOB.lighting_update_objects.len]" + msg = "L:[length(sources_queue)]|C:[length(corners_queue)]|O:[length(objects_queue)]" return ..() @@ -34,9 +33,10 @@ SUBSYSTEM_DEF(lighting) MC_SPLIT_TICK_INIT(3) if(!init_tick_checks) MC_SPLIT_TICK + var/list/queue = sources_queue var/i = 0 - for (i in 1 to GLOB.lighting_update_lights.len) - var/datum/light_source/L = GLOB.lighting_update_lights[i] + for (i in 1 to length(queue)) + var/datum/light_source/L = queue[i] L.update_corners() @@ -47,31 +47,34 @@ SUBSYSTEM_DEF(lighting) else if (MC_TICK_CHECK) break if (i) - GLOB.lighting_update_lights.Cut(1, i+1) + queue.Cut(1, i+1) i = 0 if(!init_tick_checks) MC_SPLIT_TICK - for (i in 1 to GLOB.lighting_update_corners.len) - var/datum/lighting_corner/C = GLOB.lighting_update_corners[i] + queue = corners_queue + for (i in 1 to length(queue)) + var/datum/lighting_corner/C = queue[i] + C.needs_update = FALSE //update_objects() can call qdel if the corner is storing no data C.update_objects() - C.needs_update = FALSE + if(init_tick_checks) CHECK_TICK else if (MC_TICK_CHECK) break if (i) - GLOB.lighting_update_corners.Cut(1, i+1) + queue.Cut(1, i+1) i = 0 if(!init_tick_checks) MC_SPLIT_TICK - for (i in 1 to GLOB.lighting_update_objects.len) - var/datum/lighting_object/O = GLOB.lighting_update_objects[i] + queue = objects_queue + for (i in 1 to length(queue)) + var/datum/lighting_object/O = queue[i] if (QDELETED(O)) continue @@ -83,7 +86,7 @@ SUBSYSTEM_DEF(lighting) else if (MC_TICK_CHECK) break if (i) - GLOB.lighting_update_objects.Cut(1, i+1) + queue.Cut(1, i+1) /datum/controller/subsystem/lighting/Recover() diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm new file mode 100644 index 000000000000..0d6a87e48197 --- /dev/null +++ b/code/datums/components/overlay_lighting.dm @@ -0,0 +1,381 @@ +///For switchable lights, is it on and currently emitting light? +#define LIGHTING_ON (1<<0) +///Is the parent attached to something else, its loc? Then we need to keep an eye of this. +#define LIGHTING_ATTACHED (1<<1) + +#define GET_PARENT (parent_attached_to || parent) + +/** + * Movable atom overlay-based lighting component. + * + * * Component works by applying a visual object to the parent target. + * + * * The component tracks the parent's loc to determine the current_holder. + * * The current_holder is either the parent or its loc, whichever is on a turf. If none, then the current_holder is null and the light is not visible. + * + * * Lighting works at its base by applying a dark overlay and "cutting" said darkness with light, adding (possibly colored) transparency. + * * This component uses the visible_mask visual object to apply said light mask on the darkness. + * + * * The main limitation of this system is that it uses a limited number of pre-baked geometrical shapes, but for most uses it does the job. + * + * * Another limitation is for big lights: you only see the light if you see the object emiting it. + * * For small objects this is good (you can't see them behind a wall), but for big ones this quickly becomes prety clumsy. +*/ +/datum/component/overlay_lighting + ///How far the light reaches, float. + var/range = 1 + ///Ceiling of range, integer without decimal entries. + var/lumcount_range = 0 + ///How much this light affects the dynamic_lumcount of turfs. + var/real_lum_power = 0.5 + ///The lum power being used + var/used_lum_power = 0.5 + ///Transparency value. + var/set_alpha = 0 + ///For light sources that can be turned on and off. + var/overlay_lighting_flags = NONE + + ///Cache of the possible light overlays, according to size. + var/static/list/light_overlays = list( + "32" = 'icons/effects/light_overlays/light_32.dmi', + "64" = 'icons/effects/light_overlays/light_64.dmi', + "96" = 'icons/effects/light_overlays/light_96.dmi', + "128" = 'icons/effects/light_overlays/light_128.dmi', + "160" = 'icons/effects/light_overlays/light_160.dmi', + "192" = 'icons/effects/light_overlays/light_192.dmi', + "224" = 'icons/effects/light_overlays/light_224.dmi', + "256" = 'icons/effects/light_overlays/light_256.dmi', + "288" = 'icons/effects/light_overlays/light_288.dmi', + "320" = 'icons/effects/light_overlays/light_320.dmi', + "352" = 'icons/effects/light_overlays/light_352.dmi', + ) + + ///Overlay effect to cut into the darkness and provide light. + var/obj/effect/overlay/light_visible/visible_mask + ///Lazy list to track the turfs being affected by our light, to determine their visibility. + var/list/turf/affected_turfs + ///Movable atom currently holding the light. Parent might be a flashlight, for example, but that might be held by a mob or something else. + var/atom/movable/current_holder + ///Movable atom the parent is attached to. For example, a flashlight into a helmet or gun. We'll need to track the thing the parent is attached to as if it were the parent itself. + var/atom/movable/parent_attached_to + + +/datum/component/overlay_lighting/Initialize(_range, _power, _color, starts_on) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + var/atom/movable/movable_parent = parent + if(movable_parent.light_system != MOVABLE_LIGHT) + stack_trace("[type] added to [parent], with [movable_parent.light_system] value for the light_system var. Use [MOVABLE_LIGHT] instead.") + return COMPONENT_INCOMPATIBLE + + . = ..() + + visible_mask = new() + if(!isnull(_range)) + movable_parent.set_light_range(_range) + set_range(parent, movable_parent.light_range) + if(!isnull(_power)) + movable_parent.set_light_power(_power) + set_power(parent, movable_parent.light_power) + if(!isnull(_color)) + movable_parent.set_light_color(_color) + set_color(parent, movable_parent.light_color) + if(!isnull(starts_on)) + movable_parent.set_light_on(starts_on) + + +/datum/component/overlay_lighting/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved) + RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_RANGE, .proc/set_range) + RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_POWER, .proc/set_power) + RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_COLOR, .proc/set_color) + RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_ON, .proc/on_toggle) + RegisterSignal(parent, COMSIG_ATOM_SET_LIGHT_FLAGS, .proc/on_light_flags_change) + var/atom/movable/movable_parent = parent + if(movable_parent.light_flags & LIGHT_ATTACHED) + overlay_lighting_flags |= LIGHTING_ATTACHED + set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null) + if(movable_parent.light_flags & LIGHT_NO_LUMCOUNT) + overlay_lighting_flags |= LIGHT_NO_LUMCOUNT + set_lum_power(real_lum_power) + check_holder() + if(movable_parent.light_on) + turn_on() + + +/datum/component/overlay_lighting/UnregisterFromParent() + overlay_lighting_flags &= ~LIGHTING_ATTACHED + set_parent_attached_to(null) + set_holder(null) + clean_old_turfs() + UnregisterSignal(parent, list( + COMSIG_MOVABLE_MOVED, + COMSIG_ATOM_SET_LIGHT_RANGE, + COMSIG_ATOM_SET_LIGHT_POWER, + COMSIG_ATOM_SET_LIGHT_COLOR, + COMSIG_ATOM_SET_LIGHT_ON, + COMSIG_ATOM_SET_LIGHT_FLAGS, + )) + if(overlay_lighting_flags & LIGHTING_ON) + turn_off() + return ..() + + +/datum/component/overlay_lighting/Destroy() + set_parent_attached_to(null) + set_holder(null) + clean_old_turfs() + QDEL_NULL(visible_mask) + return ..() + + +///Clears the affected_turfs lazylist, removing from its contents the effects of being near the light. +/datum/component/overlay_lighting/proc/clean_old_turfs() + for(var/turf/lit_turf as anything in affected_turfs) + lit_turf.dynamic_lumcount -= used_lum_power + affected_turfs = null + + +///Populates the affected_turfs lazylist, adding to its contents the effects of being near the light. +/datum/component/overlay_lighting/proc/get_new_turfs() + if(!current_holder) + return + for(var/turf/lit_turf in view(lumcount_range, get_turf(current_holder))) + lit_turf.dynamic_lumcount += used_lum_power + LAZYADD(affected_turfs, lit_turf) + + +///Clears the old affected turfs and populates the new ones. +/datum/component/overlay_lighting/proc/make_luminosity_update() + clean_old_turfs() + if(!isturf(current_holder?.loc)) + return + get_new_turfs() + + +///Adds the luminosity and source for the afected movable atoms to keep track of their visibility. +/datum/component/overlay_lighting/proc/add_dynamic_lumi(atom/movable/affected_movable) + LAZYSET(affected_movable.affected_dynamic_lights, src, lumcount_range + 1) + affected_movable.vis_contents += visible_mask + affected_movable.update_dynamic_luminosity() + + +///Removes the luminosity and source for the afected movable atoms to keep track of their visibility. +/datum/component/overlay_lighting/proc/remove_dynamic_lumi(atom/movable/affected_movable) + LAZYREMOVE(affected_movable.affected_dynamic_lights, src) + affected_movable.vis_contents -= visible_mask + affected_movable.update_dynamic_luminosity() + + +///Called to change the value of parent_attached_to. +/datum/component/overlay_lighting/proc/set_parent_attached_to(atom/movable/new_parent_attached_to) + if(new_parent_attached_to == parent_attached_to) + return + . = parent_attached_to + parent_attached_to = new_parent_attached_to + if(.) + var/atom/movable/old_parent_attached_to = . + UnregisterSignal(old_parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + if(old_parent_attached_to == current_holder) + RegisterSignal(old_parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel) + RegisterSignal(old_parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved) + if(parent_attached_to) + if(parent_attached_to == current_holder) + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + RegisterSignal(parent_attached_to, COMSIG_PARENT_QDELETING, .proc/on_parent_attached_to_qdel) + RegisterSignal(parent_attached_to, COMSIG_MOVABLE_MOVED, .proc/on_parent_attached_to_moved) + check_holder() + + +///Called to change the value of current_holder. +/datum/component/overlay_lighting/proc/set_holder(atom/movable/new_holder) + if(new_holder == current_holder) + return + if(current_holder) + if(current_holder != parent && current_holder != parent_attached_to) + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + if(overlay_lighting_flags & LIGHTING_ON) + remove_dynamic_lumi(current_holder) + current_holder = new_holder + if(new_holder == null) + clean_old_turfs() + return + if(overlay_lighting_flags & LIGHTING_ON) + add_dynamic_lumi(new_holder) + if(new_holder != parent && new_holder != parent_attached_to) + RegisterSignal(new_holder, COMSIG_PARENT_QDELETING, .proc/on_holder_qdel) + RegisterSignal(new_holder, COMSIG_MOVABLE_MOVED, .proc/on_holder_moved) + + +///Used to determine the new valid current_holder from the parent's loc. +/datum/component/overlay_lighting/proc/check_holder() + var/atom/movable/movable_parent = GET_PARENT + if(isturf(movable_parent.loc)) + set_holder(movable_parent) + return + var/atom/inside = movable_parent.loc //Parent's loc + if(isnull(inside)) + set_holder(null) + return + if(isturf(inside.loc)) + set_holder(inside) + return + set_holder(null) + + +///Called when the current_holder is qdeleted, to remove the light effect. +/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force) + UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + set_holder(null) + + +///Called when current_holder changes loc. +/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced) + if(!(overlay_lighting_flags & LIGHTING_ON)) + return + make_luminosity_update() + + +///Called when parent changes loc. +/datum/component/overlay_lighting/proc/on_parent_moved(atom/movable/source, OldLoc, Dir, Forced) + var/atom/movable/movable_parent = parent + if(overlay_lighting_flags & LIGHTING_ATTACHED) + set_parent_attached_to(ismovable(movable_parent.loc) ? movable_parent.loc : null) + check_holder() + if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder) + return + make_luminosity_update() + + +///Called when the current_holder is qdeleted, to remove the light effect. +/datum/component/overlay_lighting/proc/on_parent_attached_to_qdel(atom/movable/source, force) + UnregisterSignal(parent_attached_to, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED)) + if(parent_attached_to == current_holder) + set_holder(null) + set_parent_attached_to(null) + + +///Called when parent_attached_to changes loc. +/datum/component/overlay_lighting/proc/on_parent_attached_to_moved(atom/movable/source, OldLoc, Dir, Forced) + check_holder() + if(!(overlay_lighting_flags & LIGHTING_ON) || !current_holder) + return + make_luminosity_update() + + +///Changes the range which the light reaches. 0 means no light, 6 is the maximum value. +/datum/component/overlay_lighting/proc/set_range(atom/source, new_range) + if(range == new_range) + return + if(range == 0) + turn_off() + range = clamp(CEILING(new_range, 0.5), 1, 6) + var/pixel_bounds = ((range - 1) * 64) + 32 + lumcount_range = CEILING(range, 1) + visible_mask.icon = light_overlays["[pixel_bounds]"] + if(pixel_bounds == 32) + visible_mask.transform = null + return + var/offset = (pixel_bounds - 32) * 0.5 + var/matrix/transform = new + transform.Translate(-offset, -offset) + visible_mask.transform = transform + if(overlay_lighting_flags & LIGHTING_ON) + make_luminosity_update() + + +///Changes the intensity/brightness of the light by altering the visual object's alpha. +/datum/component/overlay_lighting/proc/set_power(atom/source, new_power) + set_lum_power(new_power >= 0 ? 0.5 : -0.5) + set_alpha = min(230, (abs(new_power) * 120) + 30) + visible_mask.alpha = set_alpha + + +///Changes the light's color, pretty straightforward. +/datum/component/overlay_lighting/proc/set_color(atom/source, new_color) + visible_mask.color = new_color + + +///Toggles the light on and off. +/datum/component/overlay_lighting/proc/on_toggle(atom/source, new_value) + if(new_value) //Truthy value input, turn on. + turn_on() + return + turn_off() //Falsey value, turn off. + + +///Triggered right before the parent light flags change. +/datum/component/overlay_lighting/proc/on_light_flags_change(atom/source, new_value) + var/atom/movable/movable_parent = parent + if(new_value & LIGHT_ATTACHED) + if(!(movable_parent.light_flags & LIGHT_ATTACHED)) //Gained the LIGHT_ATTACHED property. + overlay_lighting_flags |= LIGHTING_ATTACHED + if(ismovable(movable_parent.loc)) + set_parent_attached_to(movable_parent.loc) + else if(movable_parent.light_flags & LIGHT_ATTACHED) //Lost the LIGHT_ATTACHED property. + overlay_lighting_flags &= ~LIGHTING_ATTACHED + set_parent_attached_to(null) + + if(new_value & LIGHT_NO_LUMCOUNT) + if(!(movable_parent.light_flags & LIGHT_NO_LUMCOUNT)) //Gained the NO_LUMCOUNT property + overlay_lighting_flags |= LIGHT_NO_LUMCOUNT + //Recalculate affecting + set_lum_power(real_lum_power) + else if(movable_parent.light_flags & LIGHT_NO_LUMCOUNT) //Lost the NO_LUMCOUNT property + overlay_lighting_flags &= ~LIGHT_NO_LUMCOUNT + //Recalculate affecting + set_lum_power(real_lum_power) + + +///Toggles the light on. +/datum/component/overlay_lighting/proc/turn_on() + if(overlay_lighting_flags & LIGHTING_ON) + return + if(current_holder) + add_dynamic_lumi(current_holder) + overlay_lighting_flags |= LIGHTING_ON + get_new_turfs() + + +///Toggles the light off. +/datum/component/overlay_lighting/proc/turn_off() + if(!(overlay_lighting_flags & LIGHTING_ON)) + return + if(current_holder) + remove_dynamic_lumi(current_holder) + overlay_lighting_flags &= ~LIGHTING_ON + clean_old_turfs() + + +///Here we append the behavior associated to changing lum_power. +/datum/component/overlay_lighting/proc/set_lum_power(new_lum_power) + //Get the simulated luminosity count (If we have no lumcount, this is set to 0) + var/simulated_lum_power = new_lum_power + if(overlay_lighting_flags & LIGHT_NO_LUMCOUNT) + simulated_lum_power = 0 + //The new lum power is the same + if(used_lum_power == simulated_lum_power) + //This light doesn't affect lumcount, but lum_power must be updated regardless + if(new_lum_power != simulated_lum_power) + . = real_lum_power + real_lum_power = new_lum_power + return + //Set the return value to the old lum power + . = real_lum_power + real_lum_power = new_lum_power + //Get the old used lum power + var/old_lum_power = used_lum_power + used_lum_power = simulated_lum_power + //Calculate the difference + var/difference = old_lum_power - used_lum_power + //Apply it to any turf we are affecting + for(var/t in affected_turfs) + var/turf/lit_turf = t + lit_turf.dynamic_lumcount -= difference + + +#undef LIGHTING_ON +#undef LIGHTING_ATTACHED +#undef GET_PARENT diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index df74902d042b..c29716165200 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -194,7 +194,6 @@ var/obj/effect/dummy/luminescent_glow/glowth //shamelessly copied from luminescents var/glow = 3.5 var/range = 2.5 - var/color var/current_nullify_timer // For veil yogstation\code\modules\antagonists\shadowling\shadowling_abilities.dm power_coeff = 1 conflicts = list(/datum/mutation/human/glow/anti) @@ -209,16 +208,19 @@ /datum/mutation/human/glow/modify() if(!glowth) return - var/power = GET_MUTATION_POWER(src) + + var/glow_color + if(owner.dna.features["mcolor"][1] != "#") //if it doesn't start with a pound, it needs that for the color - color += "#" + glow_color += "#" if(length(owner.dna.features["mcolor"]) < 6) //this atrocity converts shorthand hex rgb back into full hex that's required for light to be given a functional value - color += owner.dna.features["mcolor"][1] + owner.dna.features["mcolor"][1] + owner.dna.features["mcolor"][2] + owner.dna.features["mcolor"][2] + owner.dna.features["mcolor"][3] + owner.dna.features["mcolor"][3] + glow_color += owner.dna.features["mcolor"][1] + owner.dna.features["mcolor"][1] + owner.dna.features["mcolor"][2] + owner.dna.features["mcolor"][2] + owner.dna.features["mcolor"][3] + owner.dna.features["mcolor"][3] else - color += owner.dna.features["mcolor"] - glowth.set_light(range * power, glow * power, color) + glow_color += owner.dna.features["mcolor"] + + glowth.set_light_range_power_color(range * GET_MUTATION_POWER(src), glow, glow_color) /datum/mutation/human/glow/on_losing(mob/living/carbon/human/owner) . = ..() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index c2a3828e402b..2eda8fda45eb 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -553,11 +553,11 @@ GLOBAL_LIST_EMPTY(teleportlocs) if(always_unpowered) return 0 switch(chan) - if(EQUIP) + if(AREA_USAGE_EQUIP) return power_equip - if(LIGHT) + if(AREA_USAGE_LIGHT) return power_light - if(ENVIRON) + if(AREA_USAGE_ENVIRON) return power_environ return 0 @@ -584,19 +584,19 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/proc/usage(chan) var/used = 0 switch(chan) - if(LIGHT) + if(AREA_USAGE_LIGHT) used += used_light - if(EQUIP) + if(AREA_USAGE_EQUIP) used += used_equip - if(ENVIRON) + if(AREA_USAGE_ENVIRON) used += used_environ - if(TOTAL) + if(AREA_USAGE_TOTAL) used += used_light + used_equip + used_environ - if(STATIC_EQUIP) + if(AREA_USAGE_STATIC_EQUIP) used += static_equip - if(STATIC_LIGHT) + if(AREA_USAGE_STATIC_LIGHT) used += static_light - if(STATIC_ENVIRON) + if(AREA_USAGE_STATIC_ENVIRON) used += static_environ return used @@ -604,17 +604,17 @@ GLOBAL_LIST_EMPTY(teleportlocs) * Add a static amount of power load to an area * * Possible channels - * *STATIC_EQUIP - * *STATIC_LIGHT - * *STATIC_ENVIRON + * *AREA_USAGE_STATIC_EQUIP + * *AREA_USAGE_STATIC_LIGHT + * *AREA_USAGE_STATIC_ENVIRON */ /area/proc/addStaticPower(value, powerchannel) switch(powerchannel) - if(STATIC_EQUIP) + if(AREA_USAGE_STATIC_EQUIP) static_equip += value - if(STATIC_LIGHT) + if(AREA_USAGE_STATIC_LIGHT) static_light += value - if(STATIC_ENVIRON) + if(AREA_USAGE_STATIC_ENVIRON) static_environ += value /** @@ -633,11 +633,11 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/proc/use_power(amount, chan) amount *= POWER_MOD switch(chan) - if(EQUIP) + if(AREA_USAGE_EQUIP) used_equip += amount - if(LIGHT) + if(AREA_USAGE_LIGHT) used_light += amount - if(ENVIRON) + if(AREA_USAGE_ENVIRON) used_environ += amount /** diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 13083f4b2e42..babf4b0429f5 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -152,7 +152,7 @@ if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) - if (light_power && light_range) + if (light_system == STATIC_LIGHT && light_power && light_range) update_light() if (opacity && isturf(loc)) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 255766e1e7b8..e2cb40222a83 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -53,6 +53,11 @@ /// The degree of pressure protection that mobs in list/contents have from the external environment, between 0 and 1 var/contents_pressure_protection = 0 + ///Lazylist to keep track on the sources of illumination. + var/list/affected_dynamic_lights + ///Highest-intensity light affecting us, which determines our visibility. + var/affecting_dynamic_lumi = 0 + /atom/movable/Initialize(mapload) . = ..() @@ -63,6 +68,9 @@ render_target = ref(src) em_block = new(src, render_target) vis_contents += em_block + + if(light_system == MOVABLE_LIGHT) + AddComponent(/datum/component/overlay_lighting) /atom/movable/Destroy() QDEL_NULL(em_block) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 4fbf328ccbb3..e4e70490e728 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -21,9 +21,9 @@ Class Variables: power_channel (num) What channel to draw from when drawing power for power mode Possible Values: - EQUIP:0 -- Equipment Channel - LIGHT:2 -- Lighting Channel - ENVIRON:3 -- Environment Channel + AREA_USAGE_EQUIP:0 -- Equipment Channel + AREA_USAGE_LIGHT:2 -- Lighting Channel + AREA_USAGE_ENVIRON:3 -- Environment Channel component_parts (list) A list of component parts of machine used by frame based machines. @@ -53,11 +53,11 @@ Class Procs: Default definition uses 'use_power', 'power_channel', 'active_power_usage', 'idle_power_usage', 'powered()', and 'use_power()' implement behavior. - powered(chan = EQUIP) 'modules/power/power.dm' + powered(chan = AREA_USAGE_EQUIP) 'modules/power/power.dm' Checks to see if area that contains the object has power available for power channel given in 'chan'. - use_power(amount, chan=EQUIP) 'modules/power/power.dm' + use_power(amount, chan=AREA_USAGE_EQUIP) 'modules/power/power.dm' Deducts 'amount' from the power channel 'chan' of the area that contains the object. power_change() 'modules/power/power.dm' @@ -103,8 +103,8 @@ Class Procs: //2 = run auto, use active var/idle_power_usage = 0 var/active_power_usage = 0 - var/power_channel = EQUIP - //EQUIP,ENVIRON or LIGHT + var/power_channel = AREA_USAGE_EQUIP + //AREA_USAGE_EQUIP, AREA_USAGE_ENVIRON or AREA_USAGE_LIGHT var/wire_compatible = FALSE var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames. diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/airlock_control.dm index 83ee9915e3a2..72f0ce01acd6 100644 --- a/code/game/machinery/airlock_control.dm +++ b/code/game/machinery/airlock_control.dm @@ -90,7 +90,7 @@ name = "airlock sensor" resistance_flags = FIRE_PROOF - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON var/id_tag var/master_tag diff --git a/code/game/machinery/airlock_cycle_control.dm b/code/game/machinery/airlock_cycle_control.dm index 6a4e39ffda0f..278c0cf1a03a 100644 --- a/code/game/machinery/airlock_cycle_control.dm +++ b/code/game/machinery/airlock_cycle_control.dm @@ -49,7 +49,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 4 active_power_usage = 8 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON req_access = list(ACCESS_ATMOSPHERICS) max_integrity = 250 integrity_failure = 80 diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 27f65e5ca4e9..49d36b3c6c1d 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/stationobjs.dmi' icon_state = "doorctrl" var/skin = "doorctrl" - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON var/obj/item/assembly/device var/obj/item/electronics/airlock/board var/device_type = null diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm index b7e964f14a9a..7bd231e9afb9 100644 --- a/code/game/machinery/cell_charger.dm +++ b/code/game/machinery/cell_charger.dm @@ -6,7 +6,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 5 active_power_usage = 60 - power_channel = EQUIP + power_channel = AREA_USAGE_EQUIP circuit = /obj/item/circuitboard/machine/cell_charger pass_flags = PASSTABLE var/obj/item/stock_parts/cell/charging = null diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index ff550b0f5a47..42c8a300fd3e 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -9,7 +9,10 @@ max_integrity = 200 integrity_failure = 100 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 40, ACID = 20) - var/brightness_on = 1 + light_system = STATIC_LIGHT + light_range = 2 + light_power = 1 + light_on = TRUE var/icon_keyboard = "generic_key" var/icon_screen = "generic" var/clockwork = FALSE @@ -98,9 +101,9 @@ if(!.) return // reduce unneeded light changes if(stat & NOPOWER) - set_light(0) + set_light(FALSE) else - set_light(brightness_on) + set_light(TRUE) /obj/machinery/computer/screwdriver_act(mob/living/user, obj/item/I) if(..()) diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index d60096e53a4f..add9b62fbbcb 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -187,60 +187,28 @@ var/turf/cen = get_turf(src) FOR_DVIEW(var/turf/t, 3, get_turf(src),INVISIBILITY_LIGHTING) if(t.x == cen.x && t.y > cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_RED - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_RED) continue if(t.x == cen.x && t.y < cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_PURPLE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_PURPLE) continue if(t.x > cen.x && t.y == cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_YELLOW - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_YELLOW) continue if(t.x < cen.x && t.y == cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_GREEN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_GREEN) continue if((t.x+1 == cen.x && t.y+1 == cen.y) || (t.x+2==cen.x && t.y+2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_ORANGE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_ORANGE) continue if((t.x-1 == cen.x && t.y-1 == cen.y) || (t.x-2==cen.x && t.y-2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_CYAN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_CYAN) continue if((t.x-1 == cen.x && t.y+1 == cen.y) || (t.x-2==cen.x && t.y+2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_BLUEGREEN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUEGREEN) continue if((t.x+1 == cen.x && t.y-1 == cen.y) || (t.x+2==cen.x && t.y-2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_BLUE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUE) continue continue FOR_DVIEW_END @@ -272,61 +240,80 @@ sleep(0.7 SECONDS) if(selection.song_name == "Engineering's Ultimate High-Energy Hustle") sleep(28 SECONDS) - for(var/obj/reveal in sparkles) + for(var/s in sparkles) + var/obj/effect/overlay/sparkles/reveal = s reveal.alpha = 255 while(active) - for(var/obj/item/flashlight/spotlight/glow in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests - if(QDELETED(src) || !active || QDELETED(glow)) + for(var/g in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests + var/obj/item/flashlight/spotlight/glow = g + if(QDELETED(glow)) + stack_trace("[glow?.gc_destroyed ? "Qdeleting glow" : "null entry"] found in [src].[gc_destroyed ? " Source qdeleting at the time." : ""]") return - if(glow.light_color == LIGHT_COLOR_RED) - glow.light_color = LIGHT_COLOR_BLUE - glow.light_power = glow.light_power * 1.48 - glow.light_range = 0 - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_BLUE) - glow.light_color = LIGHT_COLOR_GREEN - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.light_power = glow.light_power * 2 // Any changes to power must come in pairs to neutralize it for other colors - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_GREEN) - glow.light_color = LIGHT_COLOR_ORANGE - glow.light_power = glow.light_power * 0.5 - glow.light_range = 0 - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_ORANGE) - glow.light_color = LIGHT_COLOR_PURPLE - glow.light_power = glow.light_power * 2.27 - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_PURPLE) - glow.light_color = LIGHT_COLOR_BLUEGREEN - glow.light_power = glow.light_power * 0.44 - glow.light_range = 0 - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_BLUEGREEN) - glow.light_color = LIGHT_COLOR_YELLOW - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_YELLOW) - glow.light_color = LIGHT_COLOR_CYAN - glow.light_range = 0 - glow.update_light() - continue - if(glow.light_color == LIGHT_COLOR_CYAN) - glow.light_color = LIGHT_COLOR_RED - glow.light_power = glow.light_power * 0.68 - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() - continue + switch(glow.light_color) + if(LIGHT_COLOR_RED) + if(glow.even_cycle) + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_BLUE) + else + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 1.48, LIGHT_COLOR_BLUE) + glow.set_light_on(TRUE) + if(LIGHT_COLOR_BLUE) + if(glow.even_cycle) + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 2, LIGHT_COLOR_GREEN) + glow.set_light_on(TRUE) + else + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_GREEN) + if(LIGHT_COLOR_GREEN) + if(glow.even_cycle) + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_ORANGE) + else + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.5, LIGHT_COLOR_ORANGE) + glow.set_light_on(TRUE) + if(LIGHT_COLOR_ORANGE) + if(glow.even_cycle) + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 2.27, LIGHT_COLOR_PURPLE) + glow.set_light_on(TRUE) + else + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_PURPLE) + if(LIGHT_COLOR_PURPLE) + if(glow.even_cycle) + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_BLUEGREEN) + else + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.44, LIGHT_COLOR_BLUEGREEN) + glow.set_light_on(TRUE) + if(LIGHT_COLOR_BLUEGREEN) + if(glow.even_cycle) + glow.set_light_range(glow.base_light_range * DISCO_INFENO_RANGE) + glow.set_light_color(LIGHT_COLOR_YELLOW) + glow.set_light_on(TRUE) + else + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_YELLOW) + if(LIGHT_COLOR_YELLOW) + if(glow.even_cycle) + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_CYAN) + else + glow.set_light_range(glow.base_light_range * DISCO_INFENO_RANGE) + glow.set_light_color(LIGHT_COLOR_CYAN) + glow.set_light_on(TRUE) + if(LIGHT_COLOR_CYAN) + if(glow.even_cycle) + glow.set_light_range_power_color(glow.base_light_range * DISCO_INFENO_RANGE, glow.light_power * 0.68, LIGHT_COLOR_RED) + glow.set_light_on(TRUE) + else + glow.set_light_on(FALSE) + glow.set_light_color(LIGHT_COLOR_RED) + glow.even_cycle = !glow.even_cycle if(prob(2)) // Unique effects for the dance floor that show up randomly to mix things up INVOKE_ASYNC(src, .proc/hierofunk) sleep(selection.song_beat) + if(QDELETED(src)) + return #undef DISCO_INFENO_RANGE diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index d567f0c2fefc..7000b0768fce 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -9,7 +9,7 @@ density = FALSE use_power = IDLE_POWER_USE idle_power_usage = 1 - power_channel = EQUIP + power_channel = AREA_USAGE_EQUIP req_one_access = list(ACCESS_MEDICAL, ACCESS_HEADS, ACCESS_SECURITY) //used to control clamps var/obj/item/defibrillator/defib //this mount's defibrillator var/clamps_locked = FALSE //if true, and a defib is loaded, it can't be removed without unlocking the clamps diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 0688a16a63fa..b2aad8bb28c2 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -7,7 +7,7 @@ density = TRUE move_resist = MOVE_FORCE_VERY_STRONG layer = OPEN_DOOR_LAYER - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON max_integrity = 350 armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 70) CanAtmosPass = ATMOS_PASS_DENSITY diff --git a/code/game/machinery/doors/ministile.dm b/code/game/machinery/doors/ministile.dm index 9ad153a681c2..e119865b075c 100644 --- a/code/game/machinery/doors/ministile.dm +++ b/code/game/machinery/doors/ministile.dm @@ -3,7 +3,7 @@ desc = "A mechanical door that permits one-way access to an area." icon = 'icons/obj/objects.dmi' icon_state = "ministile_map" - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON density = TRUE obj_integrity = 150 max_integrity = 150 diff --git a/code/game/machinery/doors/turnstile.dm b/code/game/machinery/doors/turnstile.dm index 44f639c9f826..188d842212ad 100644 --- a/code/game/machinery/doors/turnstile.dm +++ b/code/game/machinery/doors/turnstile.dm @@ -3,7 +3,7 @@ desc = "A mechanical door that permits one-way access to an area." icon = 'icons/obj/objects.dmi' icon_state = "turnstile_map" - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON density = TRUE obj_integrity = 250 max_integrity = 250 diff --git a/code/game/machinery/embedded_controller/access_controller.dm b/code/game/machinery/embedded_controller/access_controller.dm index f4ec0aa85a09..3e7908f5deea 100644 --- a/code/game/machinery/embedded_controller/access_controller.dm +++ b/code/game/machinery/embedded_controller/access_controller.dm @@ -5,7 +5,7 @@ #define CYCLE_INTERIOR 5 /obj/machinery/doorButtons - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON use_power = IDLE_POWER_USE idle_power_usage = 2 active_power_usage = 4 diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm index 2d4ddc48a190..bb838b650fc2 100644 --- a/code/game/machinery/embedded_controller/airlock_controller.dm +++ b/code/game/machinery/embedded_controller/airlock_controller.dm @@ -201,7 +201,7 @@ density = FALSE frequency = FREQ_AIRLOCK_CONTROL - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON // Setup parameters only var/id_tag @@ -312,4 +312,4 @@ [state_options]"} - return output \ No newline at end of file + return output diff --git a/code/game/machinery/embedded_controller/simple_vent_controller.dm b/code/game/machinery/embedded_controller/simple_vent_controller.dm index 33be1e3f79ad..7679080ea1f9 100644 --- a/code/game/machinery/embedded_controller/simple_vent_controller.dm +++ b/code/game/machinery/embedded_controller/simple_vent_controller.dm @@ -39,7 +39,7 @@ density = FALSE frequency = FREQ_ATMOS_CONTROL - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON // Setup parameters only var/airpump_tag diff --git a/code/game/machinery/fat_sucker.dm b/code/game/machinery/fat_sucker.dm index e0ac8225c976..d69554a7a9ba 100644 --- a/code/game/machinery/fat_sucker.dm +++ b/code/game/machinery/fat_sucker.dm @@ -117,12 +117,12 @@ else overlays += "[icon_state]_door_off" if(occupant) - if(powered(EQUIP)) + if(powered(AREA_USAGE_EQUIP)) overlays += "[icon_state]_stack" overlays += "[icon_state]_yellow" else overlays += "[icon_state]_red" - else if(powered(EQUIP)) + else if(powered(AREA_USAGE_EQUIP)) overlays += "[icon_state]_red" if(panel_open) overlays += "[icon_state]_panel" @@ -130,7 +130,7 @@ /obj/machinery/fat_sucker/process(delta_time) if(!processing) return - if(!powered(EQUIP) || !occupant || !iscarbon(occupant)) + if(!powered(AREA_USAGE_EQUIP) || !occupant || !iscarbon(occupant)) open_machine() return @@ -151,7 +151,7 @@ use_power(500) /obj/machinery/fat_sucker/proc/start_extracting() - if(state_open || !occupant || processing || !powered(EQUIP)) + if(state_open || !occupant || processing || !powered(AREA_USAGE_EQUIP)) return if(iscarbon(occupant)) var/mob/living/carbon/C = occupant diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index ddf247310c8f..303562183071 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -23,7 +23,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 2 active_power_usage = 6 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON resistance_flags = FIRE_PROOF light_power = 0 diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 68a6934bf0d8..e66a081cfb2e 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -24,6 +24,9 @@ anchored = FALSE base_state = "pflash" density = TRUE + light_system = MOVABLE_LIGHT //Used as a flash here. + light_range = FLASH_LIGHT_RANGE + light_on = FALSE /obj/machinery/flasher/Initialize(mapload, ndir = 0, built = 0) . = ..() // ..() is EXTREMELY IMPORTANT, never forget to add it @@ -108,7 +111,9 @@ playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) flick("[base_state]_flash", src) - flash_lighting_fx(FLASH_LIGHT_RANGE, light_power, light_color) + set_light_on(TRUE) + addtimer(CALLBACK(src, .proc/flash_end), FLASH_LIGHT_DURATION, TIMER_OVERRIDE|TIMER_UNIQUE) + last_flash = world.time use_power(1000) @@ -126,6 +131,8 @@ return 1 +/obj/machinery/flasher/proc/flash_end() + set_light_on(FALSE) /obj/machinery/flasher/emp_act(severity) . = ..() diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 2b0a10a0bc17..7fa81fae7e1d 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -57,7 +57,7 @@ start_harvest() /obj/machinery/harvester/proc/can_harvest() - if(!powered(EQUIP) || state_open || !occupant || !iscarbon(occupant)) + if(!powered(AREA_USAGE_EQUIP) || state_open || !occupant || !iscarbon(occupant)) return var/mob/living/carbon/C = occupant if(!allow_clothing) @@ -92,7 +92,7 @@ /obj/machinery/harvester/proc/harvest() update_icon() - if(!harvesting || state_open || !powered(EQUIP) || !occupant || !iscarbon(occupant)) + if(!harvesting || state_open || !powered(AREA_USAGE_EQUIP) || !occupant || !iscarbon(occupant)) return playsound(src, 'sound/machines/juicer.ogg', 20, 1) var/mob/living/carbon/C = occupant diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 185b7ef3994d..69652c065011 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -427,7 +427,6 @@ obj/machinery/holopad/secure/Initialize() Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.setAnchored(TRUE)//So space wind cannot drag it. Hologram.name = "[user.name] (Hologram)"//If someone decides to right click. - Hologram.set_light(2) //hologram lighting move_hologram() if(AI) @@ -465,9 +464,9 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ use_power = total_users > 0 ? ACTIVE_POWER_USE : IDLE_POWER_USE active_power_usage = HOLOPAD_PASSIVE_POWER_USAGE + (HOLOGRAM_POWER_USAGE * total_users) if(total_users || replay_mode) - set_light(2) + set_light_on(TRUE) else - set_light(0) + set_light_on(FALSE) update_icon() /obj/machinery/holopad/update_icon() @@ -599,7 +598,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.setAnchored(TRUE)//So space wind cannot drag it. Hologram.name = "[record.caller_name] (Hologram)"//If someone decides to right click. - Hologram.set_light(2) //hologram lighting visible_message(span_notice("A holographic image of [record.caller_name] flickers to life before your eyes!")) return Hologram @@ -701,6 +699,10 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ var/mob/living/Impersonation var/datum/holocall/HC + light_system = MOVABLE_LIGHT + light_range = 4 + light_color = COLOR_CYAN + /obj/effect/overlay/holo_pad_hologram/Destroy() Impersonation = null if(!QDELETED(HC)) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 7e819f7d4963..139ce45525ed 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/power.dmi' icon_state = "light-p" desc = "Make dark." - power_channel = LIGHT + power_channel = AREA_USAGE_LIGHT light_power = 0 light_range = 7 diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 200ea939bb4f..7180f3b7f036 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -16,7 +16,7 @@ idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power req_access = list(ACCESS_SEC_DOORS) - power_channel = EQUIP //drains power from the EQUIPMENT channel + power_channel = AREA_USAGE_EQUIP //drains power from the EQUIPMENT channel var/base_icon_state = "standard" var/scan_range = 7 diff --git a/code/game/machinery/sci_bombardment.dm b/code/game/machinery/sci_bombardment.dm index daee5b1ea05a..0ec1dec53e30 100644 --- a/code/game/machinery/sci_bombardment.dm +++ b/code/game/machinery/sci_bombardment.dm @@ -28,7 +28,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 500 active_power_usage = 5000 - power_channel = EQUIP + power_channel = AREA_USAGE_EQUIP density = TRUE verb_say = "states coldly" var/countdown = 30 diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 21ff45d7cb71..6fd24687c249 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -280,7 +280,7 @@ energy_drain = 0 range = 0 var/coeff = 100 - var/list/use_channels = list(EQUIP,ENVIRON,LIGHT) + var/list/use_channels = list(AREA_USAGE_EQUIP,AREA_USAGE_ENVIRON,AREA_USAGE_LIGHT) selectable = 0 /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay/Destroy() @@ -343,7 +343,7 @@ var/area/A = get_area(chassis) if(A) var/pow_chan - for(var/c in list(EQUIP,ENVIRON,LIGHT)) + for(var/c in list(AREA_USAGE_EQUIP,AREA_USAGE_ENVIRON,AREA_USAGE_LIGHT)) if(A.powered(c)) pow_chan = c break diff --git a/code/game/mecha/equipment/weapons/melee_weapons.dm b/code/game/mecha/equipment/weapons/melee_weapons.dm index a20b32014e92..ad5f790c20d2 100644 --- a/code/game/mecha/equipment/weapons/melee_weapons.dm +++ b/code/game/mecha/equipment/weapons/melee_weapons.dm @@ -190,6 +190,8 @@ structure_damage_mult = 4 //Think obi-wan cutting through a bulkhead with his lightsaber but he's a giant mech with a huge terrifying axe minimum_damage = 40 attack_speed_modifier = 1.5 //Kinda chunky + light_system = MOVABLE_LIGHT + light_range = 5 light_color = LIGHT_COLOR_RED /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/energy_axe/cleave_attack() //Mostly copy-pasted sword cleave code with minor tweaks. @@ -239,11 +241,11 @@ /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/energy_axe/on_select() START_PROCESSING(SSobj, src) - set_light(5) + set_light_on(TRUE) /obj/item/mecha_parts/mecha_equipment/melee_weapon/sword/energy_axe/on_deselect() STOP_PROCESSING(SSobj, src) - set_light(0) + set_light_on(FALSE) /obj/item/mecha_parts/mecha_equipment/melee_weapon/rocket_fist //Passive upgrade weapon when selected, makes your mech punch harder AND faster name = "\improper DD-2 \"Atom Smasher\" rocket fist" diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index d712236bf5b6..068dbe25feb0 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -22,6 +22,10 @@ layer = BELOW_MOB_LAYER//icon draw layer infra_luminosity = 15 //byond implementation is bugged. force = 5 + light_system = MOVABLE_LIGHT + light_range = 3 + light_power = 6 + light_on = FALSE flags_1 = HEAR_1 var/ruin_mecha = FALSE //if the mecha starts on a ruin, don't automatically give it a tracking beacon to prevent metagaming. var/can_move = 0 //time of next allowed movement @@ -48,7 +52,6 @@ var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference var/datum/effect_system/spark_spread/spark_system = new var/lights = FALSE - var/lights_power = 6 var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference var/completely_disabled = FALSE //stops the mech from doing anything var/omnidirectional_attacks = FALSE //lets mech shoot anywhere, not just in front of it diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm index 3d5ffb1bdf51..0da03b6a7e20 100644 --- a/code/game/mecha/mecha_actions.dm +++ b/code/game/mecha/mecha_actions.dm @@ -114,11 +114,10 @@ return chassis.lights = !chassis.lights if(chassis.lights) - chassis.set_light(chassis.lights_power) button_icon_state = "mech_lights_on" else - chassis.set_light(-chassis.lights_power) button_icon_state = "mech_lights_off" + chassis.set_light_on(chassis.lights) chassis.occupant_message("Toggled lights [chassis.lights?"on":"off"].") chassis.log_message("Toggled lights [chassis.lights?"on":"off"].", LOG_MECHA) UpdateButtonIcon() diff --git a/code/game/mecha/working/clarke.dm b/code/game/mecha/working/clarke.dm index 709209dffa2d..a360e565b88d 100644 --- a/code/game/mecha/working/clarke.dm +++ b/code/game/mecha/working/clarke.dm @@ -9,7 +9,7 @@ fast_pressure_step_in = 1.25 slow_pressure_step_in = 1.8 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - lights_power = 7 + light_power = 7 deflect_chance = 10 step_energy_drain = 15 //slightly higher energy drain since you movin those wheels FAST armor = list(MELEE = 20, BULLET = 10, LASER = 20, ENERGY = 0, BOMB = 60, BIO = 0, RAD = 70, FIRE = 100, ACID = 100) diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index 55d2dc384533..ff4d11749b6b 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -6,7 +6,7 @@ step_in = 1.5 //Move speed, lower is faster. max_temperature = 20000 max_integrity = 200 - lights_power = 7 + light_power = 7 deflect_chance = 15 armor = list(MELEE = 40, BULLET = 20, LASER = 10, ENERGY = 0, BOMB = 40, BIO = 0, RAD = 20, FIRE = 100, ACID = 100) max_equip = 6 @@ -84,7 +84,7 @@ slow_pressure_step_in = 4 //step_in while in normal pressure conditions step_in = 4 resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF - lights_power = 7 + light_power = 7 armor = list(MELEE = 40, BULLET = 30, LASER = 30, ENERGY = 30, BOMB = 60, BIO = 100, RAD = 70, FIRE = 100, ACID = 100) max_equip = 5 // More armor, less tools wreckage = /obj/structure/mecha_wreckage/ripley/firefighter @@ -103,7 +103,7 @@ step_in = 4 slow_pressure_step_in = 3 opacity=0 - lights_power = 7 + light_power = 7 wreckage = /obj/structure/mecha_wreckage/ripley/deathripley step_energy_drain = 0 enclosed = TRUE diff --git a/code/game/movable_luminosity.dm b/code/game/movable_luminosity.dm new file mode 100644 index 000000000000..7a6eaddafd9e --- /dev/null +++ b/code/game/movable_luminosity.dm @@ -0,0 +1,19 @@ +///Keeps track of the sources of dynamic luminosity and updates our visibility with the highest. +/atom/movable/proc/update_dynamic_luminosity() + var/highest = 0 + for(var/i in affected_dynamic_lights) + if(affected_dynamic_lights[i] <= highest) + continue + highest = affected_dynamic_lights[i] + if(highest == affecting_dynamic_lumi) + return + luminosity -= affecting_dynamic_lumi + affecting_dynamic_lumi = highest + luminosity += affecting_dynamic_lumi + + +///Helper to change several lighting overlay settings. +/atom/movable/proc/set_light_range_power_color(range, power, color) + set_light_range(range) + set_light_power(power) + set_light_color(color) diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm index b3f84240e94b..bcd82c07b1c2 100644 --- a/code/game/objects/effects/effect_system/effects_sparks.dm +++ b/code/game/objects/effects/effect_system/effects_sparks.dm @@ -20,9 +20,11 @@ name = "sparks" icon_state = "sparks" anchored = TRUE - light_power = 1.3 - light_range = MINIMUM_USEFUL_LIGHT_RANGE + light_system = MOVABLE_LIGHT + light_range = 2 + light_power = 0.5 light_color = LIGHT_COLOR_FIRE + light_flags = LIGHT_NO_LUMCOUNT /obj/effect/particle_effect/sparks/Initialize() ..() diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index dd0a8ba9db61..171292b2e3f6 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -75,12 +75,18 @@ desc = "Tell a coder if you're seeing this." icon_state = "nothing" light_color = "#FFFFFF" + light_system = MOVABLE_LIGHT light_range = MINIMUM_USEFUL_LIGHT_RANGE mouse_opacity = MOUSE_OPACITY_TRANSPARENT -/obj/effect/dummy/lighting_obj/Initialize(mapload, _color, _range, _power, _duration) +/obj/effect/dummy/lighting_obj/Initialize(mapload, _range, _power, _color, _duration) . = ..() - set_light(_range ? _range : light_range, _power ? _power : light_power, _color ? _color : light_color) + if(!isnull(_range)) + set_light_range(_range) + if(!isnull(_power)) + set_light_power(_power) + if(!isnull(_color)) + set_light_color(_color) if(_duration) QDEL_IN(src, _duration) diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 0267386a3936..19def920e8cd 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -77,3 +77,14 @@ layer = FLOAT_LAYER vis_flags = VIS_INHERIT_ID appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE + +/obj/effect/overlay/light_visible + name = "" + icon = 'icons/effects/light_overlays/light_32.dmi' + icon_state = "light" + layer = O_LIGHTING_VISUAL_LAYER + plane = O_LIGHTING_VISUAL_PLANE + appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + alpha = 0 + vis_flags = NONE diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm index 5111bd8fca81..c825b5ff1fe5 100644 --- a/code/game/objects/items/candle.dm +++ b/code/game/objects/items/candle.dm @@ -1,4 +1,5 @@ #define CANDLE_LUMINOSITY 2 + /obj/item/candle name = "red candle" desc = "In Greek myth, Prometheus stole fire from the Gods and gave it to \ @@ -7,7 +8,10 @@ icon_state = "candle1" item_state = "candle1" w_class = WEIGHT_CLASS_TINY + light_system = MOVABLE_LIGHT + light_range = CANDLE_LUMINOSITY light_color = LIGHT_COLOR_FIRE + light_on = FALSE heat = 1000 var/wax = 2000 var/lit = FALSE @@ -43,7 +47,7 @@ lit = TRUE if(show_message) usr.visible_message(show_message) - set_light(CANDLE_LUMINOSITY) + set_light_on(TRUE) START_PROCESSING(SSobj, src) update_icon() @@ -52,7 +56,7 @@ return lit = FALSE update_icon() - set_light(0) + set_light_on(FALSE) return TRUE /obj/item/candle/extinguish() diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 2c25ea95afd0..40497b687830 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -542,6 +542,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM w_class = WEIGHT_CLASS_TINY flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BELT + light_system = MOVABLE_LIGHT + light_range = 2 + light_power = 0.6 + light_on = FALSE var/lit = 0 var/fancy = TRUE var/overlay_state @@ -588,20 +592,21 @@ CIGARETTE PACKETS ARE IN FANCY.DM playsound(src, 'sound/items/lighter/light.ogg', 50, 2) /obj/item/lighter/proc/set_lit(new_lit) + if(lit == new_lit) + return lit = new_lit if(lit) force = 5 damtype = BURN hitsound = 'sound/items/welder.ogg' attack_verb = list("burnt", "singed") - set_light(1) START_PROCESSING(SSobj, src) else hitsound = "swing_hit" force = 0 attack_verb = null //human_defense.dm takes care of it - set_light(0) STOP_PROCESSING(SSobj, src) + set_light_on(lit) update_icon() /obj/item/lighter/extinguish() diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 9091593543b2..ad4d45cea0e4 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -40,7 +40,11 @@ GLOBAL_LIST_EMPTY(PDAs) slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) resistance_flags = FIRE_PROOF | ACID_PROOF - + light_system = MOVABLE_LIGHT + light_range = 2.3 + light_power = 0.6 + light_color = "#FFCC66" + light_on = FALSE //Main variables var/owner = null // String name of owner @@ -63,8 +67,6 @@ GLOBAL_LIST_EMPTY(PDAs) //Secondary variables var/scanmode = PDA_SCANNER_NONE - var/fon = FALSE //Is the flashlight function on? - var/f_lum = 2.3 //Luminosity for the flashlight function var/silent = FALSE //To beep or not to beep, that is the question var/toff = FALSE //If TRUE, messenger disabled var/list/tnote = list() //Current list of received signals, which are transmuted into messages on-the-spot. Can also be just plain strings, y'know, like, who really gives a shit, y'know @@ -119,8 +121,6 @@ GLOBAL_LIST_EMPTY(PDAs) /obj/item/pda/Initialize() . = ..() - if(fon) - set_light(f_lum) GLOB.PDAs += src if(default_cartridge) @@ -207,7 +207,7 @@ GLOBAL_LIST_EMPTY(PDAs) if(inserted_item) overlay.icon_state = "insert_overlay" add_overlay(new /mutable_appearance(overlay)) - if(fon) + if(light_on) overlay.icon_state = "light_overlay" add_overlay(new /mutable_appearance(overlay)) if(pai) @@ -345,7 +345,7 @@ GLOBAL_LIST_EMPTY(PDAs) if(id && id.registered_account && id.registered_account.account_job.paycheck_department) dat += "
  • [PDAIMG(notes)]Show Department Goals
  • " dat += "
  • [PDAIMG(atmos)]Atmospheric Scan
  • " - dat += "
  • [PDAIMG(flashlight)][fon ? "Disable" : "Enable"] Flashlight
  • " + dat += "
  • [PDAIMG(flashlight)][light_on ? "Disable" : "Enable"] Flashlight
  • " if (pai) if(pai.loc != src) pai = null @@ -945,13 +945,14 @@ GLOBAL_LIST_EMPTY(PDAs) /obj/item/pda/proc/toggle_light() if(issilicon(usr) || !usr.canUseTopic(src, BE_CLOSE)) return - if(fon) - fon = FALSE - set_light(0) - else if(f_lum) - fon = TRUE - set_light(f_lum) + if(light_on) + set_light_on(FALSE) + else if(light_range) + set_light_on(TRUE) update_icon() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() /obj/item/pda/proc/remove_pen() diff --git a/code/game/objects/items/devices/PDA/PDA_types.dm b/code/game/objects/items/devices/PDA/PDA_types.dm index ff18b6803b1a..5c36e10c30c3 100644 --- a/code/game/objects/items/devices/PDA/PDA_types.dm +++ b/code/game/objects/items/devices/PDA/PDA_types.dm @@ -21,7 +21,6 @@ /obj/item/pda/ai icon = null ttone = "data" - fon = FALSE /obj/item/pda/ai/attack_self(mob/user) if ((honkamt > 0) && (prob(60)))//For clown virus. diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 7e0242de8880..87cb47e81cef 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -12,9 +12,11 @@ slot_flags = ITEM_SLOT_BELT materials = list(/datum/material/iron=50, /datum/material/glass=20) actions_types = list(/datum/action/item_action/toggle_light) + light_system = MOVABLE_LIGHT + light_range = 4 + light_power = 1 + light_on = FALSE var/on = FALSE - var/brightness_on = 4 //range of light when on - var/flashlight_power = 1 //strength of the light when on /obj/item/flashlight/Initialize() . = ..() @@ -22,16 +24,14 @@ on = TRUE update_brightness() -/obj/item/flashlight/proc/update_brightness(mob/user = null) +/obj/item/flashlight/proc/update_brightness(mob/user) if(on) icon_state = "[initial(icon_state)]-on" - if(flashlight_power) - set_light(l_range = brightness_on, l_power = flashlight_power) - else - set_light(brightness_on) else icon_state = initial(icon_state) - set_light(0) + set_light_on(on) + if(light_system == STATIC_LIGHT) + update_light() /obj/item/flashlight/attack_self(mob/user) on = !on @@ -67,7 +67,7 @@ to_chat(user, span_warning("[M] doesn't have a head!")) return - if(flashlight_power < 1) + if(light_power < 1) to_chat(user, "[span_warning("\The [src] isn't bright enough to see anything!")] ") return @@ -171,7 +171,7 @@ icon_state = "penlight" item_state = "" flags_1 = CONDUCT_1 - brightness_on = 2 + light_range = 2 var/holo_cooldown = 0 /obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag) @@ -219,7 +219,7 @@ lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' force = 9 // Not as good as a stun baton. - brightness_on = 5 // A little better than the standard flashlight. + light_range = 5 // A little better than the standard flashlight. hitsound = 'sound/weapons/genhit1.ogg' // the desk lamps are a bit special @@ -231,7 +231,7 @@ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' righthand_file = 'icons/mob/inhands/items_righthand.dmi' force = 10 - brightness_on = 5 + light_range = 5 w_class = WEIGHT_CLASS_BULKY flags_1 = CONDUCT_1 materials = list() @@ -267,7 +267,7 @@ name = "flare" desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'." w_class = WEIGHT_CLASS_SMALL - brightness_on = 7 // Pretty bright. + light_range = 7 // Pretty bright. icon_state = "flare" item_state = "flare" lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' @@ -353,7 +353,7 @@ /obj/item/flashlight/flare/emergency name = "safety flare" desc = "A flare issued to Nanotrasen employees for emergencies. There are instructions on the side, it reads 'pull cord, make light, obey Nanotrasen'." - brightness_on = 3 + light_range = 3 item_state = "flare" icon_state = "flaresafety" ignition_sound = 'sound/items/flare_strike_2.ogg' @@ -363,8 +363,8 @@ /obj/item/flashlight/flare/signal name = "signalling flare" desc = "A specialized formulation of the standard Nanotrasen-issued flare, containing increased magnesium content. There are instructions on the side, it reads 'pull cord, make intense light'." - brightness_on = 5 - flashlight_power = 2 + light_range = 5 + light_power = 2 item_state = "flaresignal" icon_state = "flaresignal" light_color = LIGHT_COLOR_HALOGEN @@ -377,7 +377,7 @@ name = "torch" desc = "A torch fashioned from some leaves and a log." w_class = WEIGHT_CLASS_BULKY - brightness_on = 4 + light_range = 4 icon_state = "torch" item_state = "torch" lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' @@ -394,19 +394,19 @@ lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi' desc = "A mining lantern." - brightness_on = 6 // luminosity when on + light_range = 6 // luminosity when on /obj/item/flashlight/lantern/heirloom_moth name = "old lantern" desc = "An old lantern that has seen plenty of use." - brightness_on = 4 + light_range = 4 /obj/item/flashlight/lantern/syndicate name = "suspicious lantern" desc = "A suspicious looking lantern." icon_state = "syndilantern" item_state = "syndilantern" - brightness_on = 10 + light_range = 10 /obj/item/flashlight/lantern/jade name = "jade lantern" @@ -424,7 +424,7 @@ w_class = WEIGHT_CLASS_SMALL slot_flags = ITEM_SLOT_BELT materials = list() - brightness_on = 6 //luminosity when on + light_range = 6 //luminosity when on /obj/item/flashlight/emp var/emp_max_charges = 4 @@ -492,7 +492,7 @@ desc = "A military-grade glowstick." custom_price = 10 w_class = WEIGHT_CLASS_SMALL - brightness_on = 4 + light_range = 4 color = LIGHT_COLOR_GREEN icon_state = "glowstick" item_state = "glowstick" @@ -500,13 +500,14 @@ var/fuel = 0 /obj/item/flashlight/glowstick/Initialize() - fuel = rand(3200, 4000) + fuel = rand(1600, 2000) light_color = color + . = ..() /obj/item/flashlight/glowstick/Destroy() STOP_PROCESSING(SSobj, src) - . = ..() + return ..() /obj/item/flashlight/glowstick/process(delta_time) fuel = max(fuel -= delta_time, 0) @@ -525,13 +526,13 @@ if(fuel <= 0) icon_state = "glowstick-empty" cut_overlays() - set_light(0) + set_light_on(FALSE) else if(on) var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow") glowstick_overlay.color = color add_overlay(glowstick_overlay) item_state = "glowstick-on" - set_light(brightness_on) + set_light_on(TRUE) else icon_state = "glowstick" cut_overlays() @@ -598,30 +599,52 @@ name = "disco light" desc = "Groovy..." icon_state = null - light_color = null - brightness_on = 0 - light_range = 0 + light_range = 4 light_power = 10 alpha = 0 layer = 0 on = TRUE anchored = TRUE - var/range = null resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + ///Boolean that switches when a full color flip ends, so the light can appear in all colors. + var/even_cycle = FALSE + ///Base light_range that can be set on Initialize to use in smooth light range expansions and contractions. + var/base_light_range = 4 + +/obj/item/flashlight/spotlight/Initialize(mapload, _light_range, _light_power, _light_color) + . = ..() + if(!isnull(_light_range)) + base_light_range = _light_range + set_light_range(_light_range) + if(!isnull(_light_power)) + set_light_power(_light_power) + if(!isnull(_light_color)) + set_light_color(_light_color) /obj/item/flashlight/flashdark name = "flashdark" desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure." icon_state = "flashdark" item_state = "flashdark" - brightness_on = 2.5 - flashlight_power = -3 + light_system = STATIC_LIGHT //The overlay light component is not yet ready to produce darkness. + light_range = 0 + ///Variable to preserve old lighting behavior in flashlights, to handle darkness. + var/dark_light_range = 2.5 + ///Variable to preserve old lighting behavior in flashlights, to handle darkness. + var/dark_light_power = -3 + +/obj/item/flashlight/flashdark/update_brightness(mob/user) + . = ..() + if(on) + set_light(dark_light_range, dark_light_power) + else + set_light(0) /obj/item/flashlight/eyelight name = "eyelight" desc = "This shouldn't exist outside of someone's head, how are you seeing this?" - brightness_on = 15 - flashlight_power = 1 + light_range = 15 + light_power = 1 flags_1 = CONDUCT_1 item_flags = DROPDEL actions_types = list() diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 2b922ae40d09..d796c50dea18 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -130,7 +130,7 @@ if(!A || emped) on = FALSE else - on = A.powered(EQUIP) // set "on" to the power status + on = A.powered(AREA_USAGE_EQUIP) // set "on" to the power status if(!on) icon_state = "intercom-p" diff --git a/code/game/objects/items/discoball.dm b/code/game/objects/items/discoball.dm index 926bf3da9409..d466372c782d 100644 --- a/code/game/objects/items/discoball.dm +++ b/code/game/objects/items/discoball.dm @@ -67,7 +67,7 @@ /obj/structure/discoball/proc/DiscoFever() remove_atom_colour(TEMPORARY_COLOUR_PRIORITY) current_color = random_color() - set_light(range, power, current_color) + set_light_color(current_color) add_atom_colour("#[current_color]", FIXED_COLOUR_PRIORITY) update_icon() TimerID = addtimer(CALLBACK(src, .proc/DiscoFever), 5, TIMER_STOPPABLE) //Call ourselves every 0.5 seconds to change colors @@ -100,60 +100,28 @@ var/turf/cen = get_turf(src) FOR_DVIEW(var/turf/t, 3, get_turf(src),INVISIBILITY_LIGHTING) if(t.x == cen.x && t.y > cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_RED - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_RED) continue if(t.x == cen.x && t.y < cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_PURPLE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_PURPLE) continue if(t.x > cen.x && t.y == cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_YELLOW - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_YELLOW) continue if(t.x < cen.x && t.y == cen.y) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_GREEN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_GREEN) continue if((t.x+1 == cen.x && t.y+1 == cen.y) || (t.x+2==cen.x && t.y+2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_ORANGE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_ORANGE) continue if((t.x-1 == cen.x && t.y-1 == cen.y) || (t.x-2==cen.x && t.y-2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_CYAN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_CYAN) continue if((t.x-1 == cen.x && t.y+1 == cen.y) || (t.x-2==cen.x && t.y+2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_BLUEGREEN - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUEGREEN) continue if((t.x+1 == cen.x && t.y-1 == cen.y) || (t.x+2==cen.x && t.y-2 == cen.y)) - var/obj/item/flashlight/spotlight/L = new /obj/item/flashlight/spotlight(t) - L.light_color = LIGHT_COLOR_BLUE - L.light_power = 30-(get_dist(src,L)*8) - L.range = 1.4+get_dist(src, L) - spotlights+=L + spotlights += new /obj/item/flashlight/spotlight(t, 1.4 + get_dist(src, t), 30 - (get_dist(src, t) * 8), LIGHT_COLOR_BLUE) continue continue FOR_DVIEW_END @@ -183,57 +151,38 @@ S.pixel_y = 7 S.forceMove(get_turf(src)) sleep(0.7 SECONDS) - for(var/obj/reveal in sparkles) + for(var/s in sparkles) + var/obj/effect/overlay/sparkles/reveal = s reveal.alpha = 255 while(TurnedOn) - for(var/obj/item/flashlight/spotlight/glow in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests - if(QDELETED(src) || !TurnedOn || QDELETED(glow)) + for(var/g in spotlights) // The multiples reflects custom adjustments to each colors after dozens of tests + var/obj/item/flashlight/spotlight/glow = g + if(QDELETED(glow)) + stack_trace("[glow?.gc_destroyed ? "Qdeleting glow" : "null entry"] found in [src].[gc_destroyed ? " Source qdeleting at the time." : ""]") return if(glow.light_color == LIGHT_COLOR_RED) - glow.light_color = LIGHT_COLOR_BLUE - glow.light_power = glow.light_power * 1.48 - glow.light_range = 0 - glow.update_light() + glow.set_light_range_power_color(0, glow.light_power * 1.48, LIGHT_COLOR_BLUE) continue if(glow.light_color == LIGHT_COLOR_BLUE) - glow.light_color = LIGHT_COLOR_GREEN - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.light_power = glow.light_power * 2 // Any changes to power must come in pairs to neutralize it for other colors - glow.update_light() + glow.set_light_range_power_color(glow.light_range * DISCO_INFENO_RANGE, glow.light_power * 2, LIGHT_COLOR_GREEN) continue if(glow.light_color == LIGHT_COLOR_GREEN) - glow.light_color = LIGHT_COLOR_ORANGE - glow.light_power = glow.light_power * 0.5 - glow.light_range = 0 - glow.update_light() + glow.set_light_range_power_color(0, glow.light_power * 0.5, LIGHT_COLOR_ORANGE) continue if(glow.light_color == LIGHT_COLOR_ORANGE) - glow.light_color = LIGHT_COLOR_PURPLE - glow.light_power = glow.light_power * 2.27 - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() + glow.set_light_range_power_color(glow.light_range * DISCO_INFENO_RANGE, glow.light_power * 2.27, LIGHT_COLOR_PURPLE) continue if(glow.light_color == LIGHT_COLOR_PURPLE) - glow.light_color = LIGHT_COLOR_BLUEGREEN - glow.light_power = glow.light_power * 0.44 - glow.light_range = 0 - glow.update_light() + glow.set_light_range_power_color(0, glow.light_power * 0.44, LIGHT_COLOR_BLUEGREEN) continue if(glow.light_color == LIGHT_COLOR_BLUEGREEN) - glow.light_color = LIGHT_COLOR_YELLOW - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() + glow.set_light_range_power_color(glow.light_range * DISCO_INFENO_RANGE, glow.light_power, LIGHT_COLOR_YELLOW) continue if(glow.light_color == LIGHT_COLOR_YELLOW) - glow.light_color = LIGHT_COLOR_CYAN - glow.light_range = 0 - glow.update_light() + glow.set_light_range_power_color(0, glow.light_power, LIGHT_COLOR_CYAN) continue if(glow.light_color == LIGHT_COLOR_CYAN) - glow.light_color = LIGHT_COLOR_RED - glow.light_power = glow.light_power * 0.68 - glow.light_range = glow.range * DISCO_INFENO_RANGE - glow.update_light() + glow.set_light_range_power_color(glow.light_range * DISCO_INFENO_RANGE, glow.light_power * 0.68, LIGHT_COLOR_RED) continue if(prob(2)) // Unique effects for the dance floor that show up randomly to mix things up INVOKE_ASYNC(src, .proc/hierofunk) diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index 52a51f4176c8..0aee0cf8037d 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -16,6 +16,8 @@ w_class = WEIGHT_CLASS_NORMAL materials = list(/datum/material/iron=500) resistance_flags = FIRE_PROOF + light_system = MOVABLE_LIGHT + light_on = FALSE var/status = FALSE var/lit = FALSE //on or off light_color = LIGHT_COLOR_FIRE @@ -175,6 +177,7 @@ set_light(0) playsound(loc, deac_sound, 50, TRUE) STOP_PROCESSING(SSobj,src) + set_light_on(lit) update_icon() /obj/item/flamethrower/CheckParts(list/parts_list) diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm index ad37fd547790..6a6e82b7a65a 100644 --- a/code/game/objects/items/grenades/flashbang.dm +++ b/code/game/objects/items/grenades/flashbang.dm @@ -13,7 +13,7 @@ return do_sparks(rand(5, 9), FALSE, src) playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9) - new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 4, 2) + new /obj/effect/dummy/lighting_obj (flashbang_turf, flashbang_range + 2, 4, COLOR_WHITE, 2) for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) bang(get_turf(M), M) qdel(src) diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 772bc212ee19..60e92e1eb62e 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -5,13 +5,15 @@ max_integrity = 200 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 30) resistance_flags = FIRE_PROOF - var/brightness_on = 3 + light_system = MOVABLE_LIGHT + light_range = 3 + light_power = 1 + light_on = FALSE var/saber_color = null /obj/item/melee/transforming/energy/Initialize() . = ..() if(active) - set_light(brightness_on) START_PROCESSING(SSobj, src) /obj/item/melee/transforming/energy/Destroy() @@ -40,10 +42,9 @@ if(saber_color) icon_state = "sword[saber_color]" START_PROCESSING(SSobj, src) - set_light(brightness_on) else STOP_PROCESSING(SSobj, src) - set_light(0) + set_light_on(active) /obj/item/melee/transforming/energy/is_hot() return active * heat @@ -167,7 +168,6 @@ if(hacked) var/set_color = pick(possible_colors) light_color = possible_colors[set_color] - update_light() /obj/item/melee/transforming/energy/sword/saber/red possible_colors = list("red" = LIGHT_COLOR_RED) diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 444860c628aa..c0be5ef9ddb5 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -17,6 +17,10 @@ pickup_sound = 'sound/items/handling/weldingtool_pickup.ogg' var/acti_sound = 'sound/items/welderactivate.ogg' var/deac_sound = 'sound/items/welderdeactivate.ogg' + light_system = MOVABLE_LIGHT + light_range = 2 + light_power = 0.75 + light_on = FALSE throw_speed = 3 throw_range = 5 w_class = WEIGHT_CLASS_SMALL @@ -24,12 +28,12 @@ resistance_flags = FIRE_PROOF materials = list(/datum/material/iron=70, /datum/material/glass=30) - var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2) + ///Whether the welding tool is on or off. + var/welding = FALSE var/status = TRUE //Whether the welder is secured or unsecured (able to attach rods to it to make a flamethrower) var/max_fuel = 20 //The max amount of fuel the welder can hold var/change_icons = 1 var/can_off_process = 0 - var/light_intensity = 2 //how powerful the emitted light is when used. var/progress_flash_divisor = 10 var/burned_fuel_for = 0 //when fuel was last removed heat = 3800 @@ -136,7 +140,7 @@ var/turf/location = get_turf(user) location.hotspot_expose(700, 50, 1) if(get_fuel() <= 0) - set_light(0) + set_light_on(FALSE) if(isliving(O)) var/mob/living/L = O @@ -150,8 +154,6 @@ message_admins("[ADMIN_LOOKUPFLW(user)] activated a rigged welder at [AREACOORD(user)].") explode() switched_on(user) - if(welding) - set_light(light_intensity) update_icon() @@ -179,10 +181,18 @@ else return FALSE +//Toggles the welding value. +/obj/item/weldingtool/proc/set_welding(new_value) + if(welding == new_value) + return + . = welding + welding = new_value + set_light_on(welding) //Turns off the welder if there is no more fuel (does this really need to be its own proc?) /obj/item/weldingtool/proc/check_fuel(mob/user) if(get_fuel() <= 0 && welding) + set_light_on(FALSE) switched_on(user) update_icon() //mob icon update @@ -198,7 +208,7 @@ if(!status) to_chat(user, span_warning("[src] can't be turned on while unsecured!")) return - welding = !welding + set_welding(!welding) if(welding) if(get_fuel() >= 1) to_chat(user, span_notice("You switch [src] on.")) @@ -218,8 +228,7 @@ //Switches the welder off /obj/item/weldingtool/proc/switched_off(mob/user) - welding = 0 - set_light(0) + set_welding(FALSE) force = 3 damtype = "brute" @@ -246,7 +255,7 @@ var/mob/living/carbon/human/H = user if(istype(H.head,/obj/item/clothing/head/helmet/space/plasmaman)) return - user.flash_act(light_intensity) + user.flash_act(light_range) // Flash the user during welding progress /obj/item/weldingtool/tool_check_callback(mob/living/user, amount, datum/callback/extra_checks) @@ -257,7 +266,7 @@ var/mob/living/carbon/human/H = user if(istype(H.head,/obj/item/clothing/head/helmet/space/plasmaman)) return - user.flash_act(min(light_intensity,1)) + user.flash_act(min(light_range,1)) progress_flash_divisor = initial(progress_flash_divisor) else progress_flash_divisor-- @@ -347,7 +356,8 @@ icon = 'icons/obj/abductor.dmi' icon_state = "welder_alien" toolspeed = 0.1 - light_intensity = 0 + light_system = NO_LIGHT_SUPPORT + light_range = 0 change_icons = 0 /obj/item/weldingtool/abductor/process() @@ -373,7 +383,7 @@ var/last_gen = 0 change_icons = 0 can_off_process = 1 - light_intensity = 1 + light_range = 1 toolspeed = 0.5 var/nextrefueltick = 0 diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index f54c87972aeb..105edd5390f7 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -310,16 +310,18 @@ hitsound = "swing_hit" armour_penetration = 35 var/saber_color = "green" - light_color = "#00ff00"//green attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") block_chance = 75 max_integrity = 200 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 70) resistance_flags = FIRE_PROOF + light_system = MOVABLE_LIGHT + light_range = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD + light_color = "#00ff00" //green + light_on = FALSE wound_bonus = -10 bare_wound_bonus = 20 var/hacked = FALSE - var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD var/list/possible_colors = list("red", "blue", "green", "purple") /obj/item/twohanded/dualsaber/suicide_act(mob/living/carbon/user) @@ -351,15 +353,17 @@ . = ..() if(LAZYLEN(possible_colors)) saber_color = pick(possible_colors) + var/new_color switch(saber_color) if("red") - light_color = LIGHT_COLOR_RED + new_color = LIGHT_COLOR_RED if("green") - light_color = LIGHT_COLOR_GREEN + new_color = LIGHT_COLOR_GREEN if("blue") - light_color = LIGHT_COLOR_LIGHT_CYAN + new_color = LIGHT_COLOR_LIGHT_CYAN if("purple") - light_color = LIGHT_COLOR_LAVENDER + new_color = LIGHT_COLOR_LAVENDER + set_light_color(new_color) /obj/item/twohanded/dualsaber/Destroy() STOP_PROCESSING(SSobj, src) @@ -420,7 +424,7 @@ w_class = w_class_on hitsound = 'sound/weapons/blade1.ogg' START_PROCESSING(SSobj, src) - set_light(brightness_on) + set_light_on(TRUE) /obj/item/twohanded/dualsaber/unwield() //Specific unwield () to switch hitsounds. sharpness = initial(sharpness) @@ -428,7 +432,7 @@ ..() hitsound = "swing_hit" STOP_PROCESSING(SSobj, src) - set_light(0) + set_light_on(FALSE) /obj/item/twohanded/dualsaber/process() if(wielded) @@ -751,10 +755,10 @@ force = 19 throwforce = 24 force_wielded = 6 - -/obj/item/twohanded/pitchfork/demonic/Initialize() - . = ..() - set_light(3,6,LIGHT_COLOR_RED) + light_system = MOVABLE_LIGHT + light_range = 3 + light_power = 6 + light_color = LIGHT_COLOR_RED /obj/item/twohanded/pitchfork/demonic/greater force = 24 @@ -991,6 +995,10 @@ w_class = WEIGHT_CLASS_HUGE slot_flags = ITEM_SLOT_BACK actions_types = list(/datum/action/item_action/charge_hammer) + light_system = MOVABLE_LIGHT + light_color = LIGHT_COLOR_LIGHT_CYAN + light_range = 2 + light_power = 2 var/datum/effect_system/spark_spread/spark_system //It's a surprise tool that'll help us later var/charging = FALSE var/supercharged = FALSE @@ -1042,11 +1050,11 @@ /obj/item/twohanded/vxtvulhammer/proc/supercharge() //Proc to handle when it's charged for light + sprite + damage supercharged = !supercharged if(supercharged) - set_light(2) //Glows when charged + set_light_on(TRUE) //Glows when charged force = initial(force) + (wielded ? force_wielded : 0) + 12 //12 additional damage for a total of 40 has to be a massively irritating check because of how force_wielded works armour_penetration = 100 else - set_light(0) + set_light_on(TRUE) force = initial(force) + (wielded ? force_wielded : 0) armour_penetration = initial(armour_penetration) update_icon() diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index 1011f6926607..a7e0e80c69b2 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -29,9 +29,9 @@ var/area/A = get_area(src) if(!isarea(A)) return - if(!A.powered(EQUIP)) + if(!A.powered(AREA_USAGE_EQUIP)) return - A.use_power(EQUIP, 5000) + A.use_power(AREA_USAGE_EQUIP, 5000) flick("echair_shock", src) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 2aeca9a435fc..f03fb6ae0ebf 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -80,9 +80,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/old_opacity = opacity var/old_dynamic_lighting = dynamic_lighting - var/old_affecting_lights = affecting_lights var/old_lighting_object = lighting_object - var/old_corners = corners + var/old_lighting_corner_NE = lighting_corner_NE + var/old_lighting_corner_SE = lighting_corner_SE + var/old_lighting_corner_SW = lighting_corner_SW + var/old_lighting_corner_NW = lighting_corner_NW var/old_exl = explosion_level var/old_exi = explosion_id @@ -117,11 +119,14 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( W.blueprint_data = old_bp + lighting_corner_NE = old_lighting_corner_NE + lighting_corner_SE = old_lighting_corner_SE + lighting_corner_SW = old_lighting_corner_SW + lighting_corner_NW = old_lighting_corner_NW + if(SSlighting.initialized) recalc_atom_opacity() lighting_object = old_lighting_object - affecting_lights = old_affecting_lights - corners = old_corners if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting) reconsider_lights() diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 537bf53e53ba..528f4381e122 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -46,7 +46,7 @@ if(requires_activation) SSair.add_to_active(src) - if (light_power && light_range) + if (light_system == STATIC_LIGHT && light_power && light_range) update_light() if (opacity) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index b54880c5725e..d3b970f48426 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -71,7 +71,7 @@ GLOBAL_LIST_EMPTY(station_turfs) if(color) add_atom_colour(color, FIXED_COLOUR_PRIORITY) - if (light_power && light_range) + if (light_system == STATIC_LIGHT && light_power && light_range) update_light() var/turf/T = SSmapping.get_turf_above(src) diff --git a/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm b/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm index fcb5dc33d384..9a577d21341c 100644 --- a/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm +++ b/code/modules/antagonists/bloodsuckers/powers/targeted/brawn.dm @@ -213,25 +213,21 @@ var/mob/living/carbon/human/H = target_atom H.apply_status_effect(STATUS_EFFECT_SHADOWAFFLICTED) var/turf/T = get_turf(H) - for(var/datum/light_source/LS in T.affecting_lights) + for(var/datum/light_source/LS in T.get_affecting_lights()) var/atom/LO = LS.source_atom if(isitem(LO)) var/obj/item/I = LO if(istype(I, /obj/item/clothing/head/helmet/space/hardsuit)) var/obj/item/clothing/head/helmet/space/hardsuit/HA = I - if(HA.on) - HA.on = FALSE + HA.set_light_on(FALSE) if(istype(I, /obj/item/clothing/head/helmet/space/plasmaman)) var/obj/item/clothing/head/helmet/space/plasmaman/PA = I - if(PA.on) - PA.on = FALSE + PA.set_light_on(FALSE) if(istype(I, /obj/item/flashlight)) var/obj/item/flashlight/F = I - if(F.on) - F.on = FALSE - F.update_brightness() + F.set_light_on(FALSE) if(istype(LO, /mob/living/silicon/robot)) var/mob/living/silicon/robot/borg = LO if(!borg.lamp_cooldown) borg.smash_headlamp() - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 4467f2edd586..ffc219b907db 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -424,12 +424,12 @@ user.visible_message(span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"), \ span_cultitalic("You attempt to stun [L] with the spell!")) - user.mob_light(_color = LIGHT_COLOR_BLOOD_MAGIC, _range = 3, _duration = 2) + user.mob_light(_range = 3, _color = LIGHT_COLOR_BLOOD_MAGIC, _duration = 0.2 SECONDS) var/anti_magic_source = L.anti_magic_check() if(anti_magic_source) - L.mob_light(_color = LIGHT_COLOR_HOLY_MAGIC, _range = 2, _duration = 100) + L.mob_light(_range = 2, _color = LIGHT_COLOR_HOLY_MAGIC, _duration = 10 SECONDS) var/mutable_appearance/forbearance = mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER) L.add_overlay(forbearance) addtimer(CALLBACK(L, /atom/proc/cut_overlay, forbearance), 100) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 0c35ee1df4aa..bbdda7a0ca8c 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -101,6 +101,8 @@ throw_range = 3 sharpness = SHARP_EDGED light_color = "#ff0000" + light_system = MOVABLE_LIGHT + light_range = 4 attack_verb = list("cleaved", "slashed", "torn", "hacked", "ripped", "diced", "carved") icon = 'icons/obj/weapons/swords.dmi' icon_state = "cultbastard" @@ -120,7 +122,6 @@ /obj/item/twohanded/required/cult_bastard/Initialize() . = ..() - set_light(4) jaunt = new(src) linked_action = new(src) AddComponent(/datum/component/butchering, 50, 80) @@ -361,7 +362,7 @@ icon_state = "cult_helmet" item_state = "cult_helmet" armor = list(MELEE = 60, BULLET = 50, LASER = 30,ENERGY = 15, BOMB = 30, BIO = 30, RAD = 30, FIRE = 40, ACID = 75) - brightness_on = 0 + light_system = NO_LIGHT_SUPPORT actions_types = list() /obj/item/clothing/suit/space/hardsuit/cult @@ -608,7 +609,7 @@ GLOBAL_VAR_INIT(curselimit, 0) name = "void torch" desc = "Used by veteran cultists to instantly transport items to their needful brethren." w_class = WEIGHT_CLASS_SMALL - brightness_on = 1 + light_range = 1 icon_state = "torch" item_state = "torch" color = "#ff0000" diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index d25a7836536b..0d4c13dc6180 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -10,7 +10,10 @@ w_class = WEIGHT_CLASS_TINY materials = list(/datum/material/iron = 300, /datum/material/glass = 300) light_color = LIGHT_COLOR_WHITE + light_system = MOVABLE_LIGHT //Used as a flash here. + light_range = FLASH_LIGHT_RANGE light_power = FLASH_LIGHT_POWER + light_on = FALSE ///flicked when we flash var/flashing_overlay = "flash-f" ///Number of times the flash has been used. @@ -109,7 +112,8 @@ return FALSE last_trigger = world.time playsound(src, 'sound/weapons/flash.ogg', 100, TRUE) - flash_lighting_fx(FLASH_LIGHT_RANGE, light_power, light_color) + set_light_on(TRUE) + addtimer(CALLBACK(src, .proc/flash_end), FLASH_LIGHT_DURATION, TIMER_OVERRIDE|TIMER_UNIQUE) times_used++ flash_recharge() update_icon(TRUE) @@ -117,6 +121,9 @@ return FALSE return TRUE +/obj/item/assembly/flash/proc/flash_end() + set_light_on(FALSE) + /obj/item/assembly/flash/proc/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE) if(!istype(M)) return diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index 7444c2595f22..a5c10e3735d8 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -47,9 +47,11 @@ icon = 'icons/effects/fire.dmi' icon_state = "1" layer = GASFIRE_LAYER + blend_mode = BLEND_ADD + light_system = MOVABLE_LIGHT light_range = LIGHT_RANGE_FIRE + light_power = 1 light_color = LIGHT_COLOR_FIRE - blend_mode = BLEND_ADD var/volume = 125 var/temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST @@ -144,7 +146,7 @@ add_overlay(fusion_overlay) add_overlay(rainbow_overlay) - set_light(l_color = rgb(LERP(250,heat_r,greyscale_fire),LERP(160,heat_g,greyscale_fire),LERP(25,heat_b,greyscale_fire))) + set_light_color(rgb(LERP(250, heat_r, greyscale_fire), LERP(160, heat_g, greyscale_fire), LERP(25, heat_b, greyscale_fire))) heat_r /= 255 heat_g /= 255 @@ -206,7 +208,6 @@ return TRUE /obj/effect/hotspot/Destroy() - set_light(0) SSair.hotspots -= src var/turf/open/T = loc if(istype(T) && T.active_hotspot == src) diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 89da6cf17ed6..666fe21e6c25 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -64,7 +64,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 4 active_power_usage = 8 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON req_access = list(ACCESS_ATMOSPHERICS) max_integrity = 250 integrity_failure = 80 diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 587100913ea5..44cbca225bc0 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -18,7 +18,7 @@ GLOBAL_LIST_EMPTY(pipeimages) move_resist = INFINITY //Moving a connected machine without actually doing the normal (dis)connection things will probably cause a LOT of issues. idle_power_usage = 0 active_power_usage = 0 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON layer = GAS_PIPE_HIDDEN_LAYER //under wires resistance_flags = FIRE_PROOF max_integrity = 200 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index 08c93f4da1cf..c61b24eabb59 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -352,7 +352,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/high_volume name = "large air vent" - power_channel = EQUIP + power_channel = AREA_USAGE_EQUIP /obj/machinery/atmospherics/components/unary/vent_pump/high_volume/New() ..() diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm index 64ce14205513..e05e29c009d4 100644 --- a/code/modules/atmospherics/machinery/other/meter.dm +++ b/code/modules/atmospherics/machinery/other/meter.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/atmospherics/pipes/meter.dmi' icon_state = "meterX" layer = GAS_METER_LAYER - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON use_power = IDLE_POWER_USE idle_power_usage = 2 active_power_usage = 4 diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 8bd77e70cc76..a093f75b13bb 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -4,19 +4,24 @@ icon_state = "hardhat0_yellow" item_state = "hardhat0_yellow" mob_overlay_icon = 'icons/mob/clothing/head/head.dmi' - var/brightness_on = 4 //luminosity when on - var/on = FALSE - //Determines used sprites: hardhat[on]_[hat_type] - var/hat_type = "yellow" armor = list(MELEE = 15, BULLET = 5, LASER = 20, ENERGY = 10, BOMB = 20, BIO = 10, RAD = 20, FIRE = 100, ACID = 50, WOUND = 10) flags_inv = 0 actions_types = list(/datum/action/item_action/toggle_helmet_light) resistance_flags = FIRE_PROOF dynamic_hair_suffix = "+generic" hattable = FALSE + light_system = MOVABLE_LIGHT + light_range = 4 + light_power = 0.8 + light_on = FALSE dog_fashion = /datum/dog_fashion/head + //Determines used sprites: hardhat[on]_[hat_type] + var/hat_type = "yellow" + ///Whether the headlamp is on or off. + var/on = FALSE + /obj/item/clothing/head/hardhat/attack_self(mob/living/user) toggle_helmet_light(user) @@ -40,10 +45,10 @@ ..() /obj/item/clothing/head/hardhat/proc/turn_on(mob/user) - set_light(brightness_on) + set_light_on(TRUE) /obj/item/clothing/head/hardhat/proc/turn_off(mob/user) - set_light(0) + set_light_on(FALSE) /obj/item/clothing/head/hardhat/orange icon_state = "hardhat0_orange" @@ -68,7 +73,7 @@ desc = "By applying state of the art lighting technology to a fire helmet, and using photo-chemical hardening methods, this hardhat will protect you from robust workplace hazards." icon_state = "hardhat0_purple" item_state = "hardhat0_purple" - brightness_on = 5 + light_range = 5 heat_protection = HEAD max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT cold_protection = HEAD @@ -110,7 +115,7 @@ /obj/item/clothing/head/hardhat/weldhat name = "welding hard hat" desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight AND welding shield! The bulb seems a little smaller though." - brightness_on = 3 //Needs a little bit of tradeoff + light_range = 3 //Needs a little bit of tradeoff dog_fashion = null actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_welding_screen) flash_protect = 2 @@ -159,7 +164,7 @@ desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight AND welding shield!" //This bulb is not smaller icon_state = "hardhat0_white" item_state = "hardhat0_white" - brightness_on = 4 //Boss always takes the best stuff + light_range = 4 //Boss always takes the best stuff hat_type = "white" clothing_flags = STOPSPRESSUREDAMAGE heat_protection = HEAD diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index f6c6d9a93718..91b69b9b12c6 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -30,6 +30,12 @@ . = ..() AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_HEAD)) +/obj/item/clothing/head/helmet/Destroy() + var/obj/item/flashlight/seclite/old_light = set_attached_light(null) + if(old_light) + qdel(old_light) + return ..() + /obj/item/clothing/head/helmet/examine(mob/user) .=..() if(attached_light) @@ -39,18 +45,31 @@ else if(can_flashlight) . += "It has a mounting point for a seclite." -/obj/item/clothing/head/helmet/Destroy() - QDEL_NULL(attached_light) - return ..() - /obj/item/clothing/head/helmet/handle_atom_del(atom/A) if(A == attached_light) - attached_light = null + set_attached_light(null) update_helmlight() update_icon() QDEL_NULL(alight) + qdel(A) return ..() +///Called when attached_light value changes. +/obj/item/clothing/head/helmet/proc/set_attached_light(obj/item/flashlight/seclite/new_attached_light) + if(attached_light == new_attached_light) + return + . = attached_light + attached_light = new_attached_light + if(attached_light) + attached_light.set_light_flags(attached_light.light_flags | LIGHT_ATTACHED) + if(attached_light.loc != src) + attached_light.forceMove(src) + else if(.) + var/obj/item/flashlight/seclite/old_attached_light = . + old_attached_light.set_light_flags(old_attached_light.light_flags & ~LIGHT_ATTACHED) + if(old_attached_light.loc == src) + old_attached_light.forceMove(get_turf(src)) + /obj/item/clothing/head/helmet/sec can_flashlight = TRUE @@ -377,9 +396,7 @@ if(!user.transferItemToLoc(S, src)) return to_chat(user, span_notice("You click [S] into place on [src].")) - if(S.on) - set_light(0) - attached_light = S + set_attached_light(S) update_icon() update_helmlight() alight = new(src) @@ -397,8 +414,7 @@ if(Adjacent(user) && !issilicon(user)) user.put_in_hands(attached_light) - var/obj/item/flashlight/removed_light = attached_light - attached_light = null + var/obj/item/flashlight/removed_light = set_attached_light(null) update_helmlight() removed_light.update_brightness(user) update_icon() @@ -418,6 +434,7 @@ if(user.incapacitated()) return attached_light.on = !attached_light.on + attached_light.update_brightness() to_chat(user, span_notice("You toggle the helmet-light [attached_light.on ? "on":"off"].")) playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) @@ -425,14 +442,7 @@ /obj/item/clothing/head/helmet/proc/update_helmlight() if(attached_light) - if(attached_light.on) - set_light(attached_light.brightness_on) - else - set_light(0) update_icon() - - else - set_light(0) for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index df6a1b3d0705..54441ada851e 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -46,7 +46,7 @@ hitsound = 'sound/weapons/tap.ogg' flags_inv = HIDEEARS|HIDEHAIR armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0) - brightness_on = 2 //luminosity when on + light_range = 2 //luminosity when on flags_cover = HEADCOVERSEYES heat = 999 @@ -116,7 +116,7 @@ hat_type = "pumpkin" flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0) - brightness_on = 2 //luminosity when on + light_range = 2 //luminosity when on flags_cover = HEADCOVERSEYES hattable = FALSE @@ -166,7 +166,7 @@ hat_type = "reindeer" flags_inv = 0 armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0) - brightness_on = 1 //luminosity when on + light_range = 1 //luminosity when on dynamic_hair_suffix = "" dog_fashion = /datum/dog_fashion/head/reindeer diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index ddcb5907052e..88a9237e02e1 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -336,6 +336,10 @@ icon_state = "kindleKicks" item_state = "kindleKicks" actions_types = list(/datum/action/item_action/kindleKicks) + light_system = MOVABLE_LIGHT + light_range = 2 + light_power = 3 + light_on = FALSE var/lightCycle = 0 var/active = FALSE @@ -343,18 +347,19 @@ if(active) return active = TRUE - set_light(2, 3, rgb(rand(0,255),rand(0,255),rand(0,255))) - addtimer(CALLBACK(src, .proc/lightUp), 5) + set_light_color(rgb(rand(0, 255), rand(0, 255), rand(0, 255))) + set_light_on(active) + addtimer(CALLBACK(src, .proc/lightUp), 0.5 SECONDS) /obj/item/clothing/shoes/kindleKicks/proc/lightUp(mob/user) if(lightCycle < 15) - set_light(2, 3, rgb(rand(0,255),rand(0,255),rand(0,255))) - lightCycle += 1 - addtimer(CALLBACK(src, .proc/lightUp), 5) + set_light_color(rgb(rand(0, 255), rand(0, 255), rand(0, 255))) + lightCycle++ + addtimer(CALLBACK(src, .proc/lightUp), 0.5 SECONDS) else - set_light(0) lightCycle = 0 active = FALSE + set_light_on(active) /obj/item/clothing/shoes/russian name = "russian boots" diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index c11e708274f8..4c0e2ec2bfd6 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -6,8 +6,11 @@ item_state = "eng_helm" max_integrity = 300 armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 5, BOMB = 10, BIO = 100, RAD = 75, FIRE = 50, ACID = 75) + light_system = MOVABLE_LIGHT + light_range = 4 + light_power = 1 + light_on = FALSE var/basestate = "hardsuit" - var/brightness_on = 4 //luminosity when on var/on = FALSE var/obj/item/clothing/suit/space/hardsuit/suit //Determines used sprites: hardsuit[on]-[hardsuit_type] @@ -33,10 +36,8 @@ icon_state = "[basestate][on]-[hardsuit_type]" user.update_inv_head() //so our mob-overlays update - if(on) - set_light(brightness_on) - else - set_light(0) + set_light_on(on) + for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() @@ -264,7 +265,7 @@ resistance_flags = FIRE_PROOF heat_protection = HEAD armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 5, BOMB = 50, BIO = 100, RAD = 50, FIRE = 50, ACID = 75, WOUND = 15) - brightness_on = 7 + light_range = 7 allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator) /obj/item/clothing/head/helmet/space/hardsuit/mining/Initialize() @@ -319,7 +320,7 @@ to_chat(user, span_notice("You switch your hardsuit to EVA mode, sacrificing speed for space protection.")) name = initial(name) desc = initial(desc) - set_light(brightness_on) + set_light_on(TRUE) clothing_flags |= visor_flags flags_cover |= HEADCOVERSEYES | HEADCOVERSMOUTH flags_inv |= visor_flags_inv @@ -328,7 +329,7 @@ to_chat(user, span_notice("You switch your hardsuit to combat mode and can now run at full speed.")) name += " (combat)" desc = alt_desc - set_light(0) + set_light_on(FALSE) clothing_flags &= ~visor_flags flags_cover &= ~(HEADCOVERSEYES | HEADCOVERSMOUTH) flags_inv &= ~visor_flags_inv @@ -430,7 +431,8 @@ icon_state = "carp_helm" item_state = "syndicate" armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 75, FIRE = 60, ACID = 75) //As whimpy as a space carp - brightness_on = 0 //luminosity when on + light_system = NO_LIGHT_SUPPORT + light_range = 0 //luminosity when on actions_types = list() /obj/item/clothing/head/helmet/space/hardsuit/carp/Initialize() @@ -703,7 +705,7 @@ hardsuit_type = "ert_commander" armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 50, BIO = 100, RAD = 100, FIRE = 80, ACID = 80) strip_delay = 130 - brightness_on = 7 + light_range = 7 resistance_flags = FIRE_PROOF max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index 9a29f1e4260b..a45d14f6d2a3 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -44,8 +44,10 @@ strip_delay = 80 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, RAD = 0, FIRE = 100, ACID = 75) resistance_flags = FIRE_PROOF | ACID_PROOF - var/brightness_on = 4 //luminosity when the light is on - var/on = FALSE + light_system = MOVABLE_LIGHT + light_range = 4 + light_on = FALSE + var/helmet_on = FALSE actions_types = list(/datum/action/item_action/toggle_helmet_light) flash_protect = 0 var/base_icon_state @@ -59,15 +61,13 @@ toggle_helmet_light(user) /obj/item/clothing/head/helmet/space/plasmaman/proc/toggle_helmet_light(mob/user) - on = !on - if(on) - set_light(brightness_on) - else - set_light(0) - - icon_state = "[base_icon_state][on ? "-light":""]" + helmet_on = !helmet_on + icon_state = "[base_icon_state][helmet_on ? "-light":""]" item_state = icon_state user.update_inv_head() + + set_light_on(helmet_on) + for(var/X in actions) var/datum/action/A=X A.UpdateButtonIcon() diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 75c22a7ed523..1fde8cf7e107 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -816,7 +816,9 @@ item_state = "lampskirt_male" body_parts_covered = CHEST|GROIN|LEGS|FEET can_adjust = FALSE - var/brightness_on = 1 //luminosity when the light is on + light_system = MOVABLE_LIGHT + light_range = 2 + light_on = FALSE var/on = FALSE actions_types = list(/datum/action/item_action/toggle_helmet_light) @@ -827,10 +829,10 @@ user.update_inv_w_uniform() //So the mob overlay updates if(on) - set_light(brightness_on) + set_light_on(TRUE) user.visible_message(span_notice("[user] discreetly pulls a cord for the bulbs under [user.p_their()] skirt, turning [user.p_them()] on.")) else - set_light(0) + set_light_on(FALSE) for(var/X in actions) var/datum/action/A=X diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm index 9b482ba878df..95b12ccbcef0 100644 --- a/code/modules/holodeck/items.dm +++ b/code/modules/holodeck/items.dm @@ -156,7 +156,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 2 active_power_usage = 6 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON /obj/machinery/readybutton/attack_ai(mob/user as mob) to_chat(user, "The station AI is not to interact with these devices.") diff --git a/code/modules/hydroponics/grown/ambrosia.dm b/code/modules/hydroponics/grown/ambrosia.dm index 0f717ded716b..b7655d8fa6cf 100644 --- a/code/modules/hydroponics/grown/ambrosia.dm +++ b/code/modules/hydroponics/grown/ambrosia.dm @@ -73,6 +73,7 @@ desc = "Eating this makes you immortal." icon_state = "ambrosia_gaia" filling_color = rgb(255, 175, 0) + light_system = MOVABLE_LIGHT light_range = 3 seed = /obj/item/seeds/ambrosia/gaia wine_power = 70 diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 38b42ea567bb..939e5bcd2e5f 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -260,8 +260,9 @@ return max(S.potency*(rate + 0.01), 0.1) /datum/plant_gene/trait/glow/on_new(obj/item/reagent_containers/food/snacks/grown/G, newloc) - ..() - G.set_light(glow_range(G.seed), glow_power(G.seed), glow_color) + . = ..() + G.light_system = MOVABLE_LIGHT + G.AddComponent(/datum/component/overlay_lighting, glow_range(G.seed), glow_power(G.seed), glow_color) /datum/plant_gene/trait/glow/shadow //makes plant emit slightly purple shadows diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 4960ab1a3dfb..65749bbaa8b9 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -1,11 +1,21 @@ /atom - var/light_power = 1 // Intensity of the light. - var/light_range = 0 // Range in tiles of the light. - var/light_color // Hexadecimal RGB string representing the colour of the light. - - var/tmp/datum/light_source/light // Our light source. Don't fuck with this directly unless you have a good reason! - var/tmp/list/light_sources // Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list. + ///Light systems, both shouldn't be active at the same time. + var/light_system = STATIC_LIGHT + ///Range of the light in tiles. Zero means no light. + var/light_range = 0 + ///Intensity of the light. The stronger, the less shadows you will see on the lit area. + var/light_power = 1 + ///Hexadecimal RGB string representing the colour of the light. White by default. + var/light_color = COLOR_WHITE + ///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values. + var/light_on = TRUE + ///Bitflags to determine lighting-related atom properties. + var/light_flags = NONE + ///Our light source. Don't fuck with this directly unless you have a good reason! + var/tmp/datum/light_source/light + ///Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list. + var/tmp/list/light_sources // The proc you should always use to set the light of this atom. // Nonesensical value for l_color default, so we can detect if it gets set to null. @@ -35,6 +45,9 @@ if (QDELETED(src)) return + if(light_system != STATIC_LIGHT) + CRASH("update_light() for [src] with following light_system value: [light_system]") + if (!light_power || !light_range) // We won't emit light anyways, destroy the light source. QDEL_NULL(light) else @@ -81,55 +94,97 @@ /atom/movable/Moved(atom/OldLoc, Dir) . = ..() - var/datum/light_source/L - var/thing - for (thing in light_sources) // Cycle through the light sources on this atom and tell them to update. - L = thing - L.source_atom.update_light() + for (var/datum/light_source/light as anything in light_sources) // Cycle through the light sources on this atom and tell them to update. + light.source_atom.update_light() /atom/vv_edit_var(var_name, var_value) switch (var_name) if ("light_range") - set_light(l_range=var_value) + if(light_system == STATIC_LIGHT) + set_light(l_range = var_value) + else + set_light_range(var_value) datum_flags |= DF_VAR_EDITED return TRUE if ("light_power") - set_light(l_power=var_value) + if(light_system == STATIC_LIGHT) + set_light(l_power = var_value) + else + set_light_power(var_value) datum_flags |= DF_VAR_EDITED return TRUE if ("light_color") - set_light(l_color=var_value) + if(light_system == STATIC_LIGHT) + set_light(l_color = var_value) + else + set_light_color(var_value) datum_flags |= DF_VAR_EDITED return TRUE return ..() -/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = LIGHT_COLOR_WHITE, _duration = FLASH_LIGHT_DURATION, _reset_lighting = TRUE) +/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) return -/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = LIGHT_COLOR_WHITE, _duration = FLASH_LIGHT_DURATION, _reset_lighting = TRUE) +/turf/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) if(!_duration) stack_trace("Lighting FX obj created on a turf without a duration") - new /obj/effect/dummy/lighting_obj (src, _color, _range, _power, _duration) - -/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = LIGHT_COLOR_WHITE, _duration = FLASH_LIGHT_DURATION, _reset_lighting = TRUE) - var/temp_color - var/temp_power - var/temp_range - if(!_reset_lighting) //incase the obj already has a lighting color that you don't want cleared out after, ie computer monitors. - temp_color = light_color - temp_power = light_power - temp_range = light_range - set_light(_range, _power, _color) - addtimer(CALLBACK(src, /atom/proc/set_light, _reset_lighting ? initial(light_range) : temp_range, _reset_lighting ? initial(light_power) : temp_power, _reset_lighting ? initial(light_color) : temp_color), _duration, TIMER_OVERRIDE|TIMER_UNIQUE) - -/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = LIGHT_COLOR_WHITE, _duration = FLASH_LIGHT_DURATION, _reset_lighting = TRUE) - mob_light(_color, _range, _power, _duration) - -/mob/living/proc/mob_light(_color, _range, _power, _duration) - var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _color, _range, _power, _duration) + new /obj/effect/dummy/lighting_obj (src, _range, _power, _color, _duration) + +/obj/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + if(!_duration) + stack_trace("Lighting FX obj created on a obj without a duration") + new /obj/effect/dummy/lighting_obj (get_turf(src), _range, _power, _color, _duration) + + +/mob/living/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION) + mob_light(_range, _power, _color, _duration) + + +/mob/living/proc/mob_light(_range, _power, _color, _duration) + var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = new (src, _range, _power, _color, _duration) return mob_light_obj + +/atom/proc/set_light_range(new_range) + if(new_range == light_range) + return + SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_RANGE, new_range) + . = light_range + light_range = new_range + + +/atom/proc/set_light_power(new_power) + if(new_power == light_power) + return + SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_POWER, new_power) + . = light_power + light_power = new_power + + +/atom/proc/set_light_color(new_color) + if(new_color == light_color) + return + SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_COLOR, new_color) + . = light_color + light_color = new_color + + +/atom/proc/set_light_on(new_value) + if(new_value == light_on) + return + SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_ON, new_value) + . = light_on + light_on = new_value + + +/atom/proc/set_light_flags(new_value) + if(new_value == light_flags) + return + SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_FLAGS, new_value) + . = light_flags + light_flags = new_value + diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index 44fed0f02d91..a19f2e23bc26 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -2,32 +2,35 @@ // And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). // For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. -// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. -GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)) - /datum/lighting_corner - var/list/turf/masters var/list/datum/light_source/affecting // Light sources affecting us. - var/active = FALSE // TRUE if one of our masters has dynamic lighting. - var/x = 0 - var/y = 0 + var/x = 0 + var/y = 0 + + var/turf/master_NE + var/turf/master_SE + var/turf/master_SW + var/turf/master_NW var/lum_r = 0 var/lum_g = 0 var/lum_b = 0 - var/needs_update = FALSE + //true color values, guaranteed to be between 0 and 1 + var/cache_r = LIGHTING_SOFT_THRESHOLD + var/cache_g = LIGHTING_SOFT_THRESHOLD + var/cache_b = LIGHTING_SOFT_THRESHOLD - var/cache_r = LIGHTING_SOFT_THRESHOLD - var/cache_g = LIGHTING_SOFT_THRESHOLD - var/cache_b = LIGHTING_SOFT_THRESHOLD - var/cache_mx = 0 + ///the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this + var/largest_color_luminosity = 0 + + ///whether we are to be added to SSlighting's corners_queue list for an update + var/needs_update = FALSE /datum/lighting_corner/New(var/turf/new_turf, var/diagonal) . = ..() - masters = list() - masters[new_turf] = turn(diagonal, 180) + save_master(new_turf, turn(diagonal, 180)) var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. @@ -38,50 +41,49 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. // So we'll have this hardcode instead. - var/turf/T - var/i + var/turf/new_master_turf // Diagonal one is easy. - T = get_step(new_turf, diagonal) - if (T) // In case we're on the map's border. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = diagonal - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) - T.corners[i] = src + new_master_turf = get_step(new_turf, diagonal) + if (new_master_turf) // In case we're on the map's border. + save_master(new_master_turf, diagonal) // Now the horizontal one. - T = get_step(new_turf, horizontal) - if (T) // Ditto. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src + new_master_turf = get_step(new_turf, horizontal) + if (new_master_turf) // Ditto. + save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. // And finally the vertical one. - T = get_step(new_turf, vertical) - if (T) - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src - - update_active() - -/datum/lighting_corner/proc/update_active() - active = FALSE - var/turf/T - var/thing - for (thing in masters) - T = thing - if (T.lighting_object) - active = TRUE - return + new_master_turf = get_step(new_turf, vertical) + if (new_master_turf) + save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. + +/datum/lighting_corner/proc/save_master(turf/master, dir) + switch (dir) + if (NORTHEAST) + master_NE = master + master.lighting_corner_SW = src + if (SOUTHEAST) + master_SE = master + master.lighting_corner_NW = src + if (SOUTHWEST) + master_SW = master + master.lighting_corner_NE = src + if (NORTHWEST) + master_NW = master + master.lighting_corner_SE = src + +/datum/lighting_corner/proc/self_destruct_if_idle() + if (!LAZYLEN(affecting)) + qdel(src, force = TRUE) + +/datum/lighting_corner/proc/vis_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.vis_update() + +/datum/lighting_corner/proc/full_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.recalc_corner(src) // God that was a mess, now to do the rest of the corner code! Hooray! /datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b) @@ -94,20 +96,20 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, if (!needs_update) needs_update = TRUE - GLOB.lighting_update_corners += src + SSlighting.corners_queue += src /datum/lighting_corner/proc/update_objects() // Cache these values ahead of time so 4 individual lighting objects don't all calculate them individually. var/lum_r = src.lum_r var/lum_g = src.lum_g var/lum_b = src.lum_b - var/mx = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1. + var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1. . = 1 // factor - if (mx > 1) - . = 1 / mx + if (largest_color_luminosity > 1) + . = 1 / largest_color_luminosity #if LIGHTING_SOFT_THRESHOLD != 0 - else if (mx < LIGHTING_SOFT_THRESHOLD) + else if (largest_color_luminosity < LIGHTING_SOFT_THRESHOLD) . = 0 // 0 means soft lighting. cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD @@ -118,13 +120,29 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE) cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE) #endif - cache_mx = round(mx, LIGHTING_ROUND_VALUE) + src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE) + + var/datum/lighting_object/lighting_object = master_NE?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_SE?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_SW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_NW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object - for (var/TT in masters) - var/turf/T = TT - if (T.lighting_object && !T.lighting_object.needs_update) - T.lighting_object.needs_update = TRUE - GLOB.lighting_update_objects += T.lighting_object + self_destruct_if_idle() /datum/lighting_corner/dummy/New() @@ -134,6 +152,23 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, if (!force) return QDEL_HINT_LETMELIVE - stack_trace("Ok, Look, /tg/, I need you to find whatever fucker decided to call qdel on a fucking lighting corner, then tell him very nicely and politely that he is 100% retarded and needs his head checked. Thanks. Send them my regards by the way.") + for (var/datum/light_source/light_source as anything in affecting) + LAZYREMOVE(light_source.effect_str, src) + affecting = null + + if (master_NE) + master_NE.lighting_corner_SW = null + master_NE.lighting_corners_initialised = FALSE + if (master_SE) + master_SE.lighting_corner_NW = null + master_SE.lighting_corners_initialised = FALSE + if (master_SW) + master_SW.lighting_corner_NE = null + master_SW.lighting_corners_initialised = FALSE + if (master_NW) + master_NW.lighting_corner_SE = null + master_NW.lighting_corners_initialised = FALSE + if (needs_update) + SSlighting.corners_queue -= src return ..() diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index 0845bb5d495a..49b3ec20e454 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -29,12 +29,12 @@ space_tile.update_starlight() needs_update = TRUE - GLOB.lighting_update_objects += src + SSlighting.objects_queue += src /datum/lighting_object/Destroy(force) if (!force) return QDEL_HINT_LETMELIVE - GLOB.lighting_update_objects -= src + SSlighting.objects_queue -= src if (isturf(affected_turf)) affected_turf.lighting_object = null affected_turf.luminosity = 1 @@ -54,34 +54,28 @@ var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new - var/list/corners = affected_turf.corners - var/datum/lighting_corner/cr = dummy_lighting_corner - var/datum/lighting_corner/cg = dummy_lighting_corner - var/datum/lighting_corner/cb = dummy_lighting_corner - var/datum/lighting_corner/ca = dummy_lighting_corner - if (corners) //done this way for speed - cr = corners[3] || dummy_lighting_corner - cg = corners[2] || dummy_lighting_corner - cb = corners[4] || dummy_lighting_corner - ca = corners[1] || dummy_lighting_corner - - var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) - - var/rr = cr.cache_r - var/rg = cr.cache_g - var/rb = cr.cache_b - - var/gr = cg.cache_r - var/gg = cg.cache_g - var/gb = cg.cache_b - - var/br = cb.cache_r - var/bg = cb.cache_g - var/bb = cb.cache_b - - var/ar = ca.cache_r - var/ag = ca.cache_g - var/ab = ca.cache_b + var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner + var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner + var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner + var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner + + var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity) + + var/rr = red_corner.cache_r + var/rg = red_corner.cache_g + var/rb = red_corner.cache_b + + var/gr = green_corner.cache_r + var/gg = green_corner.cache_g + var/gb = green_corner.cache_b + + var/br = blue_corner.cache_r + var/bg = blue_corner.cache_g + var/bb = blue_corner.cache_b + + var/ar = alpha_corner.cache_r + var/ag = alpha_corner.cache_g + var/ab = alpha_corner.cache_b #if LIGHTING_SOFT_THRESHOLD != 0 var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index a09f734ab71d..13164805fdec 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -2,14 +2,21 @@ // These are the main datums that emit light. /datum/light_source - var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held). - var/atom/source_atom // The atom that we belong to. - - var/turf/source_turf // The turf under the above. - var/turf/pixel_turf // The turf the top_atom appears to over. - var/light_power // Intensity of the emitter light. - var/light_range // The range of the emitted light. - var/light_color // The colour of the light, string, decomposed by parse_light_color() + ///The atom we're emitting light from (for example a mob if we're from a flashlight that's being held). + var/atom/top_atom + ///The atom that we belong to. + var/atom/source_atom + + ///The turf under the source atom. + var/turf/source_turf + ///The turf the top_atom appears to over. + var/turf/pixel_turf + ///Intensity of the emitter light. + var/light_power + /// The range of the emitted light. + var/light_range + /// The colour of the light, string, decomposed by parse_light_color() + var/light_color // Variables for keeping track of the colour. var/lum_r @@ -21,12 +28,14 @@ var/tmp/applied_lum_g var/tmp/applied_lum_b - var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. - var/list/turf/affecting_turfs + /// List used to store how much we're affecting corners. + var/list/datum/lighting_corner/effect_str - var/applied = FALSE // Whether we have applied our light yet or not. + /// Whether we have applied our light yet or not. + var/applied = FALSE - var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update. + /// whether we are to be added to SSlighting's sources_queue list for an update + var/needs_update = LIGHTING_NO_UPDATE /datum/light_source/New(var/atom/owner, var/atom/top) @@ -56,7 +65,7 @@ LAZYREMOVE(top_atom.light_sources, src) if (needs_update) - GLOB.lighting_update_lights -= src + SSlighting.sources_queue -= src . = ..() @@ -65,7 +74,7 @@ // Actually that'd be great if you could! #define EFFECT_UPDATE(level) \ if (needs_update == LIGHTING_NO_UPDATE) \ - GLOB.lighting_update_lights += src; \ + SSlighting.sources_queue += src; \ if (needs_update < level) \ needs_update = level; \ @@ -99,56 +108,43 @@ // The braces and semicolons are there to be able to do this on a single line. #define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) -#define APPLY_CORNER(C) \ - . = LUM_FALLOFF(C, pixel_turf); \ - . *= light_power; \ - var/OLD = effect_str[C]; \ - effect_str[C] = .; \ - \ - C.update_lumcount \ - ( \ - (. * lum_r) - (OLD * applied_lum_r), \ - (. * lum_g) - (OLD * applied_lum_g), \ - (. * lum_b) - (OLD * applied_lum_b) \ - ); - -#define REMOVE_CORNER(C) \ - . = -effect_str[C]; \ - C.update_lumcount \ - ( \ - . * applied_lum_r, \ - . * applied_lum_g, \ - . * applied_lum_b \ +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, pixel_turf); \ + . *= light_power; \ + var/OLD = effect_str[C]; \ + \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b) \ + ); \ + +#define REMOVE_CORNER(C) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ ); // This is the define used to calculate falloff. /datum/light_source/proc/remove_lum() applied = FALSE - var/thing - for (thing in affecting_turfs) - var/turf/T = thing - LAZYREMOVE(T.affecting_lights, src) - - affecting_turfs = null - - var/datum/lighting_corner/C - for (thing in effect_str) - C = thing - REMOVE_CORNER(C) + for (var/datum/lighting_corner/corner as anything in effect_str) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) - LAZYREMOVE(C.affecting, src) - - effect_str = null - -/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/corner) LAZYINITLIST(effect_str) - if (effect_str[C]) // Already have one. - REMOVE_CORNER(C) - effect_str[C] = 0 + if (effect_str[corner]) // Already have one. + REMOVE_CORNER(corner) + effect_str[corner] = 0 - APPLY_CORNER(C) - UNSETEMPTY(effect_str) + APPLY_CORNER(corner) + effect_str[corner] = . /datum/light_source/proc/update_corners() @@ -185,9 +181,9 @@ pixel_turf = get_turf_pixel(top_atom) update = TRUE else - var/P = get_turf_pixel(top_atom) - if (P != pixel_turf) - pixel_turf = P + var/pixel_loc = get_turf_pixel(top_atom) + if (pixel_loc != pixel_turf) + pixel_turf = pixel_loc update = TRUE if (!isturf(source_turf)) @@ -213,77 +209,56 @@ return //nothing's changed var/list/datum/lighting_corner/corners = list() - var/list/turf/turfs = list() - var/thing - var/datum/lighting_corner/C - var/turf/T + var/list/turf/turfs = list() if (source_turf) var/oldlum = source_turf.luminosity source_turf.luminosity = CEILING(light_range, 1) - for(T in view(CEILING(light_range, 1), source_turf)) - if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom) - continue - if (!T.lighting_corners_initialised) - T.generate_missing_corners() - for (thing in T.corners) - C = thing - corners[C] = 0 + for(var/turf/T in view(CEILING(light_range, 1), source_turf)) + if(!T.has_opaque_atom) + if (!T.lighting_corners_initialised) + T.generate_missing_corners() + corners[T.lighting_corner_NE] = 0 + corners[T.lighting_corner_SE] = 0 + corners[T.lighting_corner_SW] = 0 + corners[T.lighting_corner_NW] = 0 turfs += T source_turf.luminosity = oldlum - LAZYINITLIST(affecting_turfs) - var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. - affecting_turfs += L - for (thing in L) - T = thing - LAZYADD(T.affecting_lights, src) - - L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. - affecting_turfs -= L - for (thing in L) - T = thing - LAZYREMOVE(T.affecting_lights, src) - + var/list/datum/lighting_corner/new_corners = (corners - effect_str) LAZYINITLIST(effect_str) if (needs_update == LIGHTING_VIS_UPDATE) - for (thing in corners - effect_str) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . else - L = corners - effect_str - for (thing in L) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) - - for (thing in corners - L) // Existing corners - C = thing - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) - - L = effect_str - corners - for (thing in L) // Old, now gone, corners. - C = thing - REMOVE_CORNER(C) - LAZYREMOVE(C.affecting, src) - effect_str -= L + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . + + for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners + APPLY_CORNER(corner) + if (. != 0) + effect_str[corner] = . + else + LAZYREMOVE(corner.affecting, src) + effect_str -= corner + + var/list/datum/lighting_corner/gone_corners = effect_str - corners + for (var/datum/lighting_corner/corner as anything in gone_corners) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) + effect_str -= gone_corners applied_lum_r = lum_r applied_lum_g = lum_g applied_lum_b = lum_b UNSETEMPTY(effect_str) - UNSETEMPTY(affecting_turfs) #undef EFFECT_UPDATE #undef LUM_FALLOFF diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 975a1a2bf9c7..a99698ff33be 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -4,76 +4,68 @@ var/tmp/lighting_corners_initialised = FALSE - var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. var/tmp/datum/lighting_object/lighting_object // Our lighting object. - var/tmp/list/datum/lighting_corner/corners + + ///Lighting Corner datums. + var/tmp/datum/lighting_corner/lighting_corner_NE + var/tmp/datum/lighting_corner/lighting_corner_SE + var/tmp/datum/lighting_corner/lighting_corner_SW + var/tmp/datum/lighting_corner/lighting_corner_NW + var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. + ///Lumcount added by sources other than lighting datum objects, such as the overlay lighting component. + var/dynamic_lumcount = 0 + // Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() - var/datum/light_source/L - var/thing - for (thing in affecting_lights) - L = thing - L.vis_update() + lighting_corner_NE?.vis_update() + lighting_corner_SE?.vis_update() + lighting_corner_SW?.vis_update() + lighting_corner_NW?.vis_update() /turf/proc/lighting_clear_overlay() if (lighting_object) - qdel(lighting_object, TRUE) - - var/datum/lighting_corner/C - var/thing - for (thing in corners) - if(!thing) - continue - C = thing - C.update_active() + qdel(lighting_object, force=TRUE) // Builds a lighting object for us, but only if our area is dynamic. /turf/proc/lighting_build_overlay() if (lighting_object) - qdel(lighting_object,force=TRUE) //Shitty fix for lighting objects persisting after death + qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death - var/area/A = loc - if (!IS_DYNAMIC_LIGHTING(A) && !light_sources) + var/area/our_area = loc + if (!IS_DYNAMIC_LIGHTING(our_area) && !light_sources) return - if (!lighting_corners_initialised) - generate_missing_corners() - new/datum/lighting_object(src) - var/thing - var/datum/lighting_corner/C - var/datum/light_source/S - for (thing in corners) - if(!thing) - continue - C = thing - if (!C.active) // We would activate the corner, calculate the lighting for it. - for (thing in C.affecting) - S = thing - S.recalc_corner(C) - C.active = TRUE - // Used to get a scaled lumcount. /turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) if (!lighting_object) return 1 var/totallums = 0 - var/thing var/datum/lighting_corner/L - for (thing in corners) - if(!thing) - continue - L = thing + L = lighting_corner_NE + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SE + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SW + if (L) totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_NW + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + totallums /= 12 // 4 corners, each with 3 channels, get the average. totallums = (totallums - minlum) / (maxlum - minlum) + totallums += dynamic_lumcount + return CLAMP01(totallums) // Returns a boolean whether the turf is on soft lighting. @@ -111,14 +103,38 @@ lighting_clear_overlay() /turf/proc/generate_missing_corners() - if (!IS_DYNAMIC_LIGHTING(src) && !light_sources) - return + if (!lighting_corner_NE) + lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST) + + if (!lighting_corner_SE) + lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST) + + if (!lighting_corner_SW) + lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST) + + if (!lighting_corner_NW) + lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST) + lighting_corners_initialised = TRUE - if (!corners) - corners = list(null, null, null, null) - for (var/i = 1 to 4) - if (corners[i]) // Already have a corner on this direction. - continue +/turf/proc/get_affecting_lights() + var/list/affecting = list() + + if (!lighting_object) + return affecting - corners[i] = new/datum/lighting_corner(src, GLOB.LIGHTING_CORNER_DIAGONAL[i]) + var/datum/lighting_corner/L + L = lighting_corner_NE + if (L) + affecting += L.affecting + L = lighting_corner_SE + if (L) + affecting += L.affecting + L = lighting_corner_SW + if (L) + affecting += L.affecting + L = lighting_corner_NW + if (L) + affecting += L.affecting + + return uniqueList(affecting) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 1fcb26db33ab..aa8df422d4db 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -340,7 +340,9 @@ GLOBAL_LIST_EMPTY(bloodmen_list) desc = "Happy to light your way." icon = 'icons/obj/lighting.dmi' icon_state = "orb" + light_system = MOVABLE_LIGHT light_range = 7 + light_flags = LIGHT_ATTACHED layer = ABOVE_ALL_MOB_LAYER var/sight_flags = SEE_MOBS var/lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 5678594a0d0e..f8ac55148d16 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -37,8 +37,10 @@ healable = 0 loot = list(/obj/effect/decal/cleanable/robot_debris) del_on_death = TRUE + light_system = MOVABLE_LIGHT + light_range = 6 + light_on = FALSE var/mode = MINEDRONE_COLLECT - var/light_on = 0 var/obj/item/gun/energy/kinetic_accelerator/minebot/stored_gun /mob/living/simple_animal/hostile/mining_drone/Initialize() @@ -234,11 +236,7 @@ /datum/action/innate/minedrone/toggle_light/Activate() var/mob/living/simple_animal/hostile/mining_drone/user = owner - if(user.light_on) - user.set_light(0) - else - user.set_light(6) - user.light_on = !user.light_on + user.set_light_on(!user.light_on) to_chat(user, span_notice("You toggle your light [user.light_on ? "on" : "off"].")) /datum/action/innate/minedrone/toggle_mode diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 660a18d8eea9..5ff31f655d36 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -17,6 +17,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) invisibility = INVISIBILITY_OBSERVER hud_type = /datum/hud/ghost movement_type = GROUND | FLYING + light_system = MOVABLE_LIGHT + light_range = 1 + light_power = 2 + light_on = FALSE var/can_reenter_corpse var/bootime = 0 var/started_as_observer //This variable is set to 1 when you enter the game as an observer. @@ -926,10 +930,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/proc/set_invisibility(value) invisibility = value - if(!value) - set_light(1, 2) - else - set_light(0, 0) + set_light_on(!value ? TRUE : FALSE) // Ghosts have no momentum, being massless ectoplasm /mob/dead/observer/Process_Spacemove(movement_dir) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 7aa228f49ccb..1c3b769a3a1f 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -47,20 +47,32 @@ smells_like = "crackling sweetness" + var/obj/effect/dummy/lighting_obj/ethereal_light + + +/datum/species/ethereal/Destroy(force) + if(ethereal_light) + QDEL_NULL(ethereal_light) + return ..() + /datum/species/ethereal/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) - .=..() - if(ishuman(C)) - var/mob/living/carbon/human/H = C - default_color = "#" + H.dna.features["ethcolor"] - r1 = GETREDPART(default_color) - g1 = GETGREENPART(default_color) - b1 = GETBLUEPART(default_color) - spec_updatehealth(H) + . = ..() + if(!ishuman(C)) + return + var/mob/living/carbon/human/ethereal = C + default_color = "#[ethereal.dna.features["ethcolor"]]" + r1 = GETREDPART(default_color) + g1 = GETGREENPART(default_color) + b1 = GETBLUEPART(default_color) + //RegisterSignal(ethereal, COMSIG_ATOM_EMAG_ACT, .proc/on_emag_act) + //RegisterSignal(ethereal, COMSIG_ATOM_EMP_ACT, .proc/on_emp_act) + ethereal_light = ethereal.mob_light() + spec_updatehealth(ethereal) /datum/species/ethereal/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) - .=..() - C.set_light(0) + QDEL_NULL(ethereal_light) + return ..() /datum/species/ethereal/random_name(gender,unique,lastname) if(unique) @@ -71,15 +83,16 @@ return randname /datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/H) - .=..() + . = ..() if(H.stat != DEAD && !EMPeffect) var/healthpercent = max(H.health, 0) / 100 if(!emageffect) current_color = rgb(r2 + ((r1-r2)*healthpercent), g2 + ((g1-g2)*healthpercent), b2 + ((b1-b2)*healthpercent)) - H.set_light(1 + (3 * healthpercent), 1 + (2 * healthpercent), current_color) + ethereal_light.set_light_range_power_color(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color) + ethereal_light.set_light_on(TRUE) fixed_mut_color = copytext_char(current_color, 2) else - H.set_light(0) + ethereal_light.set_light_on(FALSE) fixed_mut_color = rgb(128,128,128) H.update_body() diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 7690f3b666ea..a48e4a53db86 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -427,7 +427,7 @@ /datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity) if(intensity) glow_intensity = intensity - glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"]) + glow.set_light_range_power_color(glow_intensity, glow_intensity, C.dna.features["mcolor"]) /obj/effect/dummy/luminescent_glow name = "luminescent glow" @@ -435,6 +435,8 @@ icon_state = "nothing" light_color = "#FFFFFF" light_range = LUMINESCENT_DEFAULT_GLOW + light_system = MOVABLE_LIGHT + light_power = 2.5 /obj/effect/dummy/luminescent_glow/Initialize() . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index da8f8c3aac82..cb2616228e44 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -211,9 +211,8 @@ /obj/item/light_eater/proc/disintegrate(obj/item/O) if(istype(O, /obj/item/pda)) var/obj/item/pda/PDA = O - PDA.set_light(0) - PDA.fon = FALSE - PDA.f_lum = 0 + PDA.set_light_on(FALSE) + PDA.set_light_range(0) //It won't be turning on again. PDA.update_icon() visible_message(span_danger("The light in [PDA] shorts out!")) else diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 6114b8cfa00f..213fe23ed952 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -47,8 +47,8 @@ if(!lacks_power()) var/area/home = get_area(src) - if(home.powered(EQUIP)) - home.use_power(1000, EQUIP) + if(home.powered(AREA_USAGE_EQUIP)) + home.use_power(1000, AREA_USAGE_EQUIP) if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC) ai_restore_power() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 46c36a0c47b1..e5045de6f3c0 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -10,6 +10,8 @@ has_limbs = 1 hud_type = /datum/hud/robot blocks_emissive = EMISSIVE_BLOCK_GENERIC + light_system = MOVABLE_LIGHT + light_on = FALSE var/custom_name = "" var/braintype = "Cyborg" @@ -795,17 +797,17 @@ //if both lamp is enabled AND the update_color flag is on, keep the lamp on. Otherwise, if anything listed is true, disable the lamp. if(!(update_color && lamp_enabled) && (turn_off || lamp_enabled || update_color || !lamp_functional || stat || low_power_mode)) if(lamp_functional && stat != DEAD) - set_light(l_power = TRUE) //If the lamp isn't broken and borg isn't dead, doomsday borgs cannot disable their light fully. - set_light(l_color = "#FF0000") //This should only matter for doomsday borgs, as any other time the lamp will be off and the color not seen - set_light(l_range = 1) //Again, like above, this only takes effect when the light is forced on by doomsday mode. - set_light(l_power = FALSE) + set_light_on(TRUE) //If the lamp isn't broken and borg isn't dead, doomsday borgs cannot disable their light fully. + set_light_color("#FF0000") //This should only matter for doomsday borgs, as any other time the lamp will be off and the color not seen + set_light_range(1) //Again, like above, this only takes effect when the light is forced on by doomsday mode. + set_light_on(FALSE) lamp_enabled = FALSE lampButton?.update_icon() update_icons() return - set_light(l_range = lamp_intensity) - set_light(l_color = lamp_color) - set_light(l_power = TRUE) + set_light_range(lamp_intensity) + set_light_color(lamp_color) + set_light_on(TRUE) lamp_enabled = TRUE lampButton?.update_icon() update_icons() diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 204de0d28e0d..9fdf05c98dba 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -4,8 +4,6 @@ layer = MOB_LAYER gender = NEUTER mob_biotypes = list(MOB_ROBOTIC) - light_range = 3 - stop_automated_movement = 1 wander = 0 healable = 0 damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) @@ -23,6 +21,9 @@ bubble_icon = "machine" speech_span = SPAN_ROBOT faction = list("neutral", "silicon" , "turret") + light_system = MOVABLE_LIGHT + light_range = 3 + light_power = 0.9 var/obj/machinery/bot_core/bot_core = null var/bot_core_type = /obj/machinery/bot_core @@ -128,7 +129,7 @@ return FALSE on = TRUE update_mobility() - set_light(initial(light_range)) + set_light_on(on) update_icon() diag_hud_set_botstat() return TRUE @@ -136,7 +137,7 @@ /mob/living/simple_animal/bot/proc/turn_off() on = FALSE update_mobility() - set_light(0) + set_light_on(on) bot_reset() //Resets an AI's call, should it exist. update_icon() diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index b212f4c36d1c..393c044f627b 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -38,6 +38,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians melee_damage_upper = 15 butcher_results = list(/obj/item/ectoplasm = 1) AIStatus = AI_OFF + light_system = MOVABLE_LIGHT + light_range = 3 + light_on = FALSE hud_type = /datum/hud/guardian dextrous_hud_type = /datum/hud/dextrous/guardian //if we're set to dextrous, account for it. var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS] @@ -338,12 +341,12 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians to_chat(src, "You don't have another mode!") /mob/living/simple_animal/hostile/guardian/proc/ToggleLight() - if(light_range<3) + if(!light_on) to_chat(src, span_notice("You activate your light.")) - set_light(3) + set_light_on(TRUE) else to_chat(src, span_notice("You deactivate your light.")) - set_light(0) + set_light_on(FALSE) /mob/living/simple_animal/hostile/guardian/verb/ShowType() set name = "Check Guardian Type" diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index 12d5f2485d8f..8b7b4622573c 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -60,7 +60,7 @@ QDEL_NULL(alert_light) if(a_intent != INTENT_HELP) icon_state = "[initial(icon_state)]_attack" - alert_light = mob_light(COLOR_RED_LIGHT, 6, 0.4) + alert_light = mob_light(6, 0.4, COLOR_RED_LIGHT) else icon_state = initial(icon_state) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index ccd81555c265..c536c55fb915 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -234,6 +234,7 @@ Difficulty: Very Hard icon = 'icons/effects/effects.dmi' icon_state = "at_shield2" layer = FLY_LAYER + light_system = MOVABLE_LIGHT light_range = 2 duration = 8 var/target diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm index 556a3316021f..feaa39c3a7c0 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm @@ -62,6 +62,7 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa var/call_help_cooldown = 0 var/call_help_cooldown_amt = 150 //Deciseconds between calling swarmers to help us when attacked var/static/list/swarmer_caps + /mob/living/simple_animal/hostile/megafauna/swarmer_swarm_beacon/Initialize() . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm index 0a28870c431c..670283b278db 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm @@ -101,6 +101,7 @@ icon_dead = "watcher_magmawing_dead" maxHealth = 235 //Compensate for the lack of slowdown on projectiles with a bit of extra health health = 235 + light_system = MOVABLE_LIGHT light_range = 3 light_power = 2.5 light_color = LIGHT_COLOR_LAVA diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm index 32e1c4d047be..25621a8ff420 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/ghost.dm @@ -31,6 +31,9 @@ movement_type = FLYING pressure_resistance = 300 gold_core_spawnable = NO_SPAWN //too spooky for science + light_system = MOVABLE_LIGHT + light_range = 1 // same glowing as visible player ghosts + light_power = 2 var/ghost_hair_style var/ghost_hair_color var/mutable_appearance/ghost_hair @@ -42,7 +45,6 @@ /mob/living/simple_animal/hostile/retaliate/ghost/Initialize() . = ..() give_hair() - set_light(1, 2) // same glowing as visible player ghosts if(random) switch(rand(0,1)) if(0) diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm index 2cf3dbb59c69..92498ad82fae 100644 --- a/code/modules/modular_computers/computers/item/computer.dm +++ b/code/modules/modular_computers/computers/item/computer.dm @@ -55,6 +55,12 @@ max_integrity = 100 armor = list(MELEE = 0, BULLET = 20, LASER = 20, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 0, ACID = 0) + light_system = MOVABLE_LIGHT + light_range = 3 + light_power = 0.6 + light_color = "#FFFFFF" + light_on = FALSE + /// List of "connection ports" in this computer and the components with which they are plugged var/list/all_components = list() /// Lazy List of extra hardware slots that can be used modularly. @@ -67,12 +73,10 @@ var/obj/physical = null ///If the computer has a flashlight/LED light/what-have-you installed var/has_light = FALSE - ///If that light is enabled - var/light_on = FALSE ///The brightness of that light var/comp_light_luminosity = 3 ///The color of that light - var/comp_light_color + var/comp_light_color = "#FFFFFF" // Preset Stuff var/list/starting_components = list() @@ -88,7 +92,8 @@ START_PROCESSING(SSobj, src) if(!physical) physical = src - comp_light_color = "#FFFFFF" + set_light_color(comp_light_color) + set_light_range(comp_light_luminosity) idle_threads = list() install_starting_components() install_starting_files() @@ -503,6 +508,34 @@ update_icon() play_computer_sound(shutdown_sound, get_clamped_volume(), FALSE) +/** + * Toggles the computer's flashlight, if it has one. + * + * Called from ui_act(), does as the name implies. + * It is seperated from ui_act() to be overwritten as needed. +*/ +/obj/item/modular_computer/proc/toggle_flashlight() + if(!has_light) + return FALSE + set_light_on(!light_on) + update_icon() + return TRUE + +/** + * Sets the computer's light color, if it has a light. + * + * Called from ui_act(), this proc takes a color string and applies it. + * It is seperated from ui_act() to be overwritten as needed. + * Arguments: + ** color is the string that holds the color value that we should use. Proc auto-fails if this is null. +*/ +/obj/item/modular_computer/proc/set_flashlight_color(color) + if(!has_light || !color) + return FALSE + comp_light_color = color + set_light_color(color) + return TRUE + /obj/item/modular_computer/screwdriver_act(mob/user, obj/item/tool) if(!all_components.len) to_chat(user, "This device doesn't have any components installed.") diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index a071d6e9f56f..cb6f3f7aa702 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -176,12 +176,7 @@ if("PC_toggle_light") play_interact_sound() - light_on = !light_on - if(light_on) - set_light(comp_light_luminosity, 1, comp_light_color) - else - set_light(0) - return TRUE + return toggle_flashlight() if("PC_light_color") var/mob/user = usr @@ -195,10 +190,7 @@ if(color_hex2num(new_color) < 200) //Colors too dark are rejected to_chat(user, span_warning("That color is too dark! Choose a lighter one.")) new_color = null - comp_light_color = new_color - light_color = new_color - update_light() - return TRUE + return set_flashlight_color(new_color) if("PC_Eject_Disk") var/param = params["name"] diff --git a/code/modules/modular_computers/hardware/recharger.dm b/code/modules/modular_computers/hardware/recharger.dm index 5c65d9d9a028..37a86e5b5947 100644 --- a/code/modules/modular_computers/hardware/recharger.dm +++ b/code/modules/modular_computers/hardware/recharger.dm @@ -41,8 +41,8 @@ if(!istype(A)) return FALSE - if(A.powered(EQUIP)) - A.use_power(amount, EQUIP) + if(A.powered(AREA_USAGE_EQUIP)) + A.use_power(amount, AREA_USAGE_EQUIP) return TRUE return FALSE diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 331e1872b2b7..19bfc350c5e3 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -17,7 +17,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 30 active_power_usage = 200 - power_channel = EQUIP + power_channel = AREA_USAGE_EQUIP max_integrity = 300 integrity_failure = 100 var/insert_anim = "photocopier1" diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 0378ce7655e4..d2fc3a8d4564 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -8,8 +8,11 @@ item_state = "camera" lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - light_color = LIGHT_COLOR_WHITE + light_system = MOVABLE_LIGHT //Used as a flash here. + light_range = 8 + light_color = COLOR_WHITE light_power = FLASH_LIGHT_POWER + light_on = FALSE w_class = WEIGHT_CLASS_SMALL flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_NECK @@ -200,7 +203,8 @@ /obj/item/camera/proc/captureimage(atom/target, mob/user, flag, size_x = 1, size_y = 1) if(flash_enabled) - flash_lighting_fx(8, light_power, light_color) + set_light_on(TRUE) + addtimer(CALLBACK(src, .proc/flash_end), FLASH_LIGHT_DURATION, TIMER_OVERRIDE|TIMER_UNIQUE) blending = TRUE var/turf/target_turf = get_turf(target) if(!isturf(target_turf)) @@ -248,6 +252,9 @@ after_picture(user, P, flag) blending = FALSE +/obj/item/camera/proc/flash_end() + set_light_on(FALSE) + /obj/item/camera/proc/after_picture(mob/user, datum/picture/picture, proximity_flag) printpicture(user, picture) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 5cabc64fe4c0..2f8f0a59fb7f 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -1255,12 +1255,12 @@ force_update = 1 return - lastused_light = area.usage(STATIC_LIGHT) - lastused_light += area.usage(LIGHT) - lastused_equip = area.usage(EQUIP) - lastused_equip += area.usage(STATIC_EQUIP) - lastused_environ = area.usage(ENVIRON) - lastused_environ += area.usage(STATIC_ENVIRON) + lastused_light = area.usage(AREA_USAGE_STATIC_LIGHT) + lastused_light += area.usage(AREA_USAGE_LIGHT) + lastused_equip = area.usage(AREA_USAGE_EQUIP) + lastused_equip += area.usage(AREA_USAGE_STATIC_EQUIP) + lastused_environ = area.usage(AREA_USAGE_ENVIRON) + lastused_environ += area.usage(AREA_USAGE_STATIC_ENVIRON) area.clear_usage() lastused_total = lastused_light + lastused_equip + lastused_environ diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 902f8528160f..7adcdd8e07cb 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -112,7 +112,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne icon_state = "on_8" idle_power_usage = 0 active_power_usage = 3000 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON sprite_number = 8 use_power = IDLE_POWER_USE interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 21102fbf7f5d..c40cc5eec4d0 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -218,7 +218,7 @@ use_power = ACTIVE_POWER_USE idle_power_usage = 2 active_power_usage = 20 - power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list + 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/forced_off = FALSE @@ -415,9 +415,9 @@ on_gs = on if(on) static_power_used = brightness * 20 //20W per unit luminosity - addStaticPower(static_power_used, STATIC_LIGHT) + addStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) else - removeStaticPower(static_power_used, STATIC_LIGHT) + removeStaticPower(static_power_used, AREA_USAGE_STATIC_LIGHT) broken_sparks(start_only=TRUE) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 4341b21331de..bacac756eae7 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -479,9 +479,7 @@ if(!user.transferItemToLoc(I, src)) return to_chat(user, span_notice("You click [S] into place on [src].")) - if(S.on) - set_light(0) - gun_light = S + set_gun_light(S) update_gunlight() alight = new(src) if(loc == user) @@ -569,12 +567,28 @@ if(!gun_light) return var/obj/item/flashlight/seclite/removed_light = gun_light - gun_light = null + set_gun_light(null) update_gunlight() removed_light.update_brightness() QDEL_NULL(alight) return TRUE +///Called when gun_light value changes. +/obj/item/gun/proc/set_gun_light(obj/item/flashlight/seclite/new_light) + if(gun_light == new_light) + return + . = gun_light + gun_light = new_light + if(gun_light) + gun_light.set_light_flags(gun_light.light_flags | LIGHT_ATTACHED) + if(gun_light.loc != src) + gun_light.forceMove(src) + else if(.) + var/obj/item/flashlight/seclite/old_gun_light = . + old_gun_light.set_light_flags(old_gun_light.light_flags & ~LIGHT_ATTACHED) + if(old_gun_light.loc == src) + old_gun_light.forceMove(get_turf(src)) + /obj/item/gun/ui_action_click(mob/user, actiontype) if(istype(actiontype, alight)) toggle_gunlight() @@ -587,30 +601,14 @@ var/mob/living/carbon/human/user = usr gun_light.on = !gun_light.on + gun_light.update_brightness() to_chat(user, span_notice("You toggle the gunlight [gun_light.on ? "on":"off"].")) playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) update_gunlight() /obj/item/gun/proc/update_gunlight() - if(gun_light) - if(gun_light.on) - set_light(gun_light.brightness_on) - else - set_light(0) - cut_overlay(flashlight_overlay, TRUE) - var/state = "flight[gun_light.on? "_on":""]" //Generic state. - if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state? - state = gun_light.icon_state - flashlight_overlay = mutable_appearance('icons/obj/guns/flashlights.dmi', state) - flashlight_overlay.pixel_x = flight_x_offset - flashlight_overlay.pixel_y = flight_y_offset - add_overlay(flashlight_overlay, TRUE) - else - set_light(0) - cut_overlay(flashlight_overlay, TRUE) - flashlight_overlay = null - update_icon(TRUE) + update_icon() for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 33d264533c73..afa813728e0b 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -22,7 +22,7 @@ can_flashlight = FALSE // Can't attach or detach the flashlight, and override it's icon update /obj/item/gun/energy/e_gun/mini/Initialize() - gun_light = new /obj/item/flashlight/seclite(src) + set_gun_light(new /obj/item/flashlight/seclite(src)) return ..() /obj/item/gun/energy/e_gun/mini/update_icon() diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 498e54d2bffc..783e14d9af63 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -5,14 +5,16 @@ damage = 20 wound_bonus = -20 bare_wound_bonus = 10 - light_range = 2 damage_type = BURN hitsound = 'sound/weapons/sear.ogg' hitsound_wall = 'sound/weapons/effects/searwall.ogg' flag = LASER eyeblur = 2 impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser + light_system = MOVABLE_LIGHT + light_range = 2 light_color = LIGHT_COLOR_RED + light_flags = LIGHT_NO_LUMCOUNT ricochets_max = 50 //Honk! ricochet_chance = 80 reflectable = REFLECT_NORMAL diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index dbc95036aecf..926cd63242aa 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -690,12 +690,30 @@ description = "A stimulating ichor which causes luminescent fungi to grow on the skin. " color = "#b5a213" taste_description = "tingling mushroom" + //Lazy list of mobs affected by the luminosity of this reagent. + var/list/mobs_affected -/datum/reagent/consumable/tinlux/on_mob_metabolize(mob/living/M) - M.set_light(2) +/datum/reagent/consumable/tinlux/reaction_mob(mob/living/M) + add_reagent_light(M) /datum/reagent/consumable/tinlux/on_mob_end_metabolize(mob/living/M) - M.set_light(-2) + remove_reagent_light(M) + +/datum/reagent/consumable/tinlux/proc/on_living_holder_deletion(mob/living/source) + remove_reagent_light(source) + +/datum/reagent/consumable/tinlux/proc/add_reagent_light(mob/living/living_holder) + var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = living_holder.mob_light(2) + mob_light_obj.set_light_color("#b5a213") + LAZYSET(mobs_affected, living_holder, mob_light_obj) + RegisterSignal(living_holder, COMSIG_PARENT_QDELETING, .proc/on_living_holder_deletion) + +/datum/reagent/consumable/tinlux/proc/remove_reagent_light(mob/living/living_holder) + UnregisterSignal(living_holder, COMSIG_PARENT_QDELETING) + var/obj/effect/dummy/lighting_obj/moblight/mob_light_obj = LAZYACCESS(mobs_affected, living_holder) + LAZYREMOVE(mobs_affected, living_holder) + if(mob_light_obj) + qdel(mob_light_obj) /datum/reagent/consumable/vitfro name = "Vitrium Froth" diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index dc8d709ef516..24f81e284d08 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -251,7 +251,7 @@ var/range = created_volume/3 if(isatom(holder.my_atom)) var/atom/A = holder.my_atom - A.flash_lighting_fx(_range = (range + 2), _reset_lighting = FALSE) + A.flash_lighting_fx(_range = (range + 2)) for(var/mob/living/carbon/C in get_hearers_in_view(range, location)) if(C.flash_act()) if(get_dist(C, location) < 4) @@ -272,7 +272,7 @@ var/range = created_volume/10 if(isatom(holder.my_atom)) var/atom/A = holder.my_atom - A.flash_lighting_fx(_range = (range + 2), _reset_lighting = FALSE) + A.flash_lighting_fx(_range = (range + 2)) for(var/mob/living/carbon/C in get_hearers_in_view(range, location)) if(C.flash_act()) if(get_dist(C, location) < 4) diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index abb96d99fb7a..fc4c858f33e1 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -12,7 +12,7 @@ GLOBAL_DATUM_INIT(keycard_events, /datum/events, new) use_power = IDLE_POWER_USE idle_power_usage = 2 active_power_usage = 6 - power_channel = ENVIRON + power_channel = AREA_USAGE_ENVIRON req_access = list(ACCESS_KEYCARD_AUTH) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF var/datum/callback/ev diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 980c28bf78ff..7c135ac2eb20 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -82,7 +82,8 @@ icon_state = "bluespace" color = "#003300" light_color = "#003300" - var/lon_range = 3 + light_system = MOVABLE_LIGHT + light_range = 3 var/resurrections = 0 var/datum/mind/mind var/respawn_time = 1800 @@ -97,7 +98,6 @@ active_phylacteries++ GLOB.poi_list |= src START_PROCESSING(SSobj, src) - set_light(lon_range) if(initial(SSticker.mode.round_ends_with_antag_death)) SSticker.mode.round_ends_with_antag_death = FALSE diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index a6388afb6c05..648901ea203a 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -258,7 +258,7 @@ var/active = FALSE var/max_light_beam_distance = 5 var/light_beam_distance = 5 - var/light_object_range = 1 + var/light_object_range = 2 var/light_object_power = 2 var/list/obj/effect/abstract/eye_lighting/eye_lighting var/obj/effect/abstract/eye_lighting/on_mob @@ -369,6 +369,7 @@ clear_visuals() var/turf/scanning = scanfrom var/stop = FALSE + on_mob.set_light_flags(on_mob.light_flags & ~LIGHT_ATTACHED) on_mob.forceMove(scanning) for(var/i in 1 to light_beam_distance) scanning = get_step(scanning, scandir) @@ -389,6 +390,7 @@ var/obj/effect/abstract/eye_lighting/L = i L.forceMove(src) if(!QDELETED(on_mob)) + on_mob.set_light_flags(on_mob.light_flags | LIGHT_ATTACHED) on_mob.forceMove(src) /obj/item/organ/eyes/robotic/glow/proc/start_visuals() @@ -405,26 +407,35 @@ /obj/item/organ/eyes/robotic/glow/proc/regenerate_light_effects() clear_visuals(TRUE) - on_mob = new(src) + on_mob = new (src, light_object_range, light_object_power, current_color_string, LIGHT_ATTACHED) for(var/i in 1 to light_beam_distance) - LAZYADD(eye_lighting,new /obj/effect/abstract/eye_lighting(src)) + LAZYADD(eye_lighting, new /obj/effect/abstract/eye_lighting(src, light_object_range, light_object_power, current_color_string)) sync_light_effects() /obj/item/organ/eyes/robotic/glow/proc/sync_light_effects() - for(var/I in eye_lighting) - var/obj/effect/abstract/eye_lighting/L = I - L.set_light(light_object_range, light_object_power, current_color_string) - if(on_mob) - on_mob.set_light(1, 1, current_color_string) + for(var/e in eye_lighting) + var/obj/effect/abstract/eye_lighting/eye_lighting = e + eye_lighting.set_light_color(current_color_string) + on_mob?.set_light_color(current_color_string) /obj/effect/abstract/eye_lighting + light_system = MOVABLE_LIGHT var/obj/item/organ/eyes/robotic/glow/parent -/obj/effect/abstract/eye_lighting/Initialize() +/obj/effect/abstract/eye_lighting/Initialize(mapload, light_object_range, light_object_power, current_color_string, light_flags) . = ..() parent = loc if(!istype(parent)) + stack_trace("/obj/effect/abstract/eye_lighting added to improper parent ([loc]). Deleting.") return INITIALIZE_HINT_QDEL + if(!isnull(light_object_range)) + set_light_range(light_object_range) + if(!isnull(light_object_power)) + set_light_power(light_object_power) + if(!isnull(current_color_string)) + set_light_color(current_color_string) + if(!isnull(light_flags)) + set_light_flags(light_flags) /obj/item/organ/eyes/moth name = "moth eyes" diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index aca532c20ef5..11ac9b4b2acb 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -394,6 +394,8 @@ hitsound = 'sound/weapons/blade1.ogg' force = 16 toolspeed = 0.7 + light_system = MOVABLE_LIGHT + light_range = 1 light_color = LIGHT_COLOR_GREEN sharpness = SHARP_EDGED @@ -403,13 +405,13 @@ if(tool_behaviour == TOOL_SCALPEL) tool_behaviour = TOOL_SAW to_chat(user, span_notice("You increase the power, now it can cut bones.")) - set_light(2) + set_light_range(2) force += 1 //we don't want to ruin sharpened stuff icon_state = "saw_a" else tool_behaviour = TOOL_SCALPEL to_chat(user, span_notice("You lower the power, it can now make precise incisions.")) - set_light(1) + set_light_range(1) force -= 1 icon_state = "scalpel_a" @@ -448,10 +450,6 @@ toolspeed = 0.7 light_color = LIGHT_COLOR_RED -/obj/item/cautery/advanced/Initialize() - . = ..() - set_light(1) - /obj/item/cautery/advanced/attack_self(mob/user) if(tool_behaviour == TOOL_CAUTERY) diff --git a/code/modules/swarmers/swarmer.dm b/code/modules/swarmers/swarmer.dm index cba60fc899ca..62f9160effb1 100644 --- a/code/modules/swarmers/swarmer.dm +++ b/code/modules/swarmers/swarmer.dm @@ -69,6 +69,10 @@ var/list/mob/living/simple_animal/hostile/swarmer/melee/dronelist ///Prevents alert spam var/last_alert = 0 + light_system = MOVABLE_LIGHT + light_range = 3 + ///Bitflags to store boolean conditions, such as whether the light is on or off. + var/swarmer_flags = NONE /mob/living/simple_animal/hostile/swarmer/Initialize() . = ..() @@ -398,20 +402,26 @@ * Proc used to allow a swarmer to toggle its light on and off. If a swarmer has any drones, change their light settings to match their master's. */ /mob/living/simple_animal/hostile/swarmer/proc/toggle_light() - if(!light_range) - set_light(3) + if(swarmer_flags & SWARMER_LIGHT_ON) + swarmer_flags = ~SWARMER_LIGHT_ON + set_light_on(FALSE) if(!mind) return for(var/d in dronelist) var/mob/living/simple_animal/hostile/swarmer/melee/drone = d - drone.set_light(3) - else - set_light(0) - if(!mind) - return - for(var/d in dronelist) - var/mob/living/simple_animal/hostile/swarmer/melee/drone = d - drone.set_light(0) + drone.swarmer_flags = ~SWARMER_LIGHT_ON + drone.set_light_on(FALSE) + return + swarmer_flags |= SWARMER_LIGHT_ON + set_light_on(TRUE) + if(!mind) + return + + for(var/d in dronelist) + var/mob/living/simple_animal/hostile/swarmer/melee/drone = d + drone.swarmer_flags |= SWARMER_LIGHT_ON + drone.set_light_on(TRUE) + balloon_alert(src, "light toggled") /** diff --git a/config/game_options.txt b/config/game_options.txt index 6d37a1f8401f..0a4b26aa9553 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -126,7 +126,7 @@ PROBABILITY CULT 5 PROBABILITY CLOCKWORK_CULT 5 # Snowflakes -PROBABILITY SHADOWLING 6 +PROBABILITY SHADOWLING 0 //For now PROBABILITY WIZARD 8 PROBABILITY NUCLEAR 9 PROBABILITY MALF 8 diff --git a/icons/effects/light_overlays/light_128.dmi b/icons/effects/light_overlays/light_128.dmi new file mode 100644 index 000000000000..22dc0b010870 Binary files /dev/null and b/icons/effects/light_overlays/light_128.dmi differ diff --git a/icons/effects/light_overlays/light_160.dmi b/icons/effects/light_overlays/light_160.dmi new file mode 100644 index 000000000000..26dfa453c516 Binary files /dev/null and b/icons/effects/light_overlays/light_160.dmi differ diff --git a/icons/effects/light_overlays/light_192.dmi b/icons/effects/light_overlays/light_192.dmi new file mode 100644 index 000000000000..aca94ee0caf5 Binary files /dev/null and b/icons/effects/light_overlays/light_192.dmi differ diff --git a/icons/effects/light_overlays/light_224.dmi b/icons/effects/light_overlays/light_224.dmi new file mode 100644 index 000000000000..9fab531d1a69 Binary files /dev/null and b/icons/effects/light_overlays/light_224.dmi differ diff --git a/icons/effects/light_overlays/light_256.dmi b/icons/effects/light_overlays/light_256.dmi new file mode 100644 index 000000000000..701562efcd8f Binary files /dev/null and b/icons/effects/light_overlays/light_256.dmi differ diff --git a/icons/effects/light_overlays/light_288.dmi b/icons/effects/light_overlays/light_288.dmi new file mode 100644 index 000000000000..b6eac180f7aa Binary files /dev/null and b/icons/effects/light_overlays/light_288.dmi differ diff --git a/icons/effects/light_overlays/light_32.dmi b/icons/effects/light_overlays/light_32.dmi new file mode 100644 index 000000000000..5269b1fba36d Binary files /dev/null and b/icons/effects/light_overlays/light_32.dmi differ diff --git a/icons/effects/light_overlays/light_320.dmi b/icons/effects/light_overlays/light_320.dmi new file mode 100644 index 000000000000..bf263c4b29be Binary files /dev/null and b/icons/effects/light_overlays/light_320.dmi differ diff --git a/icons/effects/light_overlays/light_352.dmi b/icons/effects/light_overlays/light_352.dmi new file mode 100644 index 000000000000..f895792da42d Binary files /dev/null and b/icons/effects/light_overlays/light_352.dmi differ diff --git a/icons/effects/light_overlays/light_64.dmi b/icons/effects/light_overlays/light_64.dmi new file mode 100644 index 000000000000..37fc5084abcf Binary files /dev/null and b/icons/effects/light_overlays/light_64.dmi differ diff --git a/icons/effects/light_overlays/light_96.dmi b/icons/effects/light_overlays/light_96.dmi new file mode 100644 index 000000000000..b689a1370163 Binary files /dev/null and b/icons/effects/light_overlays/light_96.dmi differ diff --git a/yogstation.dme b/yogstation.dme index e58601ecdd7a..6ea0841dbf4f 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -487,6 +487,7 @@ #include "code\datums\components\nanites.dm" #include "code\datums\components\ntnet_interface.dm" #include "code\datums\components\orbiter.dm" +#include "code\datums\components\overlay_lighting.dm" #include "code\datums\components\paintable.dm" #include "code\datums\components\rad_insulation.dm" #include "code\datums\components\radioactive.dm" @@ -721,6 +722,7 @@ #include "code\game\atoms_movable.dm" #include "code\game\communications.dm" #include "code\game\data_huds.dm" +#include "code\game\movable_luminosity.dm" #include "code\game\say.dm" #include "code\game\shuttle_engines.dm" #include "code\game\sound.dm" diff --git a/yogstation/code/game/mecha/makeshift/lockermech.dm b/yogstation/code/game/mecha/makeshift/lockermech.dm index debf217e4a13..2bd3abe045a4 100644 --- a/yogstation/code/game/mecha/makeshift/lockermech.dm +++ b/yogstation/code/game/mecha/makeshift/lockermech.dm @@ -4,7 +4,7 @@ icon = 'yogstation/icons/mecha/lockermech.dmi' icon_state = "lockermech" max_integrity = 100 //its made of scraps - lights_power = 5 + light_power = 5 step_in = 4 //Same speed as a ripley, for now. armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 60) //Same armour as a locker internal_damage_threshold = 30 //Its got shitty durability diff --git a/yogstation/code/game/objects/structures/beds_chairs/electric_bed.dm b/yogstation/code/game/objects/structures/beds_chairs/electric_bed.dm index b17033d78e52..b91ca88bea9d 100644 --- a/yogstation/code/game/objects/structures/beds_chairs/electric_bed.dm +++ b/yogstation/code/game/objects/structures/beds_chairs/electric_bed.dm @@ -26,9 +26,9 @@ var/area/A = get_area(src) if(!isarea(A)) return - if(!A.powered(EQUIP)) + if(!A.powered(AREA_USAGE_EQUIP)) return - A.use_power(EQUIP, 5000) + A.use_power(AREA_USAGE_EQUIP, 5000) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(12, 1, src) diff --git a/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/umbral_tendrils.dm b/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/umbral_tendrils.dm index 766984d00dc7..5aec8b8c0b97 100644 --- a/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/umbral_tendrils.dm +++ b/yogstation/code/modules/antagonists/darkspawn/darkspawn_objects/umbral_tendrils.dm @@ -78,9 +78,7 @@ /obj/item/umbral_tendrils/proc/disintegrate(obj/item/O) if(istype(O, /obj/item/pda)) var/obj/item/pda/PDA = O - PDA.set_light(0) - PDA.fon = FALSE - PDA.f_lum = 0 + PDA.set_light_on(FALSE) PDA.update_icon() visible_message(span_danger("The light in [PDA] shorts out!")) else diff --git a/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm b/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm index ea8d832aeb18..5c39824f1cc3 100644 --- a/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm +++ b/yogstation/code/modules/antagonists/shadowling/shadowling_abilities.dm @@ -113,7 +113,7 @@ var/blacklisted_lights = list(/obj/item/flashlight/flare, /obj/item/flashlight/slime) if(istype(I, /obj/item/flashlight)) var/obj/item/flashlight/F = I - if(F.on) + if(F.light_on) if(cold) if(is_type_in_list(F, blacklisted_lights)) F.visible_message(span_warning("The sheer cold shatters [F]!")) @@ -122,13 +122,13 @@ return if(is_type_in_list(I, blacklisted_lights)) I.visible_message(span_danger("[I] dims slightly before scattering the shadows around it.")) - return F.brightness_on //Necessary because flashlights become 0-luminosity when held. I don't make the rules of lightcode. - F.on = FALSE + return F.light_power //Necessary because flashlights become 0-luminosity when held. I don't make the rules of lightcode. + F.set_light_on(FALSE) F.update_brightness() else if(istype(I, /obj/item/pda)) var/obj/item/pda/P = I - P.fon = FALSE - I.set_light(0) + P.set_light_on(FALSE) + I.set_light_on(FALSE) return I.luminosity /obj/effect/proc_holder/spell/aoe_turf/proc/extinguishMob(mob/living/H, cold = FALSE) @@ -159,7 +159,7 @@ return to_chat(user, span_shadowling("You silently disable all nearby lights.")) var/turf/T = get_turf(user) - for(var/datum/light_source/LS in T.affecting_lights) + for(var/datum/light_source/LS in T.get_affecting_lights()) var/atom/LO = LS.source_atom if(isitem(LO)) extinguishItem(LO) diff --git a/yogstation/code/modules/clothing/chameleon.dm b/yogstation/code/modules/clothing/chameleon.dm index 95b215ebc806..74215f6649ea 100644 --- a/yogstation/code/modules/clothing/chameleon.dm +++ b/yogstation/code/modules/clothing/chameleon.dm @@ -1,5 +1,4 @@ /datum/action/item_action/chameleon/change/update_item(obj/item/picked_item, obj/item/target = target) ..() if(ispath(picked_item, /obj/item/pda) && istype(target, /obj/item/pda)) - target.light_color = initial(picked_item.light_color) - target.update_light() + target.set_light_color(initial(picked_item.light_color)) diff --git a/yogstation/code/modules/guardian/guardian.dm b/yogstation/code/modules/guardian/guardian.dm index bc8349ec17ac..a4b0e6bb390d 100644 --- a/yogstation/code/modules/guardian/guardian.dm +++ b/yogstation/code/modules/guardian/guardian.dm @@ -44,6 +44,9 @@ GLOBAL_LIST_INIT(guardian_projectile_damage, list( melee_damage_lower = 15 melee_damage_upper = 15 AIStatus = AI_OFF + light_system = MOVABLE_LIGHT + light_range = 3 + light_on = FALSE hud_type = /datum/hud/guardian see_in_dark = 8 var/list/barrier_images = list() @@ -547,12 +550,12 @@ GLOBAL_LIST_INIT(guardian_projectile_damage, list( cooldown = world.time + 10 /mob/living/simple_animal/hostile/guardian/proc/ToggleLight() - if (light_range<3) + if(!light_on) to_chat(src, span_notice("You activate your light.")) - set_light(3) + set_light_on(TRUE) else to_chat(src, span_notice("You deactivate your light.")) - set_light(0) + set_light_on(FALSE) /mob/living/simple_animal/hostile/guardian/verb/show_detail() set name = "Show Powers"