/*

DO NOT EDIT THIS FILE! It's a library and may break a lot of things.

Greetings everyone, this is a short functional library to give some helpful get_ procs based on positional and angular inputs.

It also includes a helpful replacement for get_dir called get_dir_angle()
As it stands, get_dir will return NORTH, SOUTH, EAST, and WEST only when the target atom is at exactly that direction from the source.
Otherwise it returns a combination, such as NORTHEAST. Let's have an example...

 A=source, B=target
______________________________________
|                                     |
|   A                                 |
|                             B       |
|_____________________________________|

In the example above, B is 26 spaces tot he right of A, while it's only 1 space lower. BYOND's get_dir returns SOUTHEAST in this situation.
The issue is that if you want A's dir to look intuitively toward B, it would return EAST, as the offset in the Y position is far outweighed by that in the X position.

That is what get_dir_angle() does. First it uses get_angle() to calculate the proper angle between A and B, and uses that angle to return a more appropriate direction.

This is helpful in projects that use 8 directional icons, or just want to have more approprite returned angle. I've also included a version for 4 directional calls in case you'd like
to only return NORTH, EAST, SOUTH, or WEST, and never anything inbetween. There is also a slightly more accurate version for mobs, in case you want step offsets to be applied as well.


Procs
	get_dir_angle(atom/a,atom/b) - This uses the angle between atoms (a) and (b) to give a more appropriate result than get_dir.
	get_dir_angle4(aton/a,atom/b) - much like get_dir_angle, but only resolves the four cardinal directions.
	get_angle(atom/a,atom/b) - a basic angle proc for two atoms based on loc, this proc is used for get_dir_angle, as sometimes you want the angle for atoms. This uses get_angle_nums to process its return.
	get_angle_nums(ax,ay,bx,by) - a basic angle proc for numerical values. This is used if you already have four numbers to pass as arguments instead of atoms. This is used by get_angle().
	get_pix_pos(atom/a) - This proc is used by get_angle() in the event that any of the arguments are atoms. It returns a list of the atoms position (in pixels) in two variables. Ex: list(320,336)
	get_angle_dir(atom/a) - this proc gives you the angle based on a given atom (or dir). This is helpful if you're using accurate angles already and you wish to find the angle of a dir.
	get_turn(a,b) - when working with angles, find which direction, clockwise or counterclockwise, the angle (a) should be adjusted in order to reach the angle provided (b).
	between(a,b,c,strict) - find whether or not value (a) is between (b) and (c). Strict denotes that (a) cannot be equal to (b) or (c).
	get_dist_sq(atom/a,atom/b) - a helper proc I added for the hell of it. Returns a true distance in pixels based on pythagorean theorem a^2+b^2=c^2

*/


proc
	get_dir_angle(atom/a,atom/b)
		var/d
		var/n=get_angle(a,b)
		if(n>=337.5 || n<=22.5) d=EAST
		if(n>=22.5 && n<=67.5) d=SOUTHEAST
		if(n>=67.5 && n<=112.5) d=SOUTH
		if(n>=112.5 && n<=157.5) d=SOUTHWEST
		if(n>=157.5 && n<=202.5) d=WEST
		if(n>=202.5 && n<=247.5) d=NORTHWEST
		if(n>=247.5 && n<=292.5) d=NORTH
		if(n>=292.5 && n<337.5) d=NORTHEAST
		return d

	get_dir_angle4(atom/a,atom/b)
		var/d
		var/n=get_angle(a,b)
		if(n>=315 || n<=45) d=EAST
		if(n>=45 && n<=135) d=SOUTH
		if(n>=135 && n<=225) d=WEST
		if(n>=225 && n<=315) d=NORTH
		return d

	get_angle(a,b,c,d)
		if(!a && !b && !c && !d) CRASH("No arguments given or arguments are null")
		if(isnum(a) && isnum(c)) return get_angle_nums(a,b,c,d)
		if(!isnum(a))
			if(!isnum(b))
				var/list/a_pos=get_pix_pos(a)
				var/list/b_pos=get_pix_pos(b)
				return get_angle_nums(a_pos[1],a_pos[2],b_pos[1],b_pos[2])
			else
				var/list/a_pos=get_pix_pos(a)
				return get_angle_nums(a_pos[1],a_pos[2],b,c)
		else if(!isnum(c))
			var/list/c_pos=get_pix_pos(c)
			return get_angle_nums(a,b,c_pos[1],c_pos[2])

	get_angle_nums(ax,ay,bx,by)
		var/val = sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay))
		if(!val) return 0
		var/ar = arccos((bx - ax) / val)
		var/deg = round(360 - (by - ay >= 0 ? ar : -ar), 1)
		while(deg > 360) deg -= 360
		while(deg < 0) deg += 360
		return deg

	get_pix_pos(atom/a)
		var/xstep=0
		var/ystep=0
		if(ismob(a))
			var/mob/m=a
			xstep=m.step_x
			ystep=m.step_y
		return list(a.x*world.icon_size+xstep,a.y*world.icon_size+ystep)

	get_angle_dir(atom/m)
		var/a
		var/testdir
		if(ismob(m)) testdir=m.dir
		else testdir=m
		switch(testdir)
			if(NORTH) a=270
			if(NORTHEAST) a=315
			if(NORTHWEST) a=225
			if(EAST) a=0
			if(WEST) a=180
			if(SOUTH) a=90
			if(SOUTHEAST) a=45
			if(SOUTHWEST) a=135
		return a

	get_turn(var/a as num, var/b as num)
		var/test1=abs(a-b)
		var/test2=abs(0-a)
		var/test3=abs(360-a)
		var/test4
		var/direction="0"
		if(test3<test2)
			test4=test3+abs(0-b)
			direction="360"
		else
			test4=test2+360-b
		if(test1<test4)
			if(b-a<0) return -1
			else return 1
		else
			if(direction=="360")
				return 1
			else
				return -1


	between(a,b,c,strict=0)
		if(strict) if(a>b&&a<c) return 1 //strict denotes that (a) must not be equal to b or c, but must also be between b and c
		else if(a>=b&&a<=c) return 1


	get_dist_sq(atom/a,atom/b)
		var/dx=abs(a.x-b.x)
		var/dy=abs(a.y-b.y)
		var/a2=dx*dx
		var/b2=dy*dy
		var/c2=a2+b2
		return sqrt(c2)


