function CreateCircleA1(x,y,speed,angle,distance,amount,graphic,delay){ // Creates a circle of bullets.
	let angleT = angle;
	loop(amount){
		let shot = CreateShotA1(x+distance*cos(angleT),y+distance*sin(angleT),speed,angleT,graphic,delay);
		angleT += 360/amount;
		return shot;
	}
}

function CreateCircleA2(x,y,speed,angle,accel,maxspeed,distance,amount,graphic,delay){ // Creates a circle of bullets. (with acceleration)
	let angleT = angle;
	loop(amount){
		let shot = CreateShotA2(x+distance*cos(angleT),y+distance*sin(angleT),speed,angleT,accel,maxspeed,graphic,delay);
		angleT += 360/amount;
		return shot;
	}
}

function CreateStraightLaserA2(x, y, angle, lng, wdt, deld, delt, graph, dl){ //deld is delete delay. delt is time it takes to shrink laser to nothingness
	let l = CreateStraightLaserA1(x, y, angle, lng, wdt, 413612, graph, dl);
	ShrinkLaser(l, wdt, deld, delt, dl);
	return l;
}
task ShrinkLaser(l, wdt, deld, delt, dl){
	let wdt2 = wdt;

	wait(dl+deld);
	loop(delt){
		ObjLaser_SetRenderWidth(l, wdt2);
		ObjLaser_SetIntersectionWidth(l, wdt2*0.5);
		wdt2 -= wdt/delt;
		yield;
	}
	Obj_Delete(l);
}

function GetAngleToBoss(obj){
	let angle = atan2(ObjMove_GetY(objBoss) -  ObjMove_GetY(obj), ObjMove_GetX(objBoss) -  ObjMove_GetX(obj));
	return angle;
}

function DelayLaser(x, y, ang, l, w, dt, graph, delay){ // By SparenOfIria. (i just made it a function instead of a task)
	let objLaser = CreateStraightLaserA1(x, y, ang, l, w, dt, graph, delay);
	ObjStLaser_SetSource(objLaser, false);
	DeleteLaser(objLaser, delay);
	return objLaser;
}
task DeleteLaser(objLaser, delay){
	loop(delay-1){
		if(ObjEnemy_GetInfo(objBoss, INFO_LIFE) <= 0){Obj_Delete(objLaser); return;}
		yield;
	}
	Obj_Delete(objLaser);
}

task ReflectWalls(obj, bounces){
	loop{
		while(bounces <= 0){yield;}
		if(ObjMove_GetX(obj) >= GetStgFrameWidth){
			ObjMove_SetAngle(obj, 180-ObjMove_GetAngle(obj));
			bounces -= 1;
		}
		else if(ObjMove_GetX(obj) <= GetStgFrameLeft-25){
			ObjMove_SetAngle(obj, 180-ObjMove_GetAngle(obj));
			bounces -= 1;
		}
		yield;
	}
}
task ReflectCeiling(obj, bounces){
	loop{
		while(bounces <= 0){yield;}
		if(ObjMove_GetY(obj) <= GetStgFrameTop){
			ObjMove_SetAngle(obj, -1*ObjMove_GetAngle(obj));
		}
		yield;
	}
}
task ReflectFloor(obj, bounces){
	loop{
		while(bounces <= 0){yield;}
		if(ObjMove_GetY(obj) >= GetStgFrameHeight){
			ObjMove_SetAngle(obj, -1*ObjMove_GetAngle(obj));
		}
		yield;
	}
}

function GetAllShotID{
	return GetShotIdInCircleA2(GetStgFrameWidth/2, GetStgFrameHeight/2, 1000, TARGET_ENEMY);
}

function ShootFromEnemyA1(enemy, radiusX, radiusY, speed, angle, graphic, delay){
	let shot = CreateShotA1(ObjMove_GetX(enemy)+radiusX*cos(angle), ObjMove_GetY(enemy)+radiusY*sin(angle), speed, angle, graphic, delay);
	return shot;
}

function ShootFromEnemyDA1(enemy, dispX, dispY, radiusX, radiusY, speed, angle, graphic, delay){
	let shot = CreateShotA1(ObjMove_GetX(enemy)+radiusX*cos(angle)+dispX, ObjMove_GetY(enemy)+radiusY*sin(angle)+dispY, speed, angle, graphic, delay);
	return shot;
}

function ShootFromEnemyA2(enemy, radiusX, radiusY, speed, angle, accel, maxspeed, graphic, delay){
	let shot = CreateShotA2(ObjMove_GetX(enemy)+radiusX*cos(angle), ObjMove_GetY(enemy)+radiusY*sin(angle), speed, angle, accel, maxspeed, graphic, delay);
	return shot;
}

function ShootFromEnemyDA2(enemy, dispX, dispY, radiusX, radiusY, speed, angle, accel, maxspeed, graphic, delay){
	let shot = CreateShotA2(ObjMove_GetX(enemy)+radiusX*cos(angle)+dispX, ObjMove_GetY(enemy)+radiusY*sin(angle)+dispY, speed, angle, accel, maxspeed, graphic, delay);
	return shot;
}

