Advertisement
Guest User

Untitled

a guest
Jan 21st, 2013
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.41 KB | None | 0 0
  1. /*
  2. LightLib.dm
  3. Lighting Engine for BYOND
  4. Original Author: forum_account
  5. Modification Author: FIREking
  6. */
  7.  
  8. #define LIGHTING_ENABLE 1
  9.  
  10. #define LIGHTING_ICON 'gfx/lighting/lighting.dmi'
  11. #define LIGHTING_LAYER 30
  12. #define LIGHTING_RANGE 13
  13. #define LIGHTING_SPEED 10
  14.  
  15. world
  16. New()
  17. ..()
  18. if(LIGHTING_ENABLE)
  19. spawn lighting.init()
  20.  
  21. var/list/clients = list() //keep track of clients
  22.  
  23. client/New()
  24. ..()
  25. clients += src
  26.  
  27. client/Del()
  28. clients -= src
  29. ..()
  30.  
  31. atom/var
  32. tmp/light/light = null
  33. opaque = 0
  34.  
  35. atom
  36. Del()
  37. if(light)
  38. light.Die()
  39. ..()
  40.  
  41. turf/var/tmp
  42. shading/shading = null
  43. can_shade = 1 //completely dark
  44. ignore_shade = 0 //completely lit
  45.  
  46. var/Lighting/lighting = new()
  47. var/shading/null_shading = new(null, null, 0)
  48.  
  49. Lighting
  50. var/tmp
  51. states = 0
  52. icon = LIGHTING_ICON
  53. light_range = LIGHTING_RANGE
  54. list/changed = list()
  55. list/initialized = list()
  56. list/lights = list()
  57. ambient = 0
  58. __ambient = 0
  59. _light_delay = 0
  60.  
  61. list/to_process = list()
  62. list/shades_amb = list()
  63.  
  64. New()
  65. CalculateDelay()
  66. spawn(1) _loop()
  67.  
  68. proc
  69. CalculateDelay() //call this when/if you change world.fps or world.tick_lag
  70. _light_delay = (world.icon_size * world.tick_lag) / LIGHTING_SPEED
  71.  
  72. _loop()
  73. while(src)
  74. sleep(_light_delay)
  75.  
  76. if(clients.len <= 0) continue
  77.  
  78. if(!states)
  79. if(!icon)
  80. del(src)
  81. CRASH("The global var lighting.icon must be set.")
  82.  
  83. var/list/l = icon_states(icon)
  84. states = l.len ** 0.25
  85.  
  86. if(__ambient != ambient)
  87. __ambient = ambient
  88.  
  89. spawn(world.tick_lag)
  90. for(var/s in shades_amb)
  91. s:lum(0)
  92.  
  93. shades_amb.Cut()
  94.  
  95. for(var/c in clients)
  96. for(var/light/l in range(light_range, c))
  97. l.out_of_sight = 0
  98. if(l.should_wake)
  99. if(!to_process.Find(l)) to_process += l
  100.  
  101. //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
  102. //this scans all lights, scans for forced changes and checks if it is out of sight and not in the process list
  103. //if that's the case, we call the light's left_view() proc which negates its effect and marks it out of sight
  104. //out of sight will prevent it from being negated again until visible again
  105. for(var/l in lights)
  106. if(l:should_wake && !to_process.Find(l) && !l:out_of_sight)
  107. l:left_view()
  108. l:out_of_sight = 1
  109.  
  110. for(var/l in to_process)
  111. if(l) l:loop()
  112. if(l) l:should_wake = 0
  113.  
  114. to_process.Cut()
  115.  
  116. for(var/s in changed)
  117. s:icon_state = "[s:c1:lum][s:c2:lum][s:c3:lum][s:lum]"
  118. s:changed = 0
  119.  
  120. changed.Cut()
  121.  
  122. init()
  123.  
  124. var/list/z_levels = list()
  125.  
  126. for(var/a in args)
  127. if(isnum(a))
  128. z_levels += a
  129. else if(isicon(a))
  130. world << "The lighting's icon should now be set by setting the lighting.icon var directly, not by passing an icon to init()."
  131.  
  132. if(z_levels.len == 0)
  133. for(var/i = 1 to world.maxz)
  134. z_levels += i
  135.  
  136. var/list/light_objects = list()
  137.  
  138. for(var/z in z_levels)
  139.  
  140. if(isnull(icon))
  141. CRASH("You have to first tell dynamic lighting which icon file to use by setting the lighting.icon var.")
  142.  
  143. if(z in initialized)
  144. continue
  145.  
  146. initialized += z
  147.  
  148. for(var/x = 1 to world.maxx)
  149. for(var/y = 1 to world.maxy)
  150.  
  151. var/turf/t = locate(x, y, z)
  152.  
  153. if(t.shading) continue
  154.  
  155. if(!t)
  156. break
  157.  
  158. if(!t.ignore_shade)
  159. t.shading = new(t, icon, 0)
  160. light_objects += t.shading
  161.  
  162. for(var/shading/s in light_objects)
  163. s.init()
  164.  
  165. if(s.loc && !s.changed)
  166. s.changed = 1
  167. lighting.changed += s
  168.  
  169. shading
  170. parent_type = /obj
  171.  
  172. layer = LIGHTING_LAYER
  173.  
  174. mouse_opacity = 0
  175.  
  176. var/tmp
  177. lum = 0
  178. __lum = 0
  179.  
  180. shading/c1 = null
  181. shading/c2 = null
  182. shading/c3 = null
  183.  
  184. shading/u1 = null
  185. shading/u2 = null
  186. shading/u3 = null
  187.  
  188. changed = 0
  189. ambient = 0
  190. dead = 0
  191.  
  192. New(turf/t, i, l)
  193. ..(t)
  194. if(!icon) icon = i
  195. lum = l
  196.  
  197. proc/Die()
  198. dead = 1
  199. loc = null
  200. c1 = null
  201. c2 = null
  202. c3 = null
  203. u1 = null
  204. u2 = null
  205. u3 = null
  206.  
  207. Del()
  208. if(!dead)
  209. CRASH("BAD: shading.Del() not called by garbage collector!")
  210. ..()
  211.  
  212. proc
  213. init()
  214. pixel_x = -world.icon_size / 2
  215. pixel_y = pixel_x
  216.  
  217. c1 = locate(/shading) in get_step(src, SOUTH)
  218. c2 = locate(/shading) in get_step(src, SOUTHWEST)
  219. c3 = locate(/shading) in get_step(src, WEST)
  220.  
  221. u1 = locate(/shading) in get_step(src, EAST)
  222. u2 = locate(/shading) in get_step(src, NORTHEAST)
  223. u3 = locate(/shading) in get_step(src, NORTH)
  224.  
  225. if(!c1) c1 = null_shading
  226. if(!c2) c2 = null_shading
  227. if(!c3) c3 = null_shading
  228.  
  229. if(!u1) u1 = null_shading
  230. if(!u2) u2 = null_shading
  231. if(!u3) u3 = null_shading
  232.  
  233. lum(l)
  234. if(!loc:can_shade) return
  235.  
  236. __lum += l
  237.  
  238. ambient = lighting.ambient
  239.  
  240. var/new_lum = round(__lum * lighting.states + ambient, 1)
  241.  
  242. if(new_lum < 0)
  243. new_lum = 0
  244. else if(new_lum >= lighting.states)
  245. new_lum = lighting.states - 1
  246.  
  247. if(new_lum == lum) return
  248.  
  249. lum = new_lum
  250.  
  251. if(loc && !changed)
  252. changed = 1
  253. lighting.changed += src
  254.  
  255. if(u1.loc && !u1.changed)
  256. u1.changed = 1
  257. lighting.changed += u1
  258.  
  259. if(u2.loc && !u2.changed)
  260. u2.changed = 1
  261. lighting.changed += u2
  262.  
  263. if(u3.loc && !u3.changed)
  264. u3.changed = 1
  265. lighting.changed += u3
  266.  
  267. changed()
  268. if(changed) return
  269.  
  270. if(loc)
  271. changed = 1
  272. lighting.changed += src
  273.  
  274. if(u1.loc && !u1.changed)
  275. u1.changed = 1
  276. lighting.changed += u1
  277.  
  278. if(u2.loc && !u2.changed)
  279. u2.changed = 1
  280. lighting.changed += u2
  281.  
  282. if(u3.loc && !u3.changed)
  283. u3.changed = 1
  284. lighting.changed += u3
  285.  
  286. light
  287. parent_type = /obj
  288.  
  289. mouse_opacity = 0
  290.  
  291. var/tmp
  292. atom/owner
  293.  
  294. radius = 2
  295. intensity = 1
  296. ambient = 0
  297.  
  298. radius_squared = 4
  299.  
  300. __x = 0
  301. __y = 0
  302.  
  303. on = 1
  304.  
  305. changed = 1
  306.  
  307. mobile = 0
  308.  
  309. list/effect
  310.  
  311. should_wake = 1
  312.  
  313. dead = 0
  314.  
  315. update_time = 0
  316. update_delay = 0
  317.  
  318. out_of_sight = 1
  319.  
  320. New(atom/a, radius = 3, intensity = 1)
  321. if(update_delay <= 0) update_delay = world.tick_lag
  322. if(!a || !istype(a))
  323. CRASH("The first argument to the light object's constructor must be the atom that is the light source. Expected atom, received '[a]' instead.")
  324.  
  325. owner = a
  326.  
  327. if(istype(owner, /atom/movable))
  328. loc = owner.loc
  329. mobile = 1
  330. else
  331. loc = owner
  332. mobile = 0
  333.  
  334. src.radius = radius
  335. src.radius_squared = radius * radius
  336. src.intensity = intensity
  337.  
  338. __x = owner.x
  339. __y = owner.y
  340.  
  341. lighting.lights += src
  342.  
  343. Del()
  344. if(!dead)
  345. world << "BAD: light.Del() not called by garbage collector!"
  346. world.log << "BAD: light.Del() not called by garbage collector!"
  347. CRASH("BAD: light.Del() not called by garbage collector!")
  348. //off()
  349. //apply()
  350. //lighting.lights -= src
  351. //world << "garbage collector deleted light"
  352. ..()
  353.  
  354. proc/Die()
  355. dead = 1
  356. //in case the light has a light??
  357. if(src.light)
  358. src.light.Die()
  359. src.light = null
  360.  
  361. //make the area dark
  362. should_wake = 0
  363. if(on)
  364. off()
  365. apply()
  366.  
  367. //remove from the light list to clear references
  368. lighting.lights -= src
  369.  
  370. src.owner = null
  371. src.loc = null
  372.  
  373. proc
  374. loop()
  375. if(!owner)
  376. del(src)
  377.  
  378. if(mobile)
  379. var/opx = owner.x
  380. var/opy = owner.y
  381.  
  382. if(opx != __x || opy != __y)
  383. __x = opx
  384. __y = opy
  385. changed = 1
  386.  
  387. if(changed)
  388. apply()
  389. else
  390. should_wake = 0
  391.  
  392. apply()
  393.  
  394. changed = 0
  395.  
  396. if(effect)
  397.  
  398. for(var/s in effect)
  399. s:lum(-effect[s])
  400.  
  401. effect.Cut()
  402.  
  403. if(on && loc)
  404.  
  405. effect = effect()
  406.  
  407. for(var/s in effect)
  408. s:lum(effect[s])
  409.  
  410. on()
  411. if(on) return
  412.  
  413. on = 1
  414. changed = 1
  415.  
  416. off()
  417. if(!on) return
  418.  
  419. on = 0
  420. changed = 1
  421.  
  422. toggle()
  423. if(on)
  424. off()
  425. else
  426. on()
  427.  
  428. radius(r)
  429. if(radius == r) return
  430.  
  431. radius = r
  432. radius_squared = r * r
  433. changed = 1
  434.  
  435. intensity(i)
  436. if(intensity == i) return
  437.  
  438. intensity = i
  439. changed = 1
  440.  
  441. ambient(a)
  442. if(ambient == a) return
  443.  
  444. ambient = a
  445. changed = 1
  446.  
  447. center()
  448. if(istype(owner, /atom/movable))
  449.  
  450. var/atom/movable/m = owner
  451.  
  452. . = m.loc
  453. var/d = bounds_dist(m, .)
  454.  
  455. for(var/turf/t in m.locs)
  456. var/dt = bounds_dist(m, t)
  457. if(dt < d)
  458. d = dt
  459. . = t
  460. else
  461. var/turf/t = owner
  462. while(!istype(t))
  463. t = t.loc
  464.  
  465. return t
  466.  
  467. left_view()
  468. if(effect)
  469. for(var/s in effect)
  470. s:lum(-effect[s])
  471.  
  472. effect.Cut()
  473.  
  474. effect()
  475. //this is to allow for throttling of light source updates
  476. //for example, if you awnt to add some lights to an effect but its not entirely important
  477. //that the lights are updated in real time or even accurately (visual effect only, anyways)
  478. //so by setting update_delay to a tick value, you can effectively reduce expensive processing
  479. //on light sources that don't matter.
  480. if(world.time < update_time && world.time > 0) return
  481. update_time = world.time + update_delay
  482.  
  483. var/list/L = list()
  484.  
  485. for(var/shading/s in range(radius, src))
  486.  
  487. if(!isnull(L[s])) continue
  488.  
  489. if(s.x == x && s.y == y)
  490. var/lum = lum(s)
  491. if(lum > 0)
  492. L[s] = lum
  493.  
  494. continue
  495.  
  496. var/dx = (s.x - x)
  497. var/dy = (s.y - y)
  498. var/d = sqrt(dx * dx + dy * dy)
  499.  
  500. if(d > 0)
  501. dx /= d
  502. dy /= d
  503.  
  504. var/tx = x + dx + 0.5
  505. var/ty = y + dy + 0.5
  506.  
  507. for(var/i = 1 to radius)
  508.  
  509. var/turf/t = locate(round(tx), round(ty), z)
  510.  
  511. if(!t) break
  512.  
  513. if(!t.shading) break
  514.  
  515. if(!L[t.shading])
  516. var/lum = lum(t.shading)
  517. if(lum > 0)
  518. L[t.shading] = lum
  519.  
  520. if(t.opaque) break
  521.  
  522. if(t.shading == s) break
  523.  
  524. tx += dx
  525. ty += dy
  526.  
  527. return L
  528.  
  529. lum(atom/a)
  530. if(!radius)
  531. return 0
  532.  
  533. var/d = (__x - a.x) * (__x - a.x) + (__y - a.y) * (__y - a.y)
  534.  
  535. if(d > radius_squared) return 0
  536.  
  537. d = sqrt(d)
  538.  
  539. return cos(90 * d / radius) * intensity + ambient
  540.  
  541. light
  542. day_night
  543. apply()
  544. //we only give this light to players so we don't check if there's a client
  545. //if we decide to give this light to something else in the future
  546. //we will need to make sure we're only processing the tiles that any player can see.
  547. for(var/shading/s in range("17x13", owner))
  548. if(s.ambient != ambient)
  549. if(!lighting.shades_amb.Find(s))
  550. lighting.shades_amb += s
  551. return ..()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement