ID:195029
 
//Title: Line of Sight
//Credit to: DarkCampainger
//Contributed by: DarkCampainger

/*

This process returns true if there is a clear line of sight from one
pixel-specific location to another. It draws a line from the first
location to the second, and checks it for opaque objects. Although
the line is drawn based on pixels, the opaque object check is based
on square tiles only.

To use this process, simply call it and pass the two locations that create
the line of sight. The pixel-based offsets to the X and Y coordinates are
optional, and default to the center of a tile (which is 16.5, not 16!)

If you are passing pixel offsets, be sure to base them off the center of tile:
WRONG:
inLineOfSight(...,pixel_x,pixel_y,T.pixel_x,T.pixel_y)
RIGHT:
inLineOfSight(...,16.5+pixel_x,16.5+pixel_y,16.5+T.pixel_x,16.5+T.pixel_y)

Note: Keep PX1,PY1,PX2, and PY2 in the 1-32 range! The process will not convert
them for you, and you will get unexpected results!

*/


#define SIGN(X) ((X<0)?-1:1)

proc
inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
var/turf/T
if(X1==X2)
if(Y1==Y2) return 1 //Light cannot be blocked on same tile
else
var/s = SIGN(Y2-Y1)
Y1+=s
while(Y1!=Y2)
T=locate(X1,Y1,Z)
if(T.opacity) return 0
Y1+=s
else
var
m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
signX = SIGN(X2-X1)
signY = SIGN(Y2-Y1)
if(X1<X2) b+=m
while(X1!=X2 || Y1!=Y2)
if(round(m*X1+b-Y1)) Y1+=signY //Line exits tile vertically
else X1+=signX //Line exits tile horizontally
T=locate(X1,Y1,Z)
if(T.opacity) return 0
return 1

///*



Testing Code/Sample Implementation:

You can see of a demo of this snippet being used here or a variation of it in my Static Lighting Generator