/** Common Enemy Tools **/

function eFallBack(args: Array<Dynamic>) : Void
{
	var self: Enemy = args[0];
	self.vy -= GameScene.levelSpeed;
}

function eMoveEase(args:Array<Dynamic>) : Bool
{
	var self: Enemy = args[0];
	var sx: Float = args[1];
	var sy: Float = args[2];
	var tox: Float = args[3];
	var toy: Float = args[4];
	var t: Float = args[5];
	
	self.vx = sx + (tox - sx) * Ease.sineInOut(t);
	self.vy = sy + (toy - sy) * Ease.sineInOut(t);
	
	return t >= 1;
}

function eOvalEase(args:Array<Dynamic>) : Bool
{
	var self: Enemy = args[0];
	var sx: Float = args[1]; // "start x"
	var sy: Float = args[2]; // "start y"
	var tox: Float = args[3]; // "destination x"
	var toy: Float = args[4]; // "destination y"
	var t: Float = args[5]; // "time ratio (start: 0, end: 1)"
	
	var pt: Point = getOvalPoint(tox - sx, toy - sy, t, true);
	
	self.vx = sx + pt.x;
	self.vy = sy + pt.y;
	
	return t >= 1; // returns whether the movement is over based off of the time ratio
}

function eGetDodge(args:Array<Dynamic>) : Float //returns x to dodge the projected collision
{
	var self: Enemy = args[0];
	var space: Float = Level.TILE_SIZE;
	var ahead: Float = space * args[1];
	var sidestep: Float = 0;
	var freeL: Bool = false; // free to move left
	var freeR: Bool = false; // free to move right
	
	do
	{
		var partHitL: Bool = false; // if there's a hit on the left sidestep at least once
		var partHitR: Bool = false; // if there's a hit on the right sidestep at least once
		for (type in self.dodgeThese)
		{
			if (!freeL)
				if (self.collide(type, self.x - sidestep, self.y + ahead) != null)
					partHitL = true;
			
			if (!freeR)
				if (self.collide(type, self.x + sidestep, self.y + ahead) != null)
					partHitR = true;
		}
		
		if (!partHitL)
			freeL = true;
		if (!partHitR)
			freeR = true;
		
		if (!freeL && !freeR)
			sidestep += space;
	}
	while (!freeL && !freeR)
	
	var absL: Float = freeL ? sidestep : Math.POSITIVE_INFINITY;
	var absR: Float = freeR ? sidestep : Math.POSITIVE_INFINITY;
	
	return Math.min(absL, absR) == absL ? -sidestep : sidestep;
}

function eGetClearPath(args:Array<Dynamic>) : Point
{
	var self: Enemy = args[0];
	var x: Float = self.x;
	var y: Float = self.y;
	var mx: Float = args[1];
	var my: Float = args[2];
	
	if (mx == 0 && my == 0)
		return new Point(0, 0);
	
	var space: Int = Level.TILE_SIZE;
	var c: Float = Math.sqrt(Math.abs(mx) * Math.abs(mx) + Math.abs(my) * Math.abs(my));
	var div: Float = 1 / Math.floor(c / space);
	var prog: Float = div;
	var tweenX: Float = 0;
	var tweenY: Float = 0;
	
	do
	{
		var lastTX: Float = tweenX;
		var lastTY: Float = tweenY;
		
		tweenX = mx * prog;
		tweenY = my * prog;
		
		for (type in self.dodgeThese)
			if (self.collide(type, x + tweenX, y + tweenY) != null)
				return new Point(Math.round(lastTX / space) * space, lastTY);
		prog += div;
	}
	while (prog < 1)
	
	return new Point(Math.round(mx / space) * space, my);
}

function eGetClearOvalPath(args:Array<Dynamic>) : Point
{
	var self: Enemy = args[0];
	var xx: Float = self.x;
	var yy: Float = self.y;
	var mx: Float = args[1];
	var my: Float = args[2];
	
	if (mx == 0 && my == 0)
		return new Point(0, 0);
	
	var space: Int = Level.TILE_SIZE;
	var mxl: Float = Math.abs(mx);
	var myl: Float = Math.abs(my);
	var ramanujan: Float = Math.PI / 4 * (3 * (mxl + myl) - Math.sqrt((3 * mxl + myl) * (mxl + 3 * myl))); // The length of the curve
	var div: Float = 1 / Math.floor(ramanujan / space);
	var prog: Float = div;
	var pt: Point = new Point(0, 0);
	
	do
	{
		var lastTX: Float = pt.x;
		var lastTY: Float = pt.y;
		
		pt = getOvalPoint(mx, my, prog, false);
		
		for (type in self.dodgeThese)
			if (self.collide(type, xx + pt.x, yy + pt.y) != null)
				return new Point(Math.round(lastTX / space) * space, lastTY);
		prog += div;
	}
	while (prog < 1)
	
	return new Point(Math.round(mx / space) * space, my);
}

/*Common Entity Tools*/

function entityClosestWall(args:Array<Dynamic>) : Int
{
	var self: Entity = args[0];
	var max: Int = args[1];
	var dodgeThese: Array<String> = args[2];
	var x: Float = self.x;
	var y: Float = self.y;
	
	var space: Float = Level.TILE_SIZE;
	var spaces: Float = 0;
	
	do
	{
		for (type in dodgeThese)
		{
			if (self.collide(type, x + spaces, y) != null)
				return 1;
			if (self.collide(type, x - spaces, y) != null)
				return -1;
		}		
		spaces += space;
	}
	while (spaces / space < max)
	
	return 0;
}

/**Common Projectile Tools**/

function pMoveDir(args:Array<Dynamic>) : Void
{
	var self: Projectile = args[0];
	self.vx += Math.cos(self.direction) * self.speed;
	self.vy += Math.sin(self.direction) * self.speed;
}

/**Local Tools**/

// NOTE: Do not use outside of Toolbelt

function getOvalPoint(mx:Float, my:Float, t:Float, ease:Bool) : Point
{
	var sAngle: Float = 0; // "start angle"
	var arcDir: Int = mx > 0 ? 1 : -1; // "direction to rotate (clockwise / counter-clockwise)"
	var yAdjust: Float = -Math.abs(my);
	
	var d90: Float = Math.PI / 2; // "90 degrees in radians"
	
	if (my > 0)
	{
		sAngle = d90; // set start angle to 90 degrees
	}
	else
	{
		sAngle = -d90; // set start angle to -90 degrees
		arcDir *= -1; // sets the direction to rotate to clockwise
		yAdjust = -yAdjust;
	}
	
	var progAngle: Float = sAngle + arcDir * d90 * (ease ? Ease.sineInOut(t) : t);
	
	var x: Float = Math.cos(progAngle) * Math.abs(mx);
	var y: Float = Math.sin(progAngle) * Math.abs(my) + yAdjust;
	
	return new Point(x, y);
}
