// --------------------- pattern 00 -----------------------------------

// Slow flurry of fairies at fixed speed, decelerates at centre then flies down gently.
task enyFlurrySlow(beginX,beginY,gotoX,gotoY,type) { 
	let obj = summonFairy(beginX,beginY,1,type);
	
	ObjMove_SetDestAtWeight(obj,gotoX,gotoY,20,30);
	fireBalFairy00(obj);
	while(ObjMove_GetSpeed(obj) > 0) { yield; }
	ObjMove_SetAcceleration(obj,0.1);
	ObjMove_SetSpeed(obj,0);
	ObjMove_SetAngle(obj,90);
	ObjMove_SetMaxSpeed(obj,1.5);
} 

// Slow flurry of fairies at fixed speed, decelerates at centre then flies down gently.
task enyFlurrySlow2(beginX,beginY,gotoX,gotoY,type) { 
	let obj = summonFairy(beginX,beginY,1,type);
	
	ObjMove_SetDestAtWeight(obj,gotoX,gotoY,20,30);
	fireBalFairy01(obj);
	while(ObjMove_GetSpeed(obj) > 0) { yield; }
	ObjMove_SetAcceleration(obj,0.1);
	ObjMove_SetSpeed(obj,0);
	ObjMove_SetAngle(obj,90);
	ObjMove_SetMaxSpeed(obj,1.5);
} 

// Train of fairies which appear from a side then gracefully switches sides.
task enyCrissCrossTrain(beginX,beginY,endX,endY,type,side) {
	let obj = summonFairy(beginX,beginY,1,type);
	let dir = 0;
	let r = 0;
	
	ObjMove_SetDestAtSpeed(obj,ObjMove_GetX(obj),endY,3);
	fireBalCrissCrossTrain(obj,side); 
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 
	dir = atan2(ObjMove_GetY(obj)-endY,ObjMove_GetX(obj)-GetCenterX);
	r = GetDistanceXY(ObjMove_GetX(obj),ObjMove_GetY(obj),GetCenterX,GetCenterY);
	loop(108) { 
		ObjMove_SetDestAtSpeed(obj,GetCenterX+r*cos(dir),GetCenterY+r*sin(dir),3); 
		if(side == "left") { dir-=2; }
		if(side == "right") { dir+=2; }
		yield; 
	} 
	fireBalCrissCrossTrain(obj,side);
	ObjMove_SetAngle(obj,dir); 
	ObjMove_SetSpeed(obj,3);
}

// Starting large fairy with several fams
task enyStartLargeFairy(beginX,beginY) {
	let objEny = summonFairy(beginX,beginY,50,LARGE_BAL);
	let dir = 0; 
	
	ObjMove_SetDestAtWeight(objEny,ObjMove_GetX(objEny),GetCenterY-64,20,30);	
	wait(30);
	if(!Obj_IsDeleted(objEny)) { 
		fireBalLargeFairy00(objEny);
	}
	ascent(i in 0..5) { 
		if(Obj_IsDeleted(objEny)) { break; } 
		let famFairy00a = summonFamiliar(10,FAM_RED,objEny);
		let famFairy00b = summonFamiliar(10,FAM_GREEN,objEny);

		patternFamSpin(famFairy00a,objEny,dir,64,3);
		patternFamSpin(famFairy00b,objEny,dir,96,-3);
		
		fireBalFamiliar00(famFairy00a);
		fireBalFamiliar00(famFairy00b);
		fireBalFamiliar01(famFairy00a);
		dir+=360/5;
	}
	
	while(ObjMove_GetSpeed(objEny) > 0) { yield; } 
	wait(180); 
	ObjMove_SetDestAtSpeed(objEny,ObjMove_GetX(objEny),GetClipMinY-64,4);	
}

// --------------------- pattern 01 -----------------------------------

// flurry fairies
task enyFlurry01 {
	enyFlurryLeft;
	wait(45);
	enyFlurryRight;
}

// Flurry fairies towards left side
task enyFlurryLeft {
	let balFairy00a = summonFairy(GetCenterX-96,GetClipMinY-16,1,SMALL_BAL_RED);
	let balFairy00b = summonFairy(GetCenterX-72,GetClipMinY-16,1,SMALL_BAL_BLUE);
	let balFairy00c = summonFairy(GetCenterX-40,GetClipMinY-16,1,SMALL_BAL_BLUE);
	let balFairy00d = summonFairy(GetCenterX-48,GetClipMinY-16,1,SMALL_BAL_RED);
	
	patternFlurryDown(balFairy00a,GetCenterX-96,32,GetClipMinX-32,64);
	wait(30);
	patternFlurryDown(balFairy00b,GetCenterX-72,48,GetClipMinX-32,32);
	wait(30);
	patternFlurryDown(balFairy00c,GetCenterX-40,112,GetClipMinX-32,96);
	wait(30);
	patternFlurryDown(balFairy00d,GetCenterX-112,64,GetClipMinX-112,64);
} 