function CreateGravityShotA1(x, y, initial, gravity, angle, graphic, delay){
	let shot = CreateShotA1(x, y, initial, angle, graphic, delay);
	GravityBullets(shot, initial, gravity);
	return shot;
}
task GravityBullets(shot, initial, gravity){
	let grav = initial/2;
	while(!Obj_IsDeleted(shot)){
		grav += gravity;
		ObjMove_SetPosition(shot, ObjMove_GetX(shot), ObjMove_GetY(shot)+grav);
		yield;
	}
}

function CreateHomingShotA1(x, y, speed, angle, hdelay, htime, graphic, delay){
	let shot = CreateShotA1(x, y, speed, angle, graphic, delay);
	HomeShot1(shot, htime, hdelay);
	return shot;
}
task HomeShot1(shot, htime, hdelay){
	wait(hdelay);
	loop(htime){
		ObjMove_SetAngle(shot, GetAngleToPlayer(shot));
		yield;
	}
}
task HomeShot2(shot, spd, htime, hdelay){
	let ang = 0;

	wait(hdelay);
	loop(htime){
		ang = 0.9 * ObjMove_GetAngle(shot) + 0.1 * atan2(GetPlayerY - ObjMove_GetY(shot), GetPlayerX - ObjMove_GetX(shot));
		ObjMove_SetAngle(shot, NormalizeAngle(ang));
		//if(GetObjectDistance(GetPlayerObjectID, shot) < ObjMove_GetSpeed(shot)){ ObjMove_SetPosition(shot, GetPlayerX, GetPlayerY); }
		yield;
	}
}

function NormalizeAngle(angle){ // Thanks Ultima.
	angle %= 360;
	if(angle<0){ angle += 360; }
	return angle;
}

// Familiars.

let imgFamiliar = GetCurrentScriptDirectory ~ "../img/yingyang.png";

let orbcount = 0;

function CreateFamiliarA1(enemy, destX, destY, graphic){ // Create a familiar from the enemy to a destination.
	let objFamiliar = ObjEnemy_Create(OBJ_ENEMY);
	
	ObjEnemy_Regist(objFamiliar);
	ObjPrim_SetTexture(objFamiliar, imgFamiliar);
	ObjRender_SetScaleXYZ(objFamiliar, 1.5, 1.5, 0);
	ObjRender_SetAlpha(objFamiliar, 150);
	ObjMove_SetPosition(objFamiliar, ObjMove_GetX(enemy), ObjMove_GetY(enemy));
	ObjMove_SetDestAtWeight(objFamiliar, destX, destY, 12, 6);

	// Type 0 is invisible.
	
	if(graphic == 1){ // Visible.
		ObjSprite2D_SetSourceRect(objFamiliar,33,96,63,127);
		ObjSprite2D_SetDestCenter(objFamiliar);
		FamiliarSpin(objFamiliar);
	}

	return objFamiliar;
}
function CreateFamiliarA2(x, y, graphic){ // Create a familiar in a specific position.
	let objFamiliar = ObjEnemy_Create(OBJ_ENEMY);
	
	ObjEnemy_Regist(objFamiliar);
	ObjPrim_SetTexture(objFamiliar, imgFamiliar);
	ObjRender_SetScaleXYZ(objFamiliar, 1.5, 1.5, 0);
	ObjRender_SetAlpha(objFamiliar, 150);
	ObjMove_SetPosition(objFamiliar, x, y);

	// Type 0 is invisible.
	
	if(graphic == 1){ // Visible.
		ObjSprite2D_SetSourceRect(objFamiliar,33,96,63,127);
		ObjSprite2D_SetDestCenter(objFamiliar);
		FamiliarSpin(objFamiliar);
	}

	return objFamiliar;
}
function CreateFamiliarA3(x, y, speed, angle, graphic){ // Create a familiar in a specific position (with speed and angle).
	let objFamiliar = ObjEnemy_Create(OBJ_ENEMY);
	
	ObjEnemy_Regist(objFamiliar);
	ObjPrim_SetTexture(objFamiliar, imgFamiliar);
	ObjRender_SetScaleXYZ(objFamiliar, 1.5, 1.5, 0);
	ObjRender_SetAlpha(objFamiliar, 150);
	ObjMove_SetPosition(objFamiliar, x, y);
	ObjMove_SetSpeed(objFamiliar, speed);
	ObjMove_SetAngle(objFamiliar, angle);

	// Type 0 is invisible.
	
	if(graphic == 1){ // Visible.
		ObjSprite2D_SetSourceRect(objFamiliar,33,96,63,127);
		ObjSprite2D_SetDestCenter(objFamiliar);
		FamiliarSpin(objFamiliar);
	}

	return objFamiliar;
}
task FamiliarSpin(objFamiliar){
	let spinYY = 0;

	while(!Obj_IsDeleted(objFamiliar)){
		spinYY+=2;
		ObjRender_SetAngleXYZ(objFamiliar, 0, 0, -spinYY);
		yield;
	}
}