diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index e2c04299f1..448726bf0d 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -366,3 +366,35 @@ datum/projectile_data var/dest_y = src_y + distance*cos(rotation); return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y) + +/proc/GetRedPart(const/hexa) + var/hex = uppertext(hexa) + var/hi = text2ascii(hex, 2) + var/lo = text2ascii(hex, 3) + return (((hi >= 65 ? hi - 55 : hi - 48) << 4) | (lo >= 65 ? lo - 55 : lo - 48)) + +/proc/GetGreenPart(const/hexa) + var/hex = uppertext(hexa) + var/hi = text2ascii(hex, 4) + var/lo = text2ascii(hex, 5) + return (((hi >= 65 ? hi - 55 : hi - 48) << 4) | (lo >= 65 ? lo - 55 : lo - 48)) + +/proc/GetBluePart(const/hexa) + var/hex = uppertext(hexa) + var/hi = text2ascii(hex, 6) + var/lo = text2ascii(hex, 7) + return (((hi >= 65 ? hi - 55 : hi - 48) << 4) | (lo >= 65 ? lo - 55 : lo - 48)) + +/proc/GetHexColors(const/hexa) + var/hex = uppertext(hexa) + var/hi1 = text2ascii(hex, 2) + var/lo1 = text2ascii(hex, 3) + var/hi2 = text2ascii(hex, 4) + var/lo2 = text2ascii(hex, 5) + var/hi3 = text2ascii(hex, 6) + var/lo3 = text2ascii(hex, 7) + return list( + ((hi1 >= 65 ? hi1 - 55 : hi1 - 48) << 4) | (lo1 >= 65 ? lo1 - 55 : lo1 - 48), + ((hi2 >= 65 ? hi2 - 55 : hi2 - 48) << 4) | (lo2 >= 65 ? lo2 - 55 : lo2 - 48), + ((hi3 >= 65 ? hi3 - 55 : hi3 - 48) << 4) | (lo3 >= 65 ? lo3 - 55 : lo3 - 48) + ) diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm index b551d86c75..69d01e3d35 100644 --- a/code/__HELPERS/logging.dm +++ b/code/__HELPERS/logging.dm @@ -6,11 +6,12 @@ // in the logs. ascii character 13 = CR /var/global/log_end= world.system_type == UNIX ? ascii2text(13) : "" - + /proc/error(msg) world.log << "## ERROR: [msg][log_end]" +#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].") //print a warning message to world.log /proc/warning(msg) world.log << "## WARNING: [msg][log_end]" @@ -79,4 +80,4 @@ diary << "\[[time_stamp()]]PDA: [text][log_end]" /proc/log_misc(text) - diary << "\[[time_stamp()]]MISC: [text][log_end]" + diary << "\[[time_stamp()]]MISC: [text][log_end]" diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index b174147d58..d36551f1d6 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -3,6 +3,11 @@ var/const/E = 2.71828183 var/const/Sqrt2 = 1.41421356 +// List of square roots for the numbers 1-100. +var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10) /proc/Atan2(x, y) if(!x && !y) return 0 diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm index 5f87620780..c7000425f1 100644 --- a/code/controllers/_DynamicAreaLighting_TG.dm +++ b/code/controllers/_DynamicAreaLighting_TG.dm @@ -5,9 +5,10 @@ ShadowDarke's respective lighting libraries. Credits, where due, to them. Like sd_DAL (what we used to use), it changes the shading overlays of areas by splitting each type of area into sub-areas - by using the var/tag variable and moving turfs into the contents list of the correct sub-area. + by using the var/tag variable and moving turfs into the contents list of the correct sub-area. This method is + much less costly than using overlays or objects. - Unlike sd_DAL however it uses a queueing system. Everytime we call a change to opacity or luminosity + Unlike sd_DAL however it uses a queueing system. Everytime we call a change to opacity or luminosity (through SetOpacity() or SetLuminosity()) we are simply updating variables and scheduling certain lights/turfs for an update. Actual updates are handled periodically by the lighting_controller. This carries additional overheads, however it means that each thing is changed only once per lighting_controller.processing_interval ticks. Allowing for greater control @@ -15,50 +16,40 @@ setting lighting_controller.processing = 0 at say, the start of a large explosion, waiting for it to finish, and then turning it back on with lighting_controller.processing = 1. - Unlike our old system there is a hardcoded maximum luminosity. This is to discourage coders using large luminosity values - for dynamic lighting, as the cost of lighting grows rapidly at large luminosity levels (especially when changing opacity - at runtime) + Unlike our old system there are hardcoded maximum luminositys (different for certain atoms). + This is to cap the cost of creating lighting effects. + (without this, an atom with luminosity of 20 would have to update 41^2 turfs!) :s Also, in order for the queueing system to work, each light remembers the effect it casts on each turf. This is going to - have larger memory requirements than our previous system but hopefully it's worth the hassle for the greater control we - gain. Besides, there are far far worse uses of needless lists in the game, it'd be worth pruning some of them to offset - costs. + have larger memory requirements than our previous system but it's easily worth the hassle for the greater control we + gain. It also reduces cost of removing lighting effects by a lot! Known Issues/TODO: - admin-spawned turfs will have broken lumcounts. Not willing to fix it at this moment - mob luminosity will be lower than expected when one of multiple light sources is dropped after exceeding the maximum luminosity Shuttles still do not have support for dynamic lighting (I hope to fix this at some point) - No directional lighting support. Fairly easy to add this and the code is ready. + No directional lighting support. (prototype looked ugly) */ -#define LIGHTING_MAX_LUMINOSITY 12 //Hard maximum luminosity to prevet lag which could be caused by coders making mini-suns -#define LIGHTING_MAX_LUMINOSITY_MOB 7 //Mobs get their own max because 60-odd human suns running around would be pretty silly -#define LIGHTING_LAYER 10 //Drawing layer for lighting overlays -#define LIGHTING_ICON 'icons/effects/ss13_dark_alpha7.dmi' //Icon used for lighting shading effects +#define LIGHTING_CIRCULAR 1 //comment this out to use old square lighting effects. +#define LIGHTING_LAYER 10 //Drawing layer for lighting overlays +#define LIGHTING_ICON 'icons/effects/ss13_dark_alpha6.dmi' //Icon used for lighting shading effects datum/light_source var/atom/owner var/changed = 1 - var/mobile = 1 var/list/effect = list() - var/__x = 0 //x coordinate at last update var/__y = 0 //y coordinate at last update + var/l_color New(atom/A) if(!istype(A)) CRASH("The first argument to the light object's constructor must be the atom that is the light source. Expected atom, received '[A]' instead.") - ..() owner = A - - if(istype(owner, /atom/movable)) mobile = 1 //apparantly this is faster than type-checking - else mobile = 0 //Perhaps removing support for luminous turfs would be a good idea. - + l_color = owner.l_color __x = owner.x __y = owner.y - // the lighting object maintains a list of all light sources lighting_controller.lights += src @@ -69,12 +60,14 @@ datum/light_source remove_effect() return 1 //causes it to be removed from our list of lights. The garbage collector will then destroy it. - if(mobile) - // check to see if we've moved since last update - if(owner.x != __x || owner.y != __y) - __x = owner.x - __y = owner.y - changed = 1 + // check to see if we've moved since last update + if(owner.x != __x || owner.y != __y) + __x = owner.x + __y = owner.y + changed = 1 + + if (owner.l_color != l_color) + changed = 1 if(changed) changed = 0 @@ -85,197 +78,282 @@ datum/light_source proc/remove_effect() // before we apply the effect we remove the light's current effect. - if(effect.len) - for(var/turf in effect) // negate the effect of this light source - var/turf/T = turf - T.update_lumcount(-effect[T]) - effect.Cut() // clear the effect list + for(var/turf/T in effect) // negate the effect of this light source + T.update_lumcount(-effect[T], l_color, 1) + effect.Cut() // clear the effect list proc/add_effect() // only do this if the light is turned on and is on the map if(owner.loc && owner.luminosity > 0) - effect = new_effect() // identify the effects of this light source - for(var/turf in effect) - var/turf/T = turf - T.update_lumcount(effect[T]) // apply the effect + l_color = owner.l_color + effect = list() + for(var/turf/T in view(owner.get_light_range(),owner)) + var/delta_lumen = lum(T) + if(delta_lumen > 0) + effect[T] = delta_lumen + T.update_lumcount(delta_lumen, l_color, 0) + return 0 else owner.light = null return 1 //cause the light to be removed from the lights list and garbage collected once it's no //longer referenced by the queue - proc/new_effect() - . = list() - - for(var/turf/T in view(owner.luminosity, owner)) -// var/area/A = T.loc -// if(!A) continue - var/change_in_lumcount = lum(T) - if(change_in_lumcount > 0) - .[T] = change_in_lumcount - - return . - - proc/lum(turf/A) - return owner.luminosity - max(abs(A.x-__x),abs(A.y-__y)) -// var/dist = cheap_hypotenuse(A.x,A.y,__x,__y) //fetches the pythagorean distance between A and the light -// if(owner.luminosity < dist) //if the turf is outside the radius the light doesn't illuminate it -// return 0 -// return round(owner.luminosity - (dist/2),0.1) + if (owner.trueLuminosity < 1) + return 0 + var/dist + if(!A) + dist = 0 + else +#ifdef LIGHTING_CIRCULAR + dist = cheap_hypotenuse(A.x, A.y, __x, __y) +#else + dist = max(abs(A.x - __x), abs(A.y - __y)) +#endif + if (owner.trueLuminosity > 100) // This will never happen... right? + return sqrt(owner.trueLuminosity) - dist + else + return sqrtTable[owner.trueLuminosity] - dist atom var/datum/light_source/light + var/trueLuminosity = 0 // Typically 'luminosity' squared. The builtin luminosity must remain linear. + // We may read it, but NEVER set it directly. + var/l_color //Turfs with opacity when they are constructed will trigger nearby lights to update -//Turfs atoms with luminosity when they are constructed will create a light_source automatically -//TODO: lag reduction +//Turfs and atoms with luminosity when they are constructed will create a light_source automatically turf/New() ..() - if(opacity) - UpdateAffectingLights() if(luminosity) - world.log << "[type] has luminosity at New()" - if(light) world.log << "## WARNING: [type] - Don't set lights up manually during New(), We do it automatically." + if(light) WARNING("[type] - Don't set lights up manually during New(), We do it automatically.") + trueLuminosity = luminosity * luminosity light = new(src) //Movable atoms with opacity when they are constructed will trigger nearby lights to update //Movable atoms with luminosity when they are constructed will create a light_source automatically -//TODO: lag reduction atom/movable/New() ..() if(opacity) - UpdateAffectingLights() + if(isturf(loc)) + if(loc:lighting_lumcount > 1) + UpdateAffectingLights() if(luminosity) - if(light) world.log << "## WARNING: [type] - Don't set lights up manually during New(), We do it automatically." + if(light) WARNING("[type] - Don't set lights up manually during New(), We do it automatically.") + trueLuminosity = luminosity * luminosity light = new(src) -//Turfs with opacity will trigger nearby lights to update at next lighting process. -//TODO: is this really necessary? Removing it could help reduce lag during singulo-mayhem somewhat -turf/Del() - if(opacity) - UpdateAffectingLights() - ..() - //Objects with opacity will trigger nearby lights to update at next lighting process. atom/movable/Del() if(opacity) - UpdateAffectingLights() + if(isturf(loc)) + if(loc:lighting_lumcount > 1) + UpdateAffectingLights() + ..() -//Sets our luminosity. Enforces a hardcoded maximum luminosity by default. This maximum can be overridden but it is extremely -//unwise to do so. +//Sets our luminosity. //If we have no light it will create one. -//If we are setting luminosity to 0 the light will be cleaned up and delted once all its queues are complete -//if we have a light already it is merely updated -atom/proc/SetLuminosity(new_luminosity, max_luminosity = LIGHTING_MAX_LUMINOSITY) +//If we are setting luminosity to 0 the light will be cleaned up by the controller and garbage collected once all its +//queues are complete. +//if we have a light already it is merely updated, rather than making a new one. +atom/proc/SetLuminosity(new_luminosity, trueLum = FALSE) if(new_luminosity < 0) new_luminosity = 0 -// world.log << "## WARNING: [type] - luminosity cannot be negative" - else if(max_luminosity < new_luminosity) - new_luminosity = max_luminosity -// if(luminosity != new_luminosity) -// world.log << "## WARNING: [type] - LIGHT_MAX_LUMINOSITY exceeded" + if(!trueLum) + new_luminosity *= new_luminosity + if(light) + if(trueLuminosity != new_luminosity) //non-luminous lights are removed from the lights list in add_effect() + light.changed = 1 + else + if(new_luminosity) + light = new(src) + trueLuminosity = new_luminosity + if (trueLuminosity < 1) + luminosity = 0 + else if (trueLuminosity <= 100) + luminosity = sqrtTable[trueLuminosity] + else + luminosity = sqrt(trueLuminosity) - if(isturf(loc)) - if(light) - if(luminosity != new_luminosity) //TODO: remove lights from the light list when they're not luminous? DONE in add_effect - light.changed = 1 - else - if(new_luminosity) - light = new(src) +atom/proc/AddLuminosity(delta_luminosity) + if(delta_luminosity > 0) + SetLuminosity(trueLuminosity + delta_luminosity*delta_luminosity, TRUE) + else if(delta_luminosity < 0) + SetLuminosity(trueLuminosity - delta_luminosity*delta_luminosity, TRUE) - luminosity = new_luminosity +area/SetLuminosity(new_luminosity) //we don't want dynamic lighting for areas + luminosity = !!new_luminosity + trueLuminosity = luminosity -//Snowflake code to prevent mobs becoming suns (lag-prevention) -mob/SetLuminosity(new_luminosity) - ..(new_luminosity,LIGHTING_MAX_LUMINOSITY_MOB) //change our opacity (defaults to toggle), and then update all lights that affect us. -atom/proc/SetOpacity(var/new_opacity) - if(new_opacity == null) new_opacity = !opacity - else if(opacity == new_opacity) return - opacity = new_opacity +atom/proc/SetOpacity(new_opacity) + if(new_opacity == null) + new_opacity = !opacity //default = toggle opacity + else if(opacity == new_opacity) + return 0 //opacity hasn't changed! don't bother doing anything + opacity = new_opacity //update opacity, the below procs now call light updates. + return 1 - UpdateAffectingLights() +turf/SetOpacity(new_opacity) + if(..()==1) //only bother if opacity changed + if(lighting_lumcount) //only bother with an update if our turf is currently affected by a light + UpdateAffectingLights() -//set the changed status of all lights which could have possibly lit this atom. -//We don't need to worry about lights which lit us but moved away, since they will have change status set already -atom/proc/UpdateAffectingLights() - var/turf/T = src - if(!isturf(T)) - T = loc - if(!isturf(T)) return - for(var/atom in range(LIGHTING_MAX_LUMINOSITY,T)) //TODO: this will probably not work very well :( - var/atom/A = atom - if(A.light && A.luminosity) - A.light.changed = 1 //force it to update at next process() +/atom/movable/SetOpacity(new_opacity) + if(..()==1) //only bother if opacity changed + if(isturf(loc)) //only bother with an update if we're on a turf + var/turf/T = loc + if(T.lighting_lumcount) //only bother with an update if our turf is currently affected by a light + UpdateAffectingLights() -// for(var/light in lighting_controller.lights) //TODO: this will probably laaaaaag -// var/datum/light_source/L = light -// if(L.changed) continue -// if(!L.owner) continue -// if(!L.owner.luminosity) continue -// if(src in L.effect) -// L.changed = 1 turf var/lighting_lumcount = 0 var/lighting_changed = 0 + var/color_lighting_lumcount = 0 + var/list/colors = list() turf/space lighting_lumcount = 4 //starlight -turf/proc/update_lumcount(amount) +turf/proc/update_lumcount(amount, _lcolor, removing = 0) lighting_lumcount += amount -// if(lighting_lumcount < 0 || lighting_lumcount > 100) -// world.log << "## WARNING: [type] ([src]) lighting_lumcount = [lighting_lumcount]" + var/blended + + if (_lcolor) + if (l_color && _lcolor && l_color != _lcolor && !removing) // Blend colors. + var/redblend = min((GetRedPart(l_color)) + (GetRedPart(_lcolor)), 255) + var/greenblend = min((GetGreenPart(l_color)) + (GetGreenPart(_lcolor)), 255) + var/blueblend = min((GetBluePart(l_color)) + (GetBluePart(_lcolor)), 255) + blended = "#[add_zero2(num2hex(redblend), 2)][add_zero2(num2hex(greenblend),2)][add_zero2(num2hex(blueblend),2)]" + + if (removing) + colors.Remove(_lcolor) // Remove the color that's leaving us from our list. + + if (colors && !colors.len) + l_color = null // All our color is gone, no color for us. + else if (colors && colors.len > 1) + var/maxdepth = 3 // Will blend 3 colors, anymore than that and it looks bad or we will get lag on every tile update. + var/currentblended + + for (var/i = 0, ++i <= colors.len) + if (i > maxdepth) + //world << "Maxdepth reached, breaking loop." + break + + if (!currentblended) + //world << "First iteration, currentblended = [colors[i]]." + currentblended = colors[i] // Start with the first of the remaining colors. + continue + + var/redblend = min((GetRedPart(currentblended)) + (GetRedPart(colors[i])), 255) + var/greenblend = min((GetGreenPart(currentblended)) + (GetGreenPart(colors[i])), 255) + var/blueblend = min((GetBluePart(currentblended)) + (GetBluePart(colors[i])), 255) + currentblended = "#[add_zero2(num2hex(redblend), 2)][add_zero2(num2hex(greenblend), 2)][add_zero2(num2hex(blueblend), 2)]" + //world << "Finished [i] [currentblended]." + + if (currentblended) + //world << "Ended up with [currentblended]" + l_color = currentblended // blended the remaining colors so apply it. + else + l_color = null // Something went wrong, no color for you. + else + l_color = colors[colors.len] + else // we added a color. + colors.Add(_lcolor) // Add the base color to the list. + + if (blended) + l_color = blended // If we had a blended color, this is what we get otherwise. + else + l_color = _lcolor // Basecolor is our color. + + // if ((l_color != LIGHT_WHITE && l_color != "#FFF") || removing) + color_lighting_lumcount = max(color_lighting_lumcount + amount, 0) // Minimum of 0. + if(!lighting_changed) lighting_controller.changed_turfs += src lighting_changed = 1 +turf/proc/lighting_tag(const/level) + var/area/A = loc + return A.tagbase + "sd_L[level]" + +turf/proc/build_lighting_area(const/tag, const/level, const/color_light) + var/area/Area = loc + var/area/A = new Area.type() // create area if it wasn't found + // replicate vars + for(var/V in Area.vars) + switch(V) + if ("contents","lighting_overlay", "color_overlay", "overlays") + continue + else + if(issaved(Area.vars[V])) A.vars[V] = Area.vars[V] + + A.tag = tag + A.lighting_subarea = 1 + A.lighting_space = 0 // in case it was copied from a space subarea + + if (l_color != A.l_color) + A.l_color = l_color + //color_light = min(max(round(color_lighting_lumcount, 1), 0), lighting_controller.lighting_states) + //world << "[color_light] [color_lighting_lumcount]" + + A.SetLightLevel(level, color_light) + Area.related += A + return A + turf/proc/shift_to_subarea() lighting_changed = 0 var/area/Area = loc if(!istype(Area) || !Area.lighting_use_dynamic) return - // change the turf's area depending on its brightness - // restrict light to valid levels - var/light = min(max(round(lighting_lumcount,1),0),lighting_controller.lighting_states) + var/level = min(max(round(lighting_lumcount,1),0),lighting_controller.lighting_states) + var/new_tag = lighting_tag(level) - var/find = findtextEx(Area.tag, "sd_L") - var/new_tag = copytext(Area.tag, 1, find) - new_tag += "sd_L[light]" + // pomf - If we have a lighting color that is not null, apply the new tag to seperate the areas. + if (l_color) + new_tag += "[l_color][color_lighting_lumcount]" // pomf - We append the color lighting lumcount so we can have colored lights. if(Area.tag!=new_tag) //skip if already in this area - var/area/A = locate(new_tag) // find an appropriate area + var/color_light = min(max(round(color_lighting_lumcount,1),0),lighting_controller.lighting_states) - if(!A) - - A = new Area.type() // create area if it wasn't found - // replicate vars - for(var/V in Area.vars) - switch(V) - if("contents","lighting_overlay","overlays") continue - else - if(issaved(Area.vars[V])) A.vars[V] = Area.vars[V] - - A.tag = new_tag - A.lighting_subarea = 1 - A.SetLightLevel(light) - - Area.related += A + if (!A) + A = build_lighting_area(new_tag, level, color_light) + else if (l_color != A.l_color) + A.l_color = l_color + //color_light = min(max(round(color_lighting_lumcount, 1), 0), lighting_controller.lighting_states) + A.SetLightLevel(level, color_light) A.contents += src // move the turf into the area +// Dedicated lighting sublevel for space turfs +// helps us depower things in space, remove space fire alarms, +// and evens out space lighting +turf/space/lighting_tag(var/level) + var/area/A = loc + return A.tagbase + "sd_L_space" +turf/space/build_lighting_area(var/tag,var/level) + var/area/A = ..(tag,4) + A.lighting_space = 1 + A.SetLightLevel(4) + A.icon_state = null + return A + + area var/lighting_use_dynamic = 1 //Turn this flag off to prevent sd_DynamicAreaLighting from affecting this area var/image/lighting_overlay //tracks the darkness image of the area for easy removal var/lighting_subarea = 0 //tracks whether we're a lighting sub-area + var/lighting_space = 0 // true for space-only lighting subareas + var/tagbase + var/image/color_overlay //Tracks the color image. - proc/SetLightLevel(light) + proc/SetLightLevel(light, color_light = 0) if(!src) return if(light <= 0) light = 0 @@ -291,17 +369,113 @@ area else lighting_overlay = image(LIGHTING_ICON,,num2text(light),LIGHTING_LAYER) - overlays += lighting_overlay + if (color_overlay) + overlays.Remove(color_overlay) + color_overlay.icon_state = "white" + else + if (l_color) + color_overlay = image('icons/effects/effects.dmi', ,"white", 10.1) + + if (istype(color_overlay)) + color_overlay.color = l_color + + /* + if (light < 6) + switch (level) + if (6) + color_overlay.alpha = 140 + if (5) + color_overlay.alpha = 120 + if (4) + color_overlay.alpha = 100 + if (3) + color_overlay.alpha = 80 + if (2) + color_overlay.alpha = 60 + if (1) + color_overlay.alpha = 40 + if (-INFINITY to 0) + //world << "Zero or below, [color_light]." + color_overlay.alpha = 0 + else + //world << "Setting the alpha to max... color_light [color_light]." + color_overlay.alpha = 140 + + color_overlay.blend_mode = BLEND_MULTIPLY + */ + + if (1) + switch (color_light) + if (6) + color_overlay.alpha = 140 + if (5) + color_overlay.alpha = 120 + if (4) + color_overlay.alpha = 100 + if (3) + color_overlay.alpha = 80 + if (2) + color_overlay.alpha = 60 + if (1) + color_overlay.alpha = 20 + if (-INFINITY to 0) + //world << "Zero or below, [color_light]." + color_overlay.alpha = 0 + else + //world << "Setting the alpha to max... color_light [color_light]." + color_overlay.alpha = 180 + color_overlay.blend_mode = BLEND_MULTIPLY + if (color_overlay.color) + overlays.Add(color_overlay) + + if (isnull(color_overlay)) + overlays.Add(lighting_overlay) + else if (light < 6) + overlays.Add(lighting_overlay) + + proc/SetDynamicLighting() + + src.lighting_use_dynamic = 1 + for(var/turf/T in src.contents) + T.update_lumcount(0) proc/InitializeLighting() //TODO: could probably improve this bit ~Carn - if(!tag) tag = "[type]" + tagbase = "[type]" + if(!tag) tag = tagbase if(!lighting_use_dynamic) if(!lighting_subarea) // see if this is a lighting subarea already //show the dark overlay so areas, not yet in a lighting subarea, won't be bright as day and look silly. SetLightLevel(4) +//#undef LIGHTING_LAYER +#undef LIGHTING_CIRCULAR +//#undef LIGHTING_ICON -#undef LIGHTING_MAX_LUMINOSITY -#undef LIGHTING_MAX_LUMINOSITY_MOB -#undef LIGHTING_LAYER -//#undef LIGHTING_ICON \ No newline at end of file +#define LIGHTING_MAX_LUMINOSITY_STATIC 8 //Maximum luminosity to reduce lag. +#define LIGHTING_MAX_LUMINOSITY_MOBILE 5 //Moving objects have a lower max luminosity since these update more often. (lag reduction) +#define LIGHTING_MAX_LUMINOSITY_TURF 1 //turfs have a severely shortened range to protect from inevitable floor-lighttile spam. + +//set the changed status of all lights which could have possibly lit this atom. +//We don't need to worry about lights which lit us but moved away, since they will have change status set already +//This proc can cause lots of lights to be updated. :( +atom/proc/UpdateAffectingLights() + for(var/atom/A in oview(LIGHTING_MAX_LUMINOSITY_STATIC-1,src)) + if(A.light) + A.light.changed = 1 //force it to update at next process() + +//caps luminosity effects max-range based on what type the light's owner is. +atom/proc/get_light_range() + return min(luminosity, LIGHTING_MAX_LUMINOSITY_STATIC) + +atom/movable/get_light_range() + return min(luminosity, LIGHTING_MAX_LUMINOSITY_MOBILE) + +obj/machinery/light/get_light_range() + return min(luminosity, LIGHTING_MAX_LUMINOSITY_STATIC) + +turf/get_light_range() + return min(luminosity, LIGHTING_MAX_LUMINOSITY_TURF) + +#undef LIGHTING_MAX_LUMINOSITY_STATIC +#undef LIGHTING_MAX_LUMINOSITY_MOBILE +#undef LIGHTING_MAX_LUMINOSITY_TURF \ No newline at end of file diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index fa6e8649ec..1b986b6985 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