// Flurry fairies towards right side
task enyFlurryRight {
	let balFairy00a = summonFairy(GetCenterX+96,GetClipMinY-16,1,SMALL_BAL_BLUE);
	let balFairy00b = summonFairy(GetCenterX+72,GetClipMinY-16,1,SMALL_BAL_RED);
	let balFairy00c = summonFairy(GetCenterX+40,GetClipMinY-16,1,SMALL_BAL_BLUE);
	let balFairy00d = summonFairy(GetCenterX+32,GetClipMinY-16,1,SMALL_BAL_BLUE);
	
	patternFlurryDown(balFairy00a,GetCenterX+96,32,GetClipMaxX+32,64);
	wait(30);
	patternFlurryDown(balFairy00b,GetCenterX+72,48,GetClipMaxX+32,32);
	wait(30);
	patternFlurryDown(balFairy00c,GetCenterX+40,112,GetClipMaxX+32,96);
	wait(30);
	patternFlurryDown(balFairy00d,GetCenterX,48,GetClipMaxX+32,96);
} 

// Flurry downs a fairy at fixed accelerated speed, decelerates then flies away to the side gently. 
task patternFlurryDown(obj,beginX,beginY,endX,endY) {
	ObjMove_SetDestAtWeight(obj,beginX,beginY,10,30);
	while(ObjMove_GetSpeed(obj) > 0) { yield; }
	fireBalFlurryShot00(obj);
	wait(60);
	ObjMove_SetAcceleration(obj,0.1);
	ObjMove_SetSpeed(obj,0);
	ObjMove_SetAngle(obj,atan2(endY-ObjMove_GetY(obj),endX-ObjMove_GetX(obj)));
	ObjMove_SetMaxSpeed(obj,3);
} 

// --------------------- pattern 02 -----------------------------------

// Swirl a train of fairies from the top and from the bottom
task enySwirl01 {
	enySwirlBottom;
	enySwirlTop;
}

// Bottom swirling fairies 8x
task enySwirlBottom {
	ascent(i in 0..8) {
		let balFairy01a = summonFairy(GetCenterX-175,GetClipMaxY+16,1,SMALL_BAL_RED);
		patternSwirl(balFairy01a,"bottom");
		wait(15);
	}
} 

// Top swirling fairies 8x
task enySwirlTop {
	ascent(i in 0..8) {
		let balFairy01b = summonFairy(GetCenterX+175,GetClipMinY-16,1,SMALL_BAL_BLUE);
		patternSwirl(balFairy01b,"top");
		wait(15);
	}
}

// Swirls the fairies in a circle using the centre xy of the stage as pivot point then leaves the stage
task patternSwirl(obj,side) {
	let r = 0; 
	let dir = 0;
	
	if(side == "bottom") { ObjMove_SetDestAtSpeed(obj,GetCenterX-175,GetCenterY,3); }
	if(side == "top") { ObjMove_SetDestAtSpeed(obj,GetCenterX+175,GetCenterY,3); fireBalSwirlingTrain01(obj);  }
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 
	
	if(side == "bottom") { fireBalSwirlingTrain(obj); } 
	
	dir = atan2(ObjMove_GetY(obj)-GetCenterY,ObjMove_GetX(obj)-GetCenterX);
	r = GetDistanceXY(ObjMove_GetX(obj),ObjMove_GetY(obj),GetCenterX,GetCenterY);
	loop(128) { 
		ObjMove_SetDestAtSpeed(obj,GetCenterX+r*cos(dir),GetCenterY+r*sin(dir),3); 
		dir+=1.2; 
		yield; 
	} 
	ObjMove_SetAngle(obj,-dir); 
	ObjMove_SetSpeed(obj,3);
}

// Swirls the fairies in a circle using the centre xy as pivot point. Freely configurable unlike patternSwirl which belongs to the special swirl pattern
task enySwirlFree(beginX,beginY,type,side) {
	let obj = summonFairy(beginX,beginY,1,type);
	let r = 0; 
	let dir = 0;
	
	if(side == "bottom") { ObjMove_SetDestAtSpeed(obj,GetCenterX-160,GetCenterY,3); }
	if(side == "top") { ObjMove_SetDestAtSpeed(obj,GetCenterX+160,GetCenterY,3); }
	fireMidTrain(obj);
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 
	dir = atan2(ObjMove_GetY(obj)-GetCenterY,ObjMove_GetX(obj)-GetCenterX);
	r = GetDistanceXY(ObjMove_GetX(obj),ObjMove_GetY(obj),GetCenterX,GetCenterY);
	loop(220) { 
		ObjMove_SetDestAtSpeed(obj,GetCenterX+r*cos(dir),GetCenterY+r*sin(dir),3); 
		dir+=1.5; 
		yield; 
	} 
	ObjMove_SetAngle(obj,-dir); 
	ObjMove_SetSpeed(obj,3);	
} 


