Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- LightLib.dm
- Lighting Engine for BYOND
- Original Author: forum_account
- Modification Author: FIREking
- */
- #define LIGHTING_ENABLE 1
- #define LIGHTING_ICON 'gfx/lighting/lighting.dmi'
- #define LIGHTING_LAYER 30
- #define LIGHTING_RANGE 13
- #define LIGHTING_SPEED 10
- world
- New()
- ..()
- if(LIGHTING_ENABLE)
- spawn lighting.init()
- var/list/clients = list() //keep track of clients
- client/New()
- ..()
- clients += src
- client/Del()
- clients -= src
- ..()
- atom/var
- tmp/light/light = null
- opaque = 0
- atom
- Del()
- if(light)
- light.Die()
- ..()
- turf/var/tmp
- shading/shading = null
- can_shade = 1 //completely dark
- ignore_shade = 0 //completely lit
- var/Lighting/lighting = new()
- var/shading/null_shading = new(null, null, 0)
- Lighting
- var/tmp
- states = 0
- icon = LIGHTING_ICON
- light_range = LIGHTING_RANGE
- list/changed = list()
- list/initialized = list()
- list/lights = list()
- ambient = 0
- __ambient = 0
- _light_delay = 0
- list/to_process = list()
- list/shades_amb = list()
- New()
- CalculateDelay()
- spawn(1) _loop()
- proc
- CalculateDelay() //call this when/if you change world.fps or world.tick_lag
- _light_delay = (world.icon_size * world.tick_lag) / LIGHTING_SPEED
- _loop()
- while(src)
- sleep(_light_delay)
- if(clients.len <= 0) continue
- if(!states)
- if(!icon)
- del(src)
- CRASH("The global var lighting.icon must be set.")
- var/list/l = icon_states(icon)
- states = l.len ** 0.25
- if(__ambient != ambient)
- __ambient = ambient
- spawn(world.tick_lag)
- for(var/s in shades_amb)
- s:lum(0)
- shades_amb.Cut()
- for(var/c in clients)
- for(var/light/l in range(light_range, c))
- l.out_of_sight = 0
- if(l.should_wake)
- if(!to_process.Find(l)) to_process += l
- //if a moving light moves out of sight before its allowed to update again, its effect will remain even though its loc is now different
- //this scans all lights, scans for forced changes and checks if it is out of sight and not in the process list
- //if that's the case, we call the light's left_view() proc which negates its effect and marks it out of sight
- //out of sight will prevent it from being negated again until visible again
- for(var/l in lights)
- if(l:should_wake && !to_process.Find(l) && !l:out_of_sight)
- l:left_view()
- l:out_of_sight = 1
- for(var/l in to_process)
- if(l) l:loop()
- if(l) l:should_wake = 0
- to_process.Cut()
- for(var/s in changed)
- s:icon_state = "[s:c1:lum][s:c2:lum][s:c3:lum][s:lum]"
- s:changed = 0
- changed.Cut()
- init()
- var/list/z_levels = list()
- for(var/a in args)
- if(isnum(a))
- z_levels += a
- else if(isicon(a))
- world << "The lighting's icon should now be set by setting the lighting.icon var directly, not by passing an icon to init()."
- if(z_levels.len == 0)
- for(var/i = 1 to world.maxz)
- z_levels += i
- var/list/light_objects = list()
- for(var/z in z_levels)
- if(isnull(icon))
- CRASH("You have to first tell dynamic lighting which icon file to use by setting the lighting.icon var.")
- if(z in initialized)
- continue
- initialized += z
- for(var/x = 1 to world.maxx)
- for(var/y = 1 to world.maxy)
- var/turf/t = locate(x, y, z)
- if(t.shading) continue
- if(!t)
- break
- if(!t.ignore_shade)
- t.shading = new(t, icon, 0)
- light_objects += t.shading
- for(var/shading/s in light_objects)
- s.init()
- if(s.loc && !s.changed)
- s.changed = 1
- lighting.changed += s
- shading
- parent_type = /obj
- layer = LIGHTING_LAYER
- mouse_opacity = 0
- var/tmp
- lum = 0
- __lum = 0
- shading/c1 = null
- shading/c2 = null
- shading/c3 = null
- shading/u1 = null
- shading/u2 = null
- shading/u3 = null
- changed = 0
- ambient = 0
- dead = 0
- New(turf/t, i, l)
- ..(t)
- if(!icon) icon = i
- lum = l
- proc/Die()
- dead = 1
- loc = null
- c1 = null
- c2 = null
- c3 = null
- u1 = null
- u2 = null
- u3 = null
- Del()
- if(!dead)
- CRASH("BAD: shading.Del() not called by garbage collector!")
- ..()
- proc
- init()
- pixel_x = -world.icon_size / 2
- pixel_y = pixel_x
- c1 = locate(/shading) in get_step(src, SOUTH)
- c2 = locate(/shading) in get_step(src, SOUTHWEST)
- c3 = locate(/shading) in get_step(src, WEST)
- u1 = locate(/shading) in get_step(src, EAST)
- u2 = locate(/shading) in get_step(src, NORTHEAST)
- u3 = locate(/shading) in get_step(src, NORTH)
- if(!c1) c1 = null_shading
- if(!c2) c2 = null_shading
- if(!c3) c3 = null_shading
- if(!u1) u1 = null_shading
- if(!u2) u2 = null_shading
- if(!u3) u3 = null_shading
- lum(l)
- if(!loc:can_shade) return
- __lum += l
- ambient = lighting.ambient
- var/new_lum = round(__lum * lighting.states + ambient, 1)
- if(new_lum < 0)
- new_lum = 0
- else if(new_lum >= lighting.states)
- new_lum = lighting.states - 1
- if(new_lum == lum) return
- lum = new_lum
- if(loc && !changed)
- changed = 1
- lighting.changed += src
- if(u1.loc && !u1.changed)
- u1.changed = 1
- lighting.changed += u1
- if(u2.loc && !u2.changed)
- u2.changed = 1
- lighting.changed += u2
- if(u3.loc && !u3.changed)
- u3.changed = 1
- lighting.changed += u3
- changed()
- if(changed) return
- if(loc)
- changed = 1
- lighting.changed += src
- if(u1.loc && !u1.changed)
- u1.changed = 1
- lighting.changed += u1
- if(u2.loc && !u2.changed)
- u2.changed = 1
- lighting.changed += u2
- if(u3.loc && !u3.changed)
- u3.changed = 1
- lighting.changed += u3
- light
- parent_type = /obj
- mouse_opacity = 0
- var/tmp
- atom/owner
- radius = 2
- intensity = 1
- ambient = 0
- radius_squared = 4
- __x = 0
- __y = 0
- on = 1
- changed = 1
- mobile = 0
- list/effect
- should_wake = 1
- dead = 0
- update_time = 0
- update_delay = 0
- out_of_sight = 1
- New(atom/a, radius = 3, intensity = 1)
- if(update_delay <= 0) update_delay = world.tick_lag
- if(!a || !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))
- loc = owner.loc
- mobile = 1
- else
- loc = owner
- mobile = 0
- src.radius = radius
- src.radius_squared = radius * radius
- src.intensity = intensity
- __x = owner.x
- __y = owner.y
- lighting.lights += src
- Del()
- if(!dead)
- world << "BAD: light.Del() not called by garbage collector!"
- world.log << "BAD: light.Del() not called by garbage collector!"
- CRASH("BAD: light.Del() not called by garbage collector!")
- //off()
- //apply()
- //lighting.lights -= src
- //world << "garbage collector deleted light"
- ..()
- proc/Die()
- dead = 1
- //in case the light has a light??
- if(src.light)
- src.light.Die()
- src.light = null
- //make the area dark
- should_wake = 0
- if(on)
- off()
- apply()
- //remove from the light list to clear references
- lighting.lights -= src
- src.owner = null
- src.loc = null
- proc
- loop()
- if(!owner)
- del(src)
- if(mobile)
- var/opx = owner.x
- var/opy = owner.y
- if(opx != __x || opy != __y)
- __x = opx
- __y = opy
- changed = 1
- if(changed)
- apply()
- else
- should_wake = 0
- apply()
- changed = 0
- if(effect)
- for(var/s in effect)
- s:lum(-effect[s])
- effect.Cut()
- if(on && loc)
- effect = effect()
- for(var/s in effect)
- s:lum(effect[s])
- on()
- if(on) return
- on = 1
- changed = 1
- off()
- if(!on) return
- on = 0
- changed = 1
- toggle()
- if(on)
- off()
- else
- on()
- radius(r)
- if(radius == r) return
- radius = r
- radius_squared = r * r
- changed = 1
- intensity(i)
- if(intensity == i) return
- intensity = i
- changed = 1
- ambient(a)
- if(ambient == a) return
- ambient = a
- changed = 1
- center()
- if(istype(owner, /atom/movable))
- var/atom/movable/m = owner
- . = m.loc
- var/d = bounds_dist(m, .)
- for(var/turf/t in m.locs)
- var/dt = bounds_dist(m, t)
- if(dt < d)
- d = dt
- . = t
- else
- var/turf/t = owner
- while(!istype(t))
- t = t.loc
- return t
- left_view()
- if(effect)
- for(var/s in effect)
- s:lum(-effect[s])
- effect.Cut()
- effect()
- //this is to allow for throttling of light source updates
- //for example, if you awnt to add some lights to an effect but its not entirely important
- //that the lights are updated in real time or even accurately (visual effect only, anyways)
- //so by setting update_delay to a tick value, you can effectively reduce expensive processing
- //on light sources that don't matter.
- if(world.time < update_time && world.time > 0) return
- update_time = world.time + update_delay
- var/list/L = list()
- for(var/shading/s in range(radius, src))
- if(!isnull(L[s])) continue
- if(s.x == x && s.y == y)
- var/lum = lum(s)
- if(lum > 0)
- L[s] = lum
- continue
- var/dx = (s.x - x)
- var/dy = (s.y - y)
- var/d = sqrt(dx * dx + dy * dy)
- if(d > 0)
- dx /= d
- dy /= d
- var/tx = x + dx + 0.5
- var/ty = y + dy + 0.5
- for(var/i = 1 to radius)
- var/turf/t = locate(round(tx), round(ty), z)
- if(!t) break
- if(!t.shading) break
- if(!L[t.shading])
- var/lum = lum(t.shading)
- if(lum > 0)
- L[t.shading] = lum
- if(t.opaque) break
- if(t.shading == s) break
- tx += dx
- ty += dy
- return L
- lum(atom/a)
- if(!radius)
- return 0
- var/d = (__x - a.x) * (__x - a.x) + (__y - a.y) * (__y - a.y)
- if(d > radius_squared) return 0
- d = sqrt(d)
- return cos(90 * d / radius) * intensity + ambient
- light
- day_night
- apply()
- //we only give this light to players so we don't check if there's a client
- //if we decide to give this light to something else in the future
- //we will need to make sure we're only processing the tiles that any player can see.
- for(var/shading/s in range("17x13", owner))
- if(s.ambient != ambient)
- if(!lighting.shades_amb.Find(s))
- lighting.shades_amb += s
- return ..()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement