I was going to keep this a secret until I could show it in action, but I thought I'd give people an idea of what I'm making. Feel free to try this yourself, if you want to beat me to the punch. Just don't ask me for any actual code... I won't share that part.
Imagine a torch object with a luminosity of 5. In a dark area, it will cause all objects within 5 squares to be visible. Now imagine laying black dithered mobs over top of items in those squares. The further away the square, the denser the black dither. The end effect is that items within 5 squares of the torch will be visible, but increasingly blackened out as distance increases. When we reach total blackness, we also reach the luminosity range of the torch.
The dithered mobs I call light_cells. Here we assign an icon containing a number of dithered icon states, representing for example, 0%, 25%, 50%, 75%, 100% darkness. If we create a proc owned by that mob to calculate its own light intensity, all we need to do is get the intensity of the owning light source and calculate this mob's distance to it.
We can set an arbitrary range to represent the distance at which light fades to black (let's call it black_dist), set a scale from the light source's intensity (source_str) to zero, then calculate the intensity by using something like the below formula:
source_str - (get_dist(src, my_light_source)/black_dist)
Then, rounding to the nearest .25, we have the dither pattern needed.
Actually, I prefer this following proc to get_dist():
proc/get_real_dist(from_x, from_y, to_x, to_y) var x_delta = abs(from_x - to_x) y_delta = abs(from_y - to_y) return sqrt(x_delta**2 + y_delta**2)
This returns the real distance between two points on the map, using good old Pythagoras's theorum. This will make more of a visual difference as black_dist is increased, and as you increase the number of dither patterns between 0%-100%.
There are just a couple more problems to solve. First is the hitting of an edge of a map, and keeping the light_cell from attempting to draw outside of your world. It's a fairly simple matter to check for proximity, and keep this from happening.
The second is what happens when the sphere of light produced by two or more of these sources overlaps. This is a bit trickier to fix, but I do have a solution. It involves calculating the combined light total, picking the appropriate dither pattern, assinging that pattern to only one of the light_cells, and hiding all other light_cells on the same square of the map.
At the moment, I have the whole system on paper, but I've yet to program it, since whenever I open BYOND, I feel obligated to work on MLAAS. However, my next game will be using this system extensively, so expect to see a little test project soon.
I welcome any ideas or comments on these ideas. I would be willing to post the whole thing as a library when it's perfected, but will not do so until my next game is well underway. If I make the library, I want to have the first game out that actually uses it. :-)
/mob/skysaw
Thanks for writing up this post, however--now if people bug me about how my dithered lighting works, I have somewhere to point them to.