// Bottom jumping fairies
task enyJumpy01(startX,startY,dir,height,hp,type,leavedir) { 
	let balFairy02a = summonFairy(startX,startY,hp,type);
	patternJumpElegant(balFairy02a,startX,startY,dir,height,leavedir); 
} 

// Makes the fairy jump from bottom into the air, spin/float gently for a moment then drop down again
task patternJumpElegant(obj,startX,startY,dir,height,leavedir) { 
	let rx = 0;
	let ry = height; 
	rx = GetDistanceXY(ObjMove_GetX(obj),ObjMove_GetY(obj),GetCenterX,startY);
	ObjMove_SetDestAtWeight(obj,GetCenterX-rx*cos(dir),GetClipMaxY-ry*sin(dir),10,5);
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 

	fireBalJumpyFairy(obj);

	wait(45);
	if(startX < GetCenterX) { ObjMove_SetDestAtSpeed(obj,ObjMove_GetX(obj)+1000,ObjMove_GetY(obj)+leavedir,2); }
	if(startX > GetCenterX) { ObjMove_SetDestAtSpeed(obj,ObjMove_GetX(obj)-1000,ObjMove_GetY(obj)+leavedir,2); }
} 

// Twin familiar user fairy
task enyTwinFamFairy00(beginX,beginY) { 
	let objEny = summonFairy(beginX,beginY,20,AURA_RED);
	let famFairy00a = summonFamiliar(7,FAM_WHITE,objEny);
	let famFairy00b = summonFamiliar(7,FAM_WHITE,objEny);
	patternFamSpin(famFairy00a,objEny,0,45,3);
	patternFamSpin(famFairy00b,objEny,180,45,3);
	
	ObjMove_SetDestAtSpeed(objEny,ObjMove_GetX(objEny),GetCenterY-64,2);	
	while(ObjMove_GetSpeed(objEny) > 0) { yield; } 
	if(!Obj_IsDeleted(objEny)) { 
		fireBalTwinFamFairy(objEny);
		fireBalTwinFamShot(famFairy00a); 
		fireBalTwinFamShot(famFairy00b); 
	}
	wait(180); 
	ObjMove_SetDestAtSpeed(objEny,ObjMove_GetX(objEny),GetClipMaxY+64,1.5);	
} 

// Twin familiar user fairy
task enyTwinFamFairy01(beginX,beginY) { 
	let objEny = summonFairy(beginX,beginY,15,AURA_BLUE);
	let famFairy00a = summonFamiliar(7,FAM_WHITE,objEny);
	let famFairy00b = summonFamiliar(7,FAM_WHITE,objEny);
	patternFamSpin(famFairy00a,objEny,0,45,3);
	patternFamSpin(famFairy00b,objEny,180,45,3);
	fireBalTwinFamShot01(famFairy00a);
	fireBalTwinFamShot01(famFairy00b);
	
	ObjMove_SetDestAtSpeed(objEny,ObjMove_GetX(objEny),GetCenterY-64,2);	
	while(ObjMove_GetSpeed(objEny) > 0) { yield; } 
	if(!Obj_IsDeleted(objEny)) { 
		fireBalTwinFamFairy01(objEny);
	}
	wait(180); 
	ObjMove_SetDestAtSpeed(objEny,GetCenterX,GetClipMinY-64,2);	
} 

// Twin familiar user fairy
task enyMultiFamFairy00(beginX,beginY,endX,endY,fams,typefam) { 
	let objEny = summonFairy(beginX,beginY,30,AURA_RED);
	let dir = 0;

	ascent(i in 0..fams) { 
		if(Obj_IsDeleted(objEny)) { break; } 
		let famFairy00a = summonFamiliar(5,typefam,objEny);
		patternFamSpin(famFairy00a,objEny,dir,64,3);
		fireBalMultiFamShot00(famFairy00a);
		dir+=360/fams;
	}
	ObjMove_SetDestAtWeight(objEny,endX,endY,15,30);	
	fireBalMultiFamFairy(objEny);
	while(ObjMove_GetSpeed(objEny) > 0) { yield; } 
	wait(240); 
	ObjMove_SetDestAtSpeed(objEny,GetCenterX,GetClipMinY-64,2);	
} 

// Makes the familiar follow the fairy user at specified x / y location. 
task patternFamFollow(obj,masterobj,xpos,ypos) {
	while(!Obj_IsDeleted(masterobj)) { 
		ObjMove_SetPosition(obj,ObjMove_GetX(masterobj)+xpos,ObjMove_GetY(masterobj)+ypos);
		yield;
	}
} 

// --------------------- pattern 03 -----------------------------------

// Aura fairy which fires homing familiars at the player.
task enyHomingFamFairy(startX,startY) { 
	let balFairy00a = summonFairy(startX,startY,20,LARGE_BAL);
	
	ObjMove_SetDestAtWeight(balFairy00a,startX,120,15,60);
	fireBalHomingFairy(balFairy00a);
	wait(60);
	
	ascent(i in 0..6) {
		if(!Obj_IsDeleted(balFairy00a)) { 
			let famFairy00a = summonFamiliar(4,FAM_RED,balFairy00a);
			patternFamThrow(famFairy00a,balFairy00a,0,4,GetAngleToPlayer(balFairy00a),0.05);
			wait(45 - i*4.5);
		}
	}
	wait(60);
	ObjMove_SetDestAtSpeed(balFairy00a,startX,-32,2);
}

// Makes the familiar be thrown at player (aimed upon fire), allows velocity, max velocity, direction and acceleration
task patternFamThrow(obj,masterobj,v,maxv,dir,acc) {
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAcceleration(obj,acc);
	ObjMove_SetMaxSpeed(obj,maxv);
	ObjMove_SetAngle(obj,dir);
}

// Large floating fairies 2x
task enyLargeFloat01 {
	let balLargeFairy01a = summonFairy(GetCenterX-120,GetClipMinY-16,50,LARGE_BAL);
	patternFloatSide(balLargeFairy01a,"left");
	wait(30);
	let balLargeFairy01b = summonFairy(GetCenterX+120,GetClipMinY-16,50,LARGE_BAL);
	patternFloatSide(balLargeFairy01b,"right");	
}

// Makes the familiars revolve around the fairy user, allows to specify starting angle, radius and revolving speed
task patternFamSpin(obj,masterobj,startdir,maxr,dirv) {
	let dir = startdir;
	let r = 0;
	while(!Obj_IsDeleted(obj)) { 
		dir+=dirv;
		ObjMove_SetPosition(obj,ObjMove_GetX(masterobj)+r*cos(dir),ObjMove_GetY(masterobj)+r*sin(dir));
		ObjMove_SetAngle(obj,dir);
		if(r < maxr) { r++; }
		yield;
	}
} 

// Makes the fairy float towards the side opposite of start location
task patternFloatSide(obj,side) {
	ObjMove_SetDestAtSpeed(obj,ObjMove_GetX(obj),GetCenterY-32,1);
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 
	if(side == "right") { ObjMove_SetDestAtSpeed(obj,GetClipMinX-32,ObjMove_GetY(obj),1); }
	if(side == "left") { ObjMove_SetDestAtSpeed(obj,GetClipMaxX+32,ObjMove_GetY(obj),1); }
} 

// Train appearing from middle of field, making a spin then leaving down towards player. 
task enyMiddleTrain(beginX,beginY,endX,endY,type,side) { 
	let obj = summonFairy(beginX,beginY,1,type);
	let dir = 0;
	let r = 0;
	
	ObjMove_SetDestAtSpeed(obj,endX,endY,3);
	fireMidTrain(obj);
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 
	dir = atan2(ObjMove_GetY(obj)-endY,ObjMove_GetX(obj)-endX);
	r = GetDistanceXY(ObjMove_GetX(obj),ObjMove_GetY(obj),endX,endY);
	loop(128) { 
		ObjMove_SetX(obj,ObjMove_GetX(obj)-r*cos(dir));
		ObjMove_SetY(obj,ObjMove_GetY(obj)-r*sin(dir));
		r = 3;
		if(side == "left") { dir-=2; }
		if(side == "right") { dir+=2; }
		yield; 
	} 
	ObjMove_SetAngle(obj,-dir); 
	ObjMove_SetSpeed(obj,3);	
} 

// Shotgunning familiar user mini fairy
task enyShotGunFamFairy(beginX,beginY,endX,endY,type) { 
	let obj = summonFairy(beginX,beginY,5,type);
	
	ObjMove_SetDestAtWeight(obj,endX,endY,15,60);
	while(ObjMove_GetSpeed(obj) > 0) { yield; } 	
	
	if(!Obj_IsDeleted(obj)) { 
		ascent(i in 0..3) {
			let famFairy00a = summonFamiliar(4,FAM_GREEN,obj);
			patternFamThrow(famFairy00a,obj,0,2,GetAngleToPlayer(obj)+(i*12),0.5);
		}
	}	
	wait(30);
	if(!Obj_IsDeleted(obj)) { 
		fireShotGunFamFairy(obj);
	}
	wait(90);
	ObjMove_SetDestAtSpeed(obj,ObjMove_GetX(obj),GetClipMinY-32,2);
} 

// --------------------- pattern 05 -----------------------------------

// circle of fairies jump in and spin around main big fairy
task enyPirouette(startX,startY) { 
	let balFairy02a = summonFairy(startX,startY,100,LARGE_BAL);
	let r = 200; 
	let dir = 0;
	
	ObjMove_SetDestAtSpeed(balFairy02a,GetCenterX,GetCenterY,3); 
	while(ObjMove_GetSpeed(balFairy02a) > 0) { yield; }
	PlaySFX(SFX_OPTION);
	ascent(i in 0..12) { 
		enySummonEffect(GetCenterX+r*cos(dir),GetCenterY+r*sin(dir),0.01,0.01,0);
		miniPirouette(balFairy02a,dir,r,i);
		dir-=360/12;
		wait(5);
	}
	fireBalPirouette(balFairy02a);
} 

// movement + mini fairy spawn of enyPirouette. It spawns circular for fairies which move towards the big fairy (centre) 
// then spins around and after a short while expands out while gaining angular velocity. 
task miniPirouette(obj,dir,r,delay) {
	let spin = 0;
	let	c = 0;
	wait(30-delay);
	let balFairy04a = summonFairy(ObjMove_GetX(obj)+r*cos(dir),ObjMove_GetY(obj)+r*sin(dir),1,SMALL_BAL_RED);
	wait(60-delay);
	fireBalPirouetteMini(balFairy04a);
	while(r > 64) { 
		r-=2; 
		dir++;
		ObjMove_SetX(balFairy04a,GetCenterX+r*cos(dir));
		ObjMove_SetY(balFairy04a,GetCenterY+r*sin(dir));
		yield;
	} 
	while(spin < 360) { 
			spin++; 
			dir++; 
			ObjMove_SetX(balFairy04a,GetCenterX+r*cos(dir));
			ObjMove_SetY(balFairy04a,GetCenterY+r*sin(dir));
			if(c == 120) { ObjMove_SetDestAtSpeed(obj,GetCenterX,GetClipMaxY+32,3); }
			if(c > 60) { r = r + 1 * 2.5; } 
			c++;
			yield; 
	} 
}

// --------------------- pattern 06 -----------------------------------

// Wall of fairies appear from the side and launch their selves forward to the other side. 
task enyWallAttack(startX,startY,endX,type,moveSide) { 
	ascent(i in 0..7) {
		let balFairy05a = summonFairy(startX,startY,5,type);
		patternWallAttack(balFairy05a,startX,ObjMove_GetY(balFairy05a),endX,moveSide);
		fireBalWallAttackPre(balFairy05a);
		fireBalWallAttack(balFairy05a,moveSide);
		startY+=64;
	}
} 

task patternWallAttack(obj,x1,y1,x2,s) {
	if(s == "left") { ObjMove_SetDestAtWeight(obj,x1-8,y1,10,20); }
	if(s == "right") { ObjMove_SetDestAtWeight(obj,x1+8,y1,10,20); }
	wait(60);
	ObjMove_SetDestAtSpeed(obj,x2,y1,3);
}  

// --------------------- pattern 07 -----------------------------------

// Creates two mini fairies which revolve around their original centre, causing them to "dance" in circles
task enyTwinPirouette(startX,startY,endX,endY,spindir) { 
	let r = 16;
	let dir = 0;

	let balFairy05a = summonFairy(startX+r*cos(dir),startY+r*sin(dir),5,SMALL_BAL_RED);
	let balFairy05b = summonFairy(startX+r*cos(dir+180),startY+r*sin(dir+180),5,SMALL_BAL_BLUE);
	fireBalDancingFairy(balFairy05a);
	while(!Obj_IsDeleted(balFairy05a) || !Obj_IsDeleted(balFairy05b)) { 
		dir+=spindir; 
		ObjMove_SetPosition(balFairy05a,startX+r*cos(dir),startY+r*sin(dir));
		ObjMove_SetPosition(balFairy05b,startX+r*cos(dir+180),startY+r*sin(dir+180));
		startY++;
		yield;
	}
}