Advertisement
Guest User

Untitled

a guest
Dec 31st, 2012
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.99 KB | None | 0 0
  1. /*
  2.  
  3. Forum_Account's Dynamic Lighting Library optimized by FIREking
  4. 12/31/2012
  5.  
  6. All original code, concept, and design made by Forum_Account
  7. All optimizations and modifications made by FIREking
  8.  
  9. This is released without Forum_Account's direct permission
  10. If you do not agree with that, find him and complain
  11.  
  12. Things Assumed:
  13. You don't use pixel-based movement
  14. You use tile-based movement
  15. You have a movement system with speed
  16. There is a maximum speed that anything can move
  17. You don't need / have opaque objects that move
  18. You don't use light values for game rules, only for visuals
  19.  
  20. If you don't agree to any of the above, this won't work well for you
  21. These things are assumed in order to optimize the library
  22.  
  23. You realize:
  24. This is a server sided light engine
  25. Because of that, there are serious limitations
  26. I didn't invent this library, it isn't mine
  27. If you want to see the original code,
  28. download Forum_Account's Dynamic Lighting Library
  29.  
  30. Stuff:
  31. Change LIGHTING_ENABLE to 0 if you want to disable lights for a compile
  32. Set LIGHTING_ICON to your light icon, see Forum_Account's original library to make your own.
  33. Set LIGHTING_RANGE to how many tiles away from a client you want lights to be activated
  34. Set LIGHTING_SPEED to the fastest speed an object can move
  35. Library assumes speed algorithm is -> (world.icon_size * world.tick_lag) / LIGHTING_SPEED
  36. If you have another system for speed, just change CalculateDelay() to calculate light_delay variable how you want
  37. This controls how often the lighting engine loops
  38.  
  39. Weird:
  40. It's possible that a light can become stranded if you switch a client's mob
  41. ie:
  42. mob/verb/stranded()
  43. src.client.mob = new/mob/new_mob(src.loc)
  44. //the original light is now detached unless you remove it at Logout()
  45. //over time this could leave many many ghost lights, which is bad!
  46.  
  47. It's up to you to make sure you delete a light when you switch a client's mob
  48. ie:
  49. mob/Login()
  50. ..()
  51. src.light = new(src, 3)
  52. mob/Logout()
  53. del(src.light)
  54. if(key) del(src)
  55.  
  56. Bugs:
  57. Top edge and right edge of map will have a fully lit strip size of 1/2 world.icon_size
  58. This is a bug from the original library that I've never been able to fix.
  59. If a client's mob changes, the original mob's light becomes stranded, so delete it
  60.  
  61. Things left to improve:
  62. light.effect() could be improved using Recursive Shadow Casting
  63. improve it even further so it can work with pixel-based movement
  64. It's also been mentioned that the loop structure could be removed altogether
  65. and lights could only be updated only when seen / changed.
  66.  
  67. */
  68.  
  69. #define LIGHTING_ENABLE 1
  70.  
  71. #define LIGHTING_ICON 'gfx/lighting/lighting.dmi'
  72. #define LIGHTING_LAYER 100
  73. #define LIGHTING_RANGE 11
  74. #define LIGHTING_SPEED 11
  75.  
  76. world
  77. New()
  78. ..()
  79. if(LIGHTING_ENABLE)
  80. spawn lighting.init()
  81.  
  82. var/list/clients = list() //keep track of clients
  83.  
  84. client/New()
  85. ..()
  86. clients += src
  87.  
  88. client/Del()
  89. clients -= src
  90. ..()
  91.  
  92. atom
  93. var
  94. light/light = null
  95. opaque = 0
  96.  
  97. Del()
  98. if(light)
  99. del(light)
  100. ..()
  101.  
  102. turf
  103. var
  104. shading/shading = null
  105. canshade = 1
  106.  
  107. var/Lighting/lighting = new()
  108. var/shading/null_shading = new(null, null, 0)
  109.  
  110. Lighting
  111. var
  112. states = 0
  113. icon = LIGHTING_ICON
  114. light_range = LIGHTING_RANGE
  115. list/changed = list()
  116. list/initialized = list()
  117. list/lights = list()
  118. ambient = 0
  119. __ambient = 0
  120. _light_delay = 0
  121.  
  122. New()
  123. CalculateDelay()
  124. spawn(1) _loop()
  125.  
  126. proc
  127. CalculateDelay() //call this when/if you change world.fps or world.tick_lag
  128. _light_delay = (world.icon_size * world.tick_lag) / LIGHTING_SPEED
  129.  
  130. _loop()
  131. while(src)
  132. sleep(_light_delay)
  133.  
  134. if(clients.len <= 0) continue
  135.  
  136. if(!states)
  137. if(!icon)
  138. del(src)
  139. CRASH("The global var lighting.icon must be set.")
  140.  
  141. var/list/l = icon_states(icon)
  142. states = l.len ** 0.25
  143.  
  144. if(__ambient != ambient)
  145. for(var/l in lights)
  146. l:ambient(ambient)
  147.  
  148. __ambient = ambient
  149.  
  150. for(var/c in clients)
  151. for(var/light/l in range(light_range, c))
  152. if(l.should_wake)
  153. l:loop()
  154. l:should_wake = 0
  155.  
  156. for(var/s in changed)
  157. s:icon_state = "[s:c1:lum][s:c2:lum][s:c3:lum][s:lum]"
  158. s:changed = 0
  159.  
  160. changed.Cut()
  161.  
  162. init()
  163.  
  164. var/list/z_levels = list()
  165.  
  166. for(var/a in args)
  167. if(isnum(a))
  168. z_levels += a
  169. else if(isicon(a))
  170. world << "The lighting's icon should now be set by setting the lighting.icon var directly, not by passing an icon to init()."
  171.  
  172. if(z_levels.len == 0)
  173. for(var/i = 1 to world.maxz)
  174. z_levels += i
  175.  
  176. var/list/light_objects = list()
  177.  
  178. for(var/z in z_levels)
  179.  
  180. if(isnull(icon))
  181. CRASH("You have to first tell dynamic lighting which icon file to use by setting the lighting.icon var.")
  182.  
  183. if(z in initialized)
  184. continue
  185.  
  186. initialized += z
  187.  
  188. for(var/x = 1 to world.maxx)
  189. for(var/y = 1 to world.maxy)
  190.  
  191. var/turf/t = locate(x, y, z)
  192.  
  193. if(!t)
  194. break
  195.  
  196. t.shading = new(t, icon, 0)
  197. light_objects += t.shading
  198.  
  199. for(var/shading/s in light_objects)
  200. s.init()
  201.  
  202. if(s.loc && !s.changed)
  203. s.changed = 1
  204. lighting.changed += s
  205.  
  206. shading
  207. parent_type = /obj
  208.  
  209. layer = LIGHTING_LAYER
  210.  
  211. mouse_opacity = 0
  212.  
  213. var
  214. lum = 0
  215. __lum = 0
  216.  
  217. shading/c1 = null
  218. shading/c2 = null
  219. shading/c3 = null
  220.  
  221. shading/u1 = null
  222. shading/u2 = null
  223. shading/u3 = null
  224.  
  225. changed = 0
  226.  
  227. ambient = 0
  228.  
  229. New(turf/t, i, l)
  230. ..(t)
  231. icon = i
  232. lum = l
  233.  
  234. proc
  235. init()
  236. pixel_x = -world.icon_size / 2
  237. pixel_y = pixel_x
  238.  
  239. c1 = locate(/shading) in get_step(src, SOUTH)
  240. c2 = locate(/shading) in get_step(src, SOUTHWEST)
  241. c3 = locate(/shading) in get_step(src, WEST)
  242.  
  243. u1 = locate(/shading) in get_step(src, EAST)
  244. u2 = locate(/shading) in get_step(src, NORTHEAST)
  245. u3 = locate(/shading) in get_step(src, NORTH)
  246.  
  247. if(!c1) c1 = null_shading
  248. if(!c2) c2 = null_shading
  249. if(!c3) c3 = null_shading
  250.  
  251. if(!u1) u1 = null_shading
  252. if(!u2) u2 = null_shading
  253. if(!u3) u3 = null_shading
  254.  
  255. lum(l)
  256. if(!loc:canshade) return
  257. __lum += l
  258.  
  259. ambient = lighting.ambient
  260.  
  261. var/new_lum = round(__lum * lighting.states + ambient, 1)
  262.  
  263. if(new_lum < 0)
  264. new_lum = 0
  265. else if(new_lum >= lighting.states)
  266. new_lum = lighting.states - 1
  267.  
  268. if(new_lum == lum) return
  269.  
  270. lum = new_lum
  271.  
  272. if(loc && !changed)
  273. changed = 1
  274. lighting.changed += src
  275.  
  276. if(u1.loc && !u1.changed)
  277. u1.changed = 1
  278. lighting.changed += u1
  279.  
  280. if(u2.loc && !u2.changed)
  281. u2.changed = 1
  282. lighting.changed += u2
  283.  
  284. if(u3.loc && !u3.changed)
  285. u3.changed = 1
  286. lighting.changed += u3
  287.  
  288. changed()
  289. if(changed) return
  290.  
  291. if(loc)
  292. changed = 1
  293. lighting.changed += src
  294.  
  295. if(u1.loc && !u1.changed)
  296. u1.changed = 1
  297. lighting.changed += u1
  298.  
  299. if(u2.loc && !u2.changed)
  300. u2.changed = 1
  301. lighting.changed += u2
  302.  
  303. if(u3.loc && !u3.changed)
  304. u3.changed = 1
  305. lighting.changed += u3
  306.  
  307. light
  308. parent_type = /obj
  309.  
  310. var
  311. atom/owner
  312.  
  313. radius = 2
  314. intensity = 1
  315. ambient = 0
  316.  
  317. radius_squared = 4
  318.  
  319. __x = 0
  320. __y = 0
  321.  
  322. on = 1
  323.  
  324. changed = 1
  325.  
  326. mobile = 0
  327.  
  328. list/effect
  329.  
  330. should_wake = 1
  331.  
  332. New(atom/a, radius = 3, intensity = 1)
  333. if(!a || !istype(a))
  334. CRASH("The first argument to the light object's constructor must be the atom that is the light source. Expected atom, received '[a]' instead.")
  335.  
  336. owner = a
  337.  
  338. if(istype(owner, /atom/movable))
  339. loc = owner.loc
  340. mobile = 1
  341. else
  342. loc = owner
  343. mobile = 0
  344.  
  345. src.radius = radius
  346. src.radius_squared = radius * radius
  347. src.intensity = intensity
  348.  
  349. __x = owner.x
  350. __y = owner.y
  351.  
  352. lighting.lights += src
  353.  
  354. Del()
  355. off()
  356. apply()
  357. lighting.lights -= src
  358. ..()
  359.  
  360. proc
  361. loop()
  362. if(!owner)
  363. del(src)
  364.  
  365. if(mobile)
  366. var/opx = owner.x
  367. var/opy = owner.y
  368.  
  369. if(opx != __x || opy != __y)
  370. __x = opx
  371. __y = opy
  372. changed = 1
  373.  
  374. if(changed)
  375. apply()
  376. else
  377. should_wake = 0
  378.  
  379. apply()
  380.  
  381. changed = 0
  382.  
  383. if(effect)
  384.  
  385. for(var/shading/s in effect)
  386. s.lum(-effect[s])
  387.  
  388. effect.Cut()
  389.  
  390. if(on && loc)
  391.  
  392. effect = effect()
  393.  
  394. for(var/shading/s in effect)
  395. s.lum(effect[s])
  396.  
  397. on()
  398. if(on) return
  399.  
  400. on = 1
  401. changed = 1
  402.  
  403. off()
  404. if(!on) return
  405.  
  406. on = 0
  407. changed = 1
  408.  
  409. toggle()
  410. if(on)
  411. off()
  412. else
  413. on()
  414.  
  415. radius(r)
  416. if(radius == r) return
  417.  
  418. radius = r
  419. radius_squared = r * r
  420. changed = 1
  421.  
  422. intensity(i)
  423. if(intensity == i) return
  424.  
  425. intensity = i
  426. changed = 1
  427.  
  428. ambient(a)
  429. if(ambient == a) return
  430.  
  431. ambient = a
  432. changed = 1
  433.  
  434. center()
  435. if(istype(owner, /atom/movable))
  436.  
  437. var/atom/movable/m = owner
  438.  
  439. . = m.loc
  440. var/d = bounds_dist(m, .)
  441.  
  442. for(var/turf/t in m.locs)
  443. var/dt = bounds_dist(m, t)
  444. if(dt < d)
  445. d = dt
  446. . = t
  447. else
  448. var/turf/t = owner
  449. while(!istype(t))
  450. t = t.loc
  451.  
  452. return t
  453.  
  454. effect()
  455.  
  456. var/list/L = list()
  457.  
  458. for(var/shading/s in range(radius, src))
  459.  
  460. if(!isnull(L[s])) continue
  461.  
  462. if(s.x == x && s.y == y)
  463. var/lum = lum(s)
  464. if(lum > 0)
  465. L[s] = lum
  466.  
  467. continue
  468.  
  469. var/dx = (s.x - x)
  470. var/dy = (s.y - y)
  471. var/d = sqrt(dx * dx + dy * dy)
  472.  
  473. if(d > 0)
  474. dx /= d
  475. dy /= d
  476.  
  477. var/tx = x + dx + 0.5
  478. var/ty = y + dy + 0.5
  479.  
  480. for(var/i = 1 to radius)
  481.  
  482. var/turf/t = locate(round(tx), round(ty), z)
  483.  
  484. if(!t) break
  485.  
  486. if(!L[t.shading])
  487. var/lum = lum(t.shading)
  488. if(lum > 0)
  489. L[t.shading] = lum
  490.  
  491. if(t.opaque) break
  492.  
  493. if(t.shading == s) break
  494.  
  495. tx += dx
  496. ty += dy
  497.  
  498. return L
  499.  
  500. lum(atom/a)
  501.  
  502. if(!radius)
  503. return 0
  504.  
  505. var/d = (__x - a.x) * (__x - a.x) + (__y - a.y) * (__y - a.y)
  506.  
  507. if(d > radius_squared) return 0
  508.  
  509. d = sqrt(d)
  510.  
  511. return cos(90 * d / radius) * intensity + ambient
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement