//****************************************************************************************************
//	Common functions for effects or rendering the boss
//	Version: 1.0
//	Library:
//		renderBoss 					- Handles the boss rendering including animation.
//		renderBoss2 				- Handles the second boss rendering including animation.
//		setInvulnerableTime			- Sets invulnerability time for boss in frames. 
//		shareLifeHandler			- Creates shared life handling for main + partner (duo fights).
//		enemyMarker					- Grants enemy marker like classic games to aid the player.
//		breakEffect 				- Handles the glitter effect spawning for the spell circle.
//		breakEffectGlitter 			- Glitter effect.
//		concenEffect				- Grants concentration effect with various textures.
//		concenEffectHandler			- Handles the concentration effect.
//		concenAngleHandler			- Handles the direction movement of the concentration effect.
//		colorMixer					- Randomizes rapidly R G B values for disco effect. 
//		exploEffect					- Grants explosion effect such as in old 0.12m.
//		enyExplodeEffect			- Grants pichuun effect when an enemy is shot down.
//		famExplodeEffect			- Grants pichuun effect when a familiar is shot down.
//		enyExplodeGlitterParticle 	- Glitter particles for enemies/familiars shot down.
//		enyExplodeTypeParticle		- Type particles for enemies/familiars shot down.
//		showCollectLine				- Draws the auto-collect item line.
//****************************************************************************************************

#include "script/thdcs/functions/function_loaddata.txt"

//global vars
let mainBossHP = 0;

// Primary boss vars
let bossObj;
let bossX = 0;
let bossY = 0;
let bossf = 0;
let bossf2 = 0;
let bossf3 = 0;
let bossFloat = 0;
let bossFloatF = 0;
let bossAttack = 0;
let headSpeed = 0;

// Secondary boss vars
let boss2Obj;
let boss2X = 0;
let boss2Y = 0;
let boss2f = 0;
let boss2f2 = 0;
let boss2f3 = 0;
let boss2Float = 0;
let boss2FloatF = 0;
let boss2Attack = 0;

// Main boss rendering task. Draws the boss and handles the sprite animation. 
task renderBoss(type) {
	let dir;
	let speed; 
	bossObj = ObjEnemy_Create(OBJ_ENEMY_BOSS);
	ObjEnemy_Regist(bossObj);
	
	enemyMarker(bossObj, "main");
	ObjEnemy_SetDamageRate(bossObj, 100, 100);
	
	SetCommonData("bossRenderType", type);
	
	// textures and initial rect sizes for the render 1
	if(type == 11) { ObjPrim_SetTexture(bossObj,imgMidBal); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); ObjRender_SetScaleXYZ(bossObj,1.0,1.0,0); }
	if(type == 22) { ObjPrim_SetTexture(bossObj,imgMidAfro); ObjSprite2D_SetSourceRect(bossObj,0,0,128,128); ObjRender_SetScaleXYZ(bossObj,1,1,0); }
	if(type == 23) { ObjPrim_SetTexture(bossObj,imgMidNue); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 24) { ObjPrim_SetTexture(bossObj,imgMidKogasa); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 31) { ObjPrim_SetTexture(bossObj,imgMidReimu); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); ObjRender_SetScaleXYZ(bossObj,0.8,0.8,0); }
	if(type == 32) { ObjPrim_SetTexture(bossObj,imgMidYukari); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 33) { ObjPrim_SetTexture(bossObj,imgMidMarisa); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 34) { ObjPrim_SetTexture(bossObj,imgMidArisu); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	
	if(type == 1) { ObjPrim_SetTexture(bossObj,imgBossBal); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); ObjRender_SetScaleXYZ(bossObj,1,1,0); }
	if(type == 2) { ObjPrim_SetTexture(bossObj,imgBossAfro); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); ObjRender_SetScaleXYZ(bossObj,1.0,1.0,0); }
	if(type == 3) { ObjPrim_SetTexture(bossObj,imgBossDj); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); ObjRender_SetScaleXYZ(bossObj,1.0,1.0,0); }
	
	if(type == 10) { ObjPrim_SetTexture(bossObj,imgBossHina); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 20) { ObjPrim_SetTexture(bossObj,imgBossIku); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	if(type == 30) { ObjPrim_SetTexture(bossObj,imgBossTewi); ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
	
	Obj_SetRenderPriorityI(bossObj, 30);
	ObjSprite2D_SetDestCenter(bossObj); 
	
	// as long as the boss object is alive
	while(!Obj_IsDeleted(bossObj)) {

		// update info about the boss
		dir = ObjMove_GetAngle(bossObj);
		speed = ObjMove_GetSpeed(bossObj);
		bossX = ObjMove_GetX(bossObj);
		bossY = ObjMove_GetY(bossObj);	

		// Antilope animation //-------------------------------------------------------------------------------------------------------------
		if(type == 11) {
			ObjSprite2D_SetDestRect(bossObj,-48,-64+bossFloat,48,64+bossFloat);			
			if(speed == 0) { 
				if(bossAttack == 0) { 
					ObjRender_SetAngleXYZ(bossObj,0,0,0);					
					if(bossf < 15) { ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
					if(bossf >= 15 && bossf < 30) { ObjSprite2D_SetSourceRect(bossObj,96,0,192,128); }
					if(bossf >= 30 && bossf < 45) { ObjSprite2D_SetSourceRect(bossObj,192,0,288,128); }
					if(bossf >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,0,384,128); }
					bossf2 = 0;
				} 	
				if(bossAttack == 1) {
					if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,256,96,384); }
					if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,256,192,384); }
					if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,256,288,384); }
					if(bossf2 >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,256,384,384); }	
				}					
			}
			else if(cos(dir) > 0) { 
				ObjRender_SetAngleXYZ(bossObj,0,0,0);
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }			
			}
			else if(cos(dir) < 0) { 
				ObjRender_SetAngleXYZ(bossObj,0,180,0);
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }					
			}	
			bossf+=1.5;
			bossf2+=2; 
			if(bossf > 60) { bossf = 0; } 		
		}			
		// Piere & Hina animation //-------------------------------------------------------------------------------------------------------------
		if(type == 1 || type == 10) {
			ObjSprite2D_SetDestRect(bossObj,-48,-64+bossFloat,48,64+bossFloat);			
			if(speed == 0) { 
				if(bossAttack == 0) { 
					ObjRender_SetAngleXYZ(bossObj,0,0,0);					
					if(bossf < 15) { ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
					if(bossf >= 15 && bossf < 30) { ObjSprite2D_SetSourceRect(bossObj,96,0,192,128); }
					if(bossf >= 30 && bossf < 45) { ObjSprite2D_SetSourceRect(bossObj,192,0,288,128); }
					if(bossf >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,0,384,128); }
				} 	
				if(bossAttack == 1) {
					ObjSprite2D_SetSourceRect(bossObj,0,380,96,512);
				}					
			}
			else if(cos(dir) > 0) { 
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45 && bossf2 < 60) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }			
				if(bossf2 >= 60 && bossf2 < 75) { ObjSprite2D_SetSourceRect(bossObj,0,256,96,384); }			
				if(bossf2 >= 75 && bossf2 < 90) { ObjSprite2D_SetSourceRect(bossObj,96,256,192,384); }			
				if(bossf2 >= 90 && bossf2 < 105) { ObjSprite2D_SetSourceRect(bossObj,192,256,288,384); }			
				if(bossf2 >= 105) { ObjSprite2D_SetSourceRect(bossObj,288,256,384,384); }			
			}
			else if(cos(dir) < 0) { 
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45 && bossf2 < 60) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }			
				if(bossf2 >= 60 && bossf2 < 75) { ObjSprite2D_SetSourceRect(bossObj,0,256,96,384); }			
				if(bossf2 >= 75 && bossf2 < 90) { ObjSprite2D_SetSourceRect(bossObj,96,256,192,384); }			
				if(bossf2 >= 90 && bossf2 < 105) { ObjSprite2D_SetSourceRect(bossObj,192,256,288,384); }			
				if(bossf2 >= 105) { ObjSprite2D_SetSourceRect(bossObj,288,256,384,384); }				
			}	
			bossf+=1.5;
			bossf2+=4; 
			if(bossf > 60) { bossf = 0; } 	
			if(bossf2 == 120) { bossf2 = 0; }
		}	
		// UFO animation //-------------------------------------------------------------------------------------------------------------
		if(type == 22) {
			ObjSprite2D_SetDestRect(bossObj,-64,-64+bossFloat,64,64+bossFloat);			
			ObjRender_SetAngleZ(bossObj,0+bossFloat*2);			
		}	
		// Tenji (2), DJ(3), Kogasa(23), Nue(24), Tewi(30), Reimu(31), Yukari(32), Marisa(33), Alice(34), 
		if(type == 2 || type == 3 || type == 23 || type == 24 || type == 30 || type == 31 || type == 32 || type == 33 || type == 34) {
			ObjSprite2D_SetDestRect(bossObj,-48,-64+bossFloat,48,64+bossFloat);			
			if(speed == 0) { 
				if(bossAttack == 0) { 
					ObjRender_SetAngleXYZ(bossObj,0,0,0);					
					if(bossf < 15) { ObjSprite2D_SetSourceRect(bossObj,0,0,96,128); }
					if(bossf >= 15 && bossf < 30) { ObjSprite2D_SetSourceRect(bossObj,96,0,192,128); }
					if(bossf >= 30 && bossf < 45) { ObjSprite2D_SetSourceRect(bossObj,192,0,288,128); }
					if(bossf >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,0,384,128); }
				}
				if(bossAttack == 1) {
					// Tenji prepare pose
					if(type == 2) { 
						ObjSprite2D_SetSourceRect(bossObj,0,128,96,256);
					}
					// All other 
					else {
						ObjSprite2D_SetSourceRect(bossObj,0,256,96,384);
					}
				}	
				if(bossAttack == 2) {
					// Tenji atk pose
					if(type == 2) { 
						ObjSprite2D_SetSourceRect(bossObj,0,256,96,384);
					}
					// All other 
					else {
						// None
					}
				}
				if(bossAttack == 3) {
					// Tenji right side point
					if(type == 2) { 
						ObjRender_SetAngleXYZ(bossObj,0,0,0);	
						ObjSprite2D_SetSourceRect(bossObj,288,128,384,256);
					}				
				}
				if(bossAttack == 4) {
					// Tenji left side point
					if(type == 2) { 
						ObjRender_SetAngleXYZ(bossObj,0,180,0);	
						ObjSprite2D_SetSourceRect(bossObj,288,128,384,256);
					}				
				}		
				bossf2 = 0;
			}
			else if(cos(dir) > 0) { 
				ObjRender_SetAngleXYZ(bossObj,0,0,0);	
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }			
			}
			else if(cos(dir) < 0) { 
				ObjRender_SetAngleXYZ(bossObj,0,180,0);	
				if(bossf2 < 15) { ObjSprite2D_SetSourceRect(bossObj,0,128,96,256); }
				if(bossf2 >= 15 && bossf2 < 30) { ObjSprite2D_SetSourceRect(bossObj,96,128,192,256); }
				if(bossf2 >= 30 && bossf2 < 45) { ObjSprite2D_SetSourceRect(bossObj,192,128,288,256); }
				if(bossf2 >= 45) { ObjSprite2D_SetSourceRect(bossObj,288,128,384,256); }					
			}	
			bossf += 1.5;
			bossf2 += 2;
			if(bossf > 60) { bossf = 0; } 
		}			
		// Boss anim floating
		bossFloat = 32 * sin(bossFloatF) / 8;
		bossFloatF += 2;

		// collision detection
		if(!ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_IS_DURABLE_SPELL)) {
			ObjEnemy_SetIntersectionCircleToShot(bossObj, bossX, bossY, 16);
			ObjEnemy_SetIntersectionCircleToPlayer(bossObj, bossX, bossY, 32);
		}
		else {
			// No collision if durable spell
		}
		yield;
	}
}

// Secondary boss rendering task. Draws the boss and handles the sprite animation. 
task renderBoss2(type) {
	let dir;
	let speed; 
	boss2Obj = ObjEnemy_Create(OBJ_ENEMY);
	ObjEnemy_Regist(boss2Obj);

	enemyMarker(boss2Obj, "partner");
	shareLifeHandler(bossObj, boss2Obj);
	ObjEnemy_SetDamageRate(boss2Obj, 100, 100);

	SetCommonData("boss2RenderType", type);
	
	if(type == 11) { ObjPrim_SetTexture(boss2Obj,imgMidBal); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 22) { ObjPrim_SetTexture(boss2Obj,imgMidAfro); ObjSprite2D_SetSourceRect(boss2Obj,0,0,128,128); ObjRender_SetScaleXYZ(boss2Obj,1,1,0); }
	if(type == 23) { ObjPrim_SetTexture(boss2Obj,imgMidNue); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 24) { ObjPrim_SetTexture(boss2Obj,imgMidKogasa); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 31) { ObjPrim_SetTexture(boss2Obj,imgMidReimu); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); ObjRender_SetScaleXYZ(boss2Obj,0.8,0.8,0); }
	if(type == 32) { ObjPrim_SetTexture(boss2Obj,imgMidYukari); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 33) { ObjPrim_SetTexture(boss2Obj,imgMidMarisa); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 34) { ObjPrim_SetTexture(boss2Obj,imgMidArisu); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	
	if(type == 1) { ObjPrim_SetTexture(boss2Obj,imgBossBal); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 2) { ObjPrim_SetTexture(boss2Obj,imgBossAfro); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 3) { ObjPrim_SetTexture(boss2Obj,imgBossDj); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); ObjRender_SetScaleXYZ(boss2Obj,0.8,0.8,0); }
	
	if(type == 10) { ObjPrim_SetTexture(boss2Obj,imgBossHina); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 20) { ObjPrim_SetTexture(boss2Obj,imgBossIku); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	if(type == 30) { ObjPrim_SetTexture(boss2Obj,imgBossTewi); ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
	
	Obj_SetRenderPriorityI(boss2Obj, 30);
	ObjSprite2D_SetDestCenter(boss2Obj); 
	
	// as long as the boss object is alive
	while(!Obj_IsDeleted(boss2Obj)) {

		// update info about the boss
		dir = ObjMove_GetAngle(boss2Obj);
		speed = ObjMove_GetSpeed(boss2Obj);
		boss2X = ObjMove_GetX(boss2Obj);
		boss2Y = ObjMove_GetY(boss2Obj);	

		// Antilope animation //-------------------------------------------------------------------------------------------------------------
		if(type == 11) {
			ObjSprite2D_SetDestRect(boss2Obj,-32,-56+boss2Float,32,56+boss2Float);			
			if(speed == 0) { 
				if(boss2Attack == 0) { 
					ObjRender_SetAngleXYZ(boss2Obj,0,0,0);					
					ObjSprite2D_SetSourceRect(boss2Obj,0,0,64,112); 
				} 	
				if(boss2Attack == 1) { ObjSprite2D_SetSourceRect(boss2Obj,0,112,64,224); } 		// attack pose
			}
			else if(cos(dir) > 0) { ObjSprite2D_SetSourceRect(boss2Obj,0,0,64,112); }
			else if(cos(dir) < 0) { ObjSprite2D_SetSourceRect(boss2Obj,0,0,64,112); ObjRender_SetAngleXYZ(boss2Obj,0,180,0); }			
		}			
		// Piere animation //-------------------------------------------------------------------------------------------------------------
		if(type == 1) {
			ObjSprite2D_SetDestRect(boss2Obj,-32,-56+boss2Float,32,56+boss2Float);			
			if(speed == 0) { 
				if(boss2Attack == 0) { 
					ObjRender_SetAngleXYZ(boss2Obj,0,0,0);					
					ObjSprite2D_SetSourceRect(boss2Obj,0,0,64,112); 
				} 	
				if(boss2Attack == 1) { ObjSprite2D_SetSourceRect(boss2Obj,0,336,64,448); } 		// attack pose
				if(boss2Attack == 9) { ObjSprite2D_SetSourceRect(boss2Obj,5,55,55,55); } 			// tornado mode	
			}
			else if(cos(dir) > 0) { ObjSprite2D_SetSourceRect(boss2Obj,0,112,64,224); if(boss2Attack == 9) { ObjSprite2D_SetSourceRect(boss2Obj,5,55,55,55); } }
			else if(cos(dir) < 0) { ObjSprite2D_SetSourceRect(boss2Obj,0,224,64,336); if(boss2Attack == 9) { ObjSprite2D_SetSourceRect(boss2Obj,5,55,55,55); } }			
		}		
		// Hina animation //-------------------------------------------------------------------------------------------------------------
		if(type == 10) {
			ObjRender_SetScaleXYZ(boss2Obj,0.7,0.7,0);
			ObjSprite2D_SetDestRect(boss2Obj,-48,-64+boss2Float,48,64+boss2Float);			
			if(speed == 0) { 
				if(boss2Attack == 0) { 
					if(boss2f < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
					if(boss2f >= 15 && boss2f < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,0,192,128); }
					if(boss2f >= 30 && boss2f < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,0,288,128); }
					if(boss2f >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,0,384,128); }
					boss2f2 = 0;
				} 	
				if(boss2Attack == 1) { 
					if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
					if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
					if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
					if(boss2f2 >= 45 && boss2f2 < 60) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }				
					if(boss2f2 >= 60 && boss2f2 < 75) { ObjSprite2D_SetSourceRect(boss2Obj,0,256,96,384); }			
					if(boss2f2 >= 75 && boss2f2 < 90) { ObjSprite2D_SetSourceRect(boss2Obj,96,256,192,384); }				
					if(boss2f2 >= 90 && boss2f2 < 105) { ObjSprite2D_SetSourceRect(boss2Obj,192,256,288,384); }				
					if(boss2f2 >= 105) { ObjSprite2D_SetSourceRect(boss2Obj,288,256,384,384); }									
				}
			}
			else if(cos(dir) > 0) { 
					if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
					if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
					if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
					if(boss2f2 >= 45 && boss2f2 < 60) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }				
					if(boss2f2 >= 60 && boss2f2 < 75) { ObjSprite2D_SetSourceRect(boss2Obj,0,256,96,384); }			
					if(boss2f2 >= 75 && boss2f2 < 90) { ObjSprite2D_SetSourceRect(boss2Obj,96,256,192,384); }				
					if(boss2f2 >= 90 && boss2f2 < 105) { ObjSprite2D_SetSourceRect(boss2Obj,192,256,288,384); }				
					if(boss2f2 >= 105) { ObjSprite2D_SetSourceRect(boss2Obj,288,256,384,384); }			
			}
			else if(cos(dir) < 0) { 
					if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
					if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
					if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
					if(boss2f2 >= 45 && boss2f2 < 60) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }				
					if(boss2f2 >= 60 && boss2f2 < 75) { ObjSprite2D_SetSourceRect(boss2Obj,0,256,96,384); }			
					if(boss2f2 >= 75 && boss2f2 < 90) { ObjSprite2D_SetSourceRect(boss2Obj,96,256,192,384); }				
					if(boss2f2 >= 90 && boss2f2 < 105) { ObjSprite2D_SetSourceRect(boss2Obj,192,256,288,384); }				
					if(boss2f2 >= 105) { ObjSprite2D_SetSourceRect(boss2Obj,288,256,384,384); }	
			}			
			boss2f += 1.5;
			boss2f2 += 2.5;
			if(boss2f > 60) { boss2f = 0; } 
			if(boss2f2 == 120) { boss2f2 = 0; }
		}		
		// UFO animation //-------------------------------------------------------------------------------------------------------------
		if(type == 22) {
			ObjSprite2D_SetDestRect(boss2Obj,-64,-64+boss2Float,64,64+boss2Float);			
			ObjRender_SetAngleZ(boss2Obj,0+boss2Float*2);			
		}	
		// Nue, Kogasa, Reimu, Yukari, Marisa, Alice, Iku, Tewi
		if(type == 20 || type == 23 || type == 24 || type == 30 || type == 31 || type == 33 || type == 34) {
			ObjRender_SetScaleXYZ(boss2Obj,1,1,0);
			ObjSprite2D_SetDestRect(boss2Obj,-48,-64+boss2Float,48,64+boss2Float);			
			if(speed == 0) { 
				if(boss2Attack == 0) { 
					ObjRender_SetAngleXYZ(boss2Obj,0,0,0);					
					if(boss2f < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
					if(boss2f >= 15 && boss2f < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,0,192,128); }
					if(boss2f >= 30 && boss2f < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,0,288,128); }
					if(boss2f >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,0,384,128); }
					boss2f2 = 0;
				} 	
				if(boss2Attack == 1) {
					ObjSprite2D_SetSourceRect(boss2Obj,0,256,96,384);
				}				
				if(boss2Attack == 2) {
					if(type == 20 || type == 21) { 
						ObjSprite2D_SetSourceRect(boss2Obj,0,384,96,512);
					}
				}
			}
			else if(cos(dir) > 0) { 
				ObjRender_SetAngleXYZ(boss2Obj,0,0,0);	
				if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
				if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
				if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
				if(boss2f2 >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }			
			}
			else if(cos(dir) < 0) { 
				ObjRender_SetAngleXYZ(boss2Obj,0,180,0);	
				if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
				if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
				if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
				if(boss2f2 >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }					
			}	
			boss2f += 1.5;
			boss2f2 += 2;
			if(boss2f > 60) { boss2f = 0; } 
		}	
		// Yukari animation //-------------------------------------------------------------------------------------------------------------
		if(type == 32) {
			ObjRender_SetScaleXYZ(boss2Obj,0.8,0.8,0);
			ObjSprite2D_SetDestRect(boss2Obj,-48,-64+boss2Float,48,64+boss2Float);			
			if(speed == 0) { 
				if(boss2Attack == 0) {
					ObjRender_SetAngleXYZ(boss2Obj,0,0,0);					
					if(boss2f < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,0,96,128); }
					if(boss2f >= 15 && boss2f < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,0,192,128); }
					if(boss2f >= 30 && boss2f < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,0,288,128); }
					if(boss2f >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,0,384,128); }
					boss2f2 = 0;
				} 	
				if(boss2Attack == 1) {
					ObjSprite2D_SetSourceRect(boss2Obj,0,384,96,512);
				}
			}
			else if(cos(dir) > 0) { 
				ObjRender_SetAngleXYZ(boss2Obj,0,0,0);
				if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
				if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
				if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
				if(boss2f2 >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }		
			}
			else if(cos(dir) < 0) { 
				ObjRender_SetAngleXYZ(boss2Obj,0,180,0);
				if(boss2f2 < 15) { ObjSprite2D_SetSourceRect(boss2Obj,0,128,96,256); }
				if(boss2f2 >= 15 && boss2f2 < 30) { ObjSprite2D_SetSourceRect(boss2Obj,96,128,192,256); }
				if(boss2f2 >= 30 && boss2f2 < 45) { ObjSprite2D_SetSourceRect(boss2Obj,192,128,288,256); }
				if(boss2f2 >= 45) { ObjSprite2D_SetSourceRect(boss2Obj,288,128,384,256); }				
			}	
			boss2f += 1.5;
			boss2f2 += 2;
			if(boss2f > 60) { boss2f = 0; } 
			if(boss2f2 > 60) { boss2f2 = 0; } 
		}		
		boss2Float = 32 * sin(boss2FloatF) / 8;
		boss2FloatF += 2;
		
		// collision detection
		if(!ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID,INFO_IS_DURABLE_SPELL)) { 
			ObjEnemy_SetIntersectionCircleToShot(boss2Obj,boss2X,boss2Y,16);
			ObjEnemy_SetIntersectionCircleToPlayer(boss2Obj,boss2X,boss2Y,32);
		}
		else {
			// No collision if durable spell
		}

		yield;
	}
}

// Enemy or boss invul mode (since 0.12m doesn't have one)
task setInvulnerableTime(obj,t) {
	let lockShotDmgRate = ObjEnemy_GetInfo(obj, INFO_DAMAGE_RATE_SHOT);
	let lockSpellDmgRate = ObjEnemy_GetInfo(obj, INFO_DAMAGE_RATE_SPELL);

	ObjEnemy_SetDamageRate(obj,0,0);
	loop(t) { yield; }
	ObjEnemy_SetDamageRate(obj, lockShotDmgRate, lockSpellDmgRate);
}

// Test damage for dual partners obj = main boss obj2 = partner.
task shareLifeHandler(obj,obj2) {
	// get the HP of the main and store it in var
	mainBossHP = ObjEnemy_GetInfo(bossObj, INFO_LIFE);

	// Set the HP for the partner.
	ObjEnemy_SetLife(obj2, mainBossHP);
	
	while(!Obj_IsDeleted(bossObj)) {	
		// Only update the HP of the boss if it actually gets hit. This is to prevent the HP from snapping to the main value.
		if(ObjEnemy_GetInfo(obj2,INFO_SHOT_HIT_COUNT) > 0) {
		    ObjEnemy_SetLife(bossObj, ObjEnemy_GetInfo(obj2, INFO_LIFE));
        }

		// update the HP of the partner continously from the main (shared HP)
		ObjEnemy_SetLife(obj2, ObjEnemy_GetInfo(bossObj, INFO_LIFE));
		yield;
	}
}

// Spawns an sprite to act as enemy marker. Drawn on top of HUD. 
task enemyMarker(mainObj, type) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	
	if(type == "main") { ObjPrim_SetTexture(obj, enyMark); }
	if(type == "partner") { ObjPrim_SetTexture(obj, enyMark2); }
	
	ObjRender_SetBlendType(obj, BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj, 155);
	Obj_SetRenderPriorityI(obj, 90);
	ObjRender_SetPosition(obj, GetCenterX, GetClipMaxY+24, 0);
	ObjRender_SetScaleXYZ(obj, 1, 1, 0);
	ObjSprite2D_SetSourceRect(obj, 0, 0, 64, 16);
	ObjSprite2D_SetDestCenter(obj);	

	while(!Obj_IsDeleted(obj)) {
		if(!Obj_IsDeleted(mainObj)) {
		    ObjRender_SetPosition(obj, ObjMove_GetX(mainObj)+32, GetClipMaxY+26, 0);

            if(GetPlayerX > ObjMove_GetX(mainObj)-24 && GetPlayerX < ObjMove_GetX(mainObj)+24) {
                ObjRender_SetAlpha(obj,105);
            } else {
                ObjRender_SetAlpha(obj,205);
            }
        } else {
            ObjRender_SetAlpha(obj,0);
        }

		yield;
	}
	Obj_Delete(obj); 
}

//***************************************************************************************************
//	Break Effect
// 	The famous break effect code which I am proud of. Mainly used for the explosive 
//  effect when the spell card breaks. I expanded it with extra parameters for more flexibility.
//	
//	breakEffect uses simply 3 parameters for setting RGB. 
//	
//	breakEffectGlitter has more because it is the actual glitter code. 
//	Parameters:
// 				x,y 	= location
//				v 		= velocity 
//				dir 	= angle
//				parts 	= scale size
//				alphaValue = opacity
// 				r g b	= RGB value for setting glitter colours
// 	Fever ze!
//***************************************************************************************************

//	Spawns a circular pattern of randomized particles in speed and size. Allows RGB setting.
task breakEffect(red,green,blue) {
	let dir = 0;
	loop(18){ 
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18){ 
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18){ 
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18){ 
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
}

// break effect glitter 
task breakEffectGlitter(x,y,v,dir,parts,alphaValue,red,green,blue) {

	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;
	let partSizeScale = parts;
	
	ObjPrim_SetTexture(obj,circglit);
	ObjRender_SetBlendType(obj,BLEND_ADD_RGB);
	Obj_SetRenderPriorityI(obj,30);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);

	ObjMove_Special(obj,x,y,v,dir);
	
	while(! Obj_IsDeleted(obj)) {
		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);

		// glittering effect
		parts = rand(partSizeScale,partSizeScale+0.5)*sin(partc*round(rand(10,20)));
		partc++;

		// remove timer
		if(partc > round(rand(90,180))){ Obj_Delete(obj); }
		
		yield;
	}
}

//***************************************************************************************************************************
//  Concentration effect.
//	Basically it spawns the sprites in a circle with random radius from the boss.
//	The main function is concenEffect. concenEffectHandler and concenAngleHandler are for control.
//	Parameters:
//		t = time in frames. The more, the more particles are spawned over time.
//		type = type of sprite. There are 5 types for now: 
//															1 - Regular light balls 
//															2 - Ballerina feathers 
//															3 - Glittering lights (similar to breakeffect)
//															4 - Funky stars
//															5 - Gunshell ammo 
//															
//		red green blue = alternative colouring if desired. 
//***************************************************************************************************************************

// Main function to call from the script. 
task concenEffect(obj,t,type,red,green,blue) {
	let dir = 0;
	loop(t/4) { 
		ascent(i in 0..2) {  
			dir += rand_int(0,360);
			if(type == 1) { concenEffectHandler(obj,ObjMove_GetX(obj)+rand_int(120,200)*cos(dir),ObjMove_GetY(obj)+rand_int(120,200)*sin(dir),dir,type,red,green,blue); wait(1); }
			if(type == 2) { concenEffectHandler(obj,ObjMove_GetX(obj)+rand_int(120,200)*cos(dir),ObjMove_GetY(obj)+rand_int(120,200)*sin(dir),dir,type,red,green,blue); wait(1); }
			if(type == 3) { concenEffectHandler(obj,ObjMove_GetX(obj)+rand_int(240,300)*cos(dir),ObjMove_GetY(obj)+rand_int(220,300)*sin(dir),dir,type,red,green,blue); wait(4); }
			if(type == 4) { concenEffectHandler(obj,ObjMove_GetX(obj)+rand_int(240,300)*cos(dir),ObjMove_GetY(obj)+rand_int(220,300)*sin(dir),dir,type,red,green,blue); wait(6); }
			if(type == 5) { concenEffectHandler(obj,ObjMove_GetX(obj)+rand_int(240,300)*cos(dir),ObjMove_GetY(obj)+rand_int(220,300)*sin(dir),dir,type,red,green,blue); wait(6); }
		}
		yield;
	}
}

// Main task to control the sprite being spawned. Each sprite is unique and behaves such.
task concenEffectHandler(objfollow,x,y,dir,type,red,green,blue) {

	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;
	let parts = 0;
	let partspin = 0;
	let alphaValue = 55;
	let spindir = rand(1,2);
	let v = 0;
	
	if(type == 1) { ObjPrim_SetTexture(obj,circglit); v = 4; parts = rand(1.4,2.2); }
	if(type == 2) { ObjPrim_SetTexture(obj,veertje); v = 5; parts = rand(1.4,2.2); }
	if(type == 3) { ObjPrim_SetTexture(obj,circglit); v = rand_int(5.0,7.0); parts = rand(2.4,3.8); }
	if(type == 4) { ObjPrim_SetTexture(obj,sterretje); v = rand_int(4.0,7.0); parts = rand(1.2,2.0); }
	if(type == 5) { ObjPrim_SetTexture(obj,kogeltje); v = rand_int(8.0,10.0); parts = rand(1.4,2.0); }
	
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj,alphaValue);
	Obj_SetRenderPriorityI(obj,40);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetAngle(obj,0);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);

	// Handle the travel of the sprite from the spawnlocation to the centre of the boss. 
	concenAngleHandler(objfollow,obj,x,y,v,dir);

	while(!Obj_IsDeleted(objfollow)) {
		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetAngleZ(obj,partspin);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);

		// regular glitter anim
		if(type == 1) { 
			if(alphaValue < 255) { alphaValue+=10; } 
			parts += ((125*sin(partc)/300) - 0.04); 
			partc+=50; 
			if(parts <= 0.4) { Obj_Delete(obj); } 
		}
		// feather anim
		if(type == 2) { 
			if(alphaValue < 255) { alphaValue+=20; } 
			if(spindir >= 1 && spindir <= 1.5) { partspin+=5; }
			if(spindir < 2 && spindir > 1.5) { partspin-=5; }
			parts -= 0.04; 
			if(parts <= 0.5) { Obj_Delete(obj); } 
		}
		// tripping glitter anim
		if(type == 3) { 
			ObjRender_SetAngleXYZ(obj,partc,partc,partc);
			if(alphaValue < 255) { alphaValue+=25; } 
			parts += ((125*sin(partc)/300) - 0.06); 
			partc+=50; 
			if(parts <= 0.4) { Obj_Delete(obj); } 
		}
		// star anim
		if(type == 4) { 	
			if(alphaValue < 250) { alphaValue+=25; } 
			if(spindir >= 1 && spindir <= 1.5) { partspin+=5; }
			if(spindir < 2 && spindir > 1.5) { partspin-=5; }
			parts += ((125*sin(partc)/550) - 0.15); 			
			partc+=3; 
			if(parts <= 0.2) { Obj_Delete(obj); } 
		}	
		// kogel anim
		if(type == 5) { 
			if(alphaValue < 255) { alphaValue+=20; } 
			if(spindir >= 1 && spindir <= 1.5) { partspin+=1; }
			if(spindir < 2 && spindir > 1.5) { partspin-=1; }
			parts -= 0.02; 
			if(parts <= 0.5) { Obj_Delete(obj); } 
		}		
		yield;
	}
	Obj_Delete(obj);
}

// Angle handler since ObjMove doesnt respond to sprites. Requires Render_SetPosition for this reason.
task concenAngleHandler(objfollow,obj,x,y,v,dir) {
	let vx = v * cos(dir);
	let vy = v * sin(dir);

	while(! Obj_IsDeleted(obj)) {
		ObjMove_SetPosition(obj,x,y);
		ObjRender_SetPosition(obj,x,y,0);
		dir = atan2(ObjRender_GetY(objfollow) - y, ObjRender_GetX(objfollow) - x);
		vx = v * cos(dir);
		vy = v * sin(dir);

		yield;
		x += vx;
		y += vy;
	}
	Obj_Delete(obj);
}


//***************************************************************************************************************************
//	Colormixer
//  Randomizes rapidly R G B values for disco effect. 
//	Parameters:
//				obj 	= obj
//				alphaValue = alpha setting
//				r g b 	= red green blue take in values
//***************************************************************************************************************************

// Randomizer task to mix colours.
task colorMixer(obj,alphaValue,red,green,blue) {
	let maxr = red;
	let maxg = green;
	let maxb = blue;
	let mixr = 0; let mixg = 0; let mixb = 0;
	while(!Obj_IsDeleted(obj)) {

		mixr = rand_int(0,maxr); mixg = rand_int(0,maxg); mixb = rand_int(0,maxb);
		ObjRender_SetColor(obj,mixr,mixg,mixb); 		
		//if((red == 255) && (green == 255) && (blue == 255)) { red = 16; green = 255; blue = 255; }
		wait(3);
	}
}


//***************************************************************************************************************************
//	Explosion Effect
//  Ability to use explosion effect such as in 0.12m (explosion01). Partially converted from mkm's default effects.
//	Parameters:
//				x,y 	= location
//				dAlpha	= degen of alpha
//				dScale	= growth of scale
//***************************************************************************************************************************

task exploEffect(x,y,alphaValue,dscale) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj,exploTex);
	Obj_SetRenderPriority(obj,0.65);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	//ObjRender_SetAlpha(obj,255);
	ObjSprite2D_SetSourceRect(obj,1,1,63,63);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetPosition(obj,x,y,0);

	let scale = 0;
	let alpha = 255;
	
	while(alpha > 0) {
		ObjRender_SetColor(obj,alpha,alpha,alpha);
		ObjRender_SetScaleXYZ(obj,scale,scale,1);

		scale += dscale;
		alpha -= alphaValue;
		yield;
	}
	Obj_Delete(obj);
}

//***************************************************************************************************************************
//	Enemy Explosion Effect
//  Shot down fairies, familiars create a small fancy explosion. Uses breakEffectGlitter similar code.
//	Parameters:
//				obj = retrieves ID from enemy
//				type = listens to type of enemy (ie: BAL/AFRO & RED,BLUE)
//***************************************************************************************************************************

// Summons circular pattern, however randomized, of glitters and special particles depending on the parent object
// Example: If this is a blue ballerina fairy, it will spawn blue glitters and white feathers. 
//			If this is a red afro fairy, it will spawn red glitters and coloured stars.
// 			type is a parameter retrieved from the fairy object which listens to the enum of type (ie: BAL_RED)
task enyExplodeEffect(obj,type) {
	let dir = 0;
	let colourRed = 0;
	let colourGreen = 0;
	let colourBlue = 0; 
	
	// Listen which type of enemy was shot down and set colour for the glitter
	if(type == 0 || type == 2) { colourRed = 255; colourGreen = 64; colourBlue = 64; } 
	if(type == 1 || type == 4) { colourRed = 64; colourGreen = 64; colourBlue = 255; } 
	if(type == 6) { colourRed = 255; colourGreen = 64; colourBlue = 64; } 
	if(type == 7) { colourRed = 64; colourGreen = 64; colourBlue = 255; } 
	if(type > 8) { colourRed = 255; colourGreen = 64; colourBlue = 255; } 
	
	// Spawns circular pattern of glitters. Colour is according type of enemy which was shot down
	ascent(i in 0..8) { 
		//x,y,v,dir,parts,alphaValue,red,green,blue
		enyExplodeGlitterParticle(ObjMove_GetX(obj),ObjMove_GetY(obj),rand_int(1,3),dir,2,155,colourRed,colourGreen,colourBlue);
		dir+=360/8; 
	}
	
	// Spawn special particle depending on type of enemy which was shot down
	ascent(i in 0..6) { 
		enyExplodeTypeParticle(ObjMove_GetX(obj),ObjMove_GetY(obj),type);
		dir+=32.34; 
	}	
} 

task famExplodeEffect(obj,type) {
	let dir = 0;
	let colourRed = 0;
	let colourGreen = 0;
	let colourBlue = 0; 
	
	// Listen which type of enemy was shot down and set colour for the glitter
	if(type == 0) { colourRed = 255; colourGreen = 64; colourBlue = 64; } 
	if(type == 1) { colourRed = 64; colourGreen = 255; colourBlue = 64; } 
	if(type == 2) { colourRed = 64; colourGreen = 64; colourBlue = 255; } 
	if(type == 3) { colourRed = 255; colourGreen = 64; colourBlue = 255; } 
	if(type == 4) { colourRed = 255; colourGreen = 255; colourBlue = 64; }
	if(type == 5) { colourRed = 255; colourGreen = 255; colourBlue = 255; }	
	
	
	// Spawns circular pattern of glitters. Colour is according type of enemy which was shot down
	ascent(i in 0..8) { 
		//x,y,v,dir,parts,alphaValue,red,green,blue
		enyExplodeGlitterParticle(ObjMove_GetX(obj),ObjMove_GetY(obj),rand_int(1,3),dir,2,155,colourRed,colourGreen,colourBlue);
		dir+=360/8; 
	}	
} 

// Particle code for the glitters. I could use breakEffect, but small adjustments in the code made it iffy so I copy-paste it with some changes.
task enyExplodeGlitterParticle(x,y,v,dir,parts,alphaValue,red,green,blue) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;

	ObjPrim_SetTexture(obj,circglit);
	ObjRender_SetBlendType(obj,BLEND_ADD_RGB);
	Obj_SetRenderPriorityI(obj,30);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);

	ObjMove_Special(obj,x,y,v,dir);
	
	while(! Obj_IsDeleted(obj)) {
		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);

		// glittering effect
		parts = rand(2,2.5)*sin(partc*round(rand(10,20)));
		partc++;

		// remove timer
		if(partc > round(rand_int(30,90))) { Obj_Delete(obj); break; }
		
		yield;
	}
}

// Enemy explosion in different types for stage effect
task enyExplodeTypeParticle(x,y,type) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let c = 0;
	let v = rand(1.5,2.5);
	let dir = rand_int(0,359);
	let parts = 0.6;
	let spinny = rand_int(-4,4);
	let randomspinny = rand(1,2);
	
	// red, green, blue, cyan, purple, yellow, orange
	let colSet = [[255, 16, 16],[16,255,16],[16,16,255],[16,255,255],[255,16,255],[255,255,16],[255,128,16]]; 
	let colKies = 0;	
	
	// depending on type, set colour and texture
	if(type == 0 || type == 1) { ObjRender_SetColor(obj,255,255,255); ObjPrim_SetTexture(obj,veertje); }
	if(type == 2 || type == 3 || type == 4 || type == 5) { 
		colKies = rand_int(0,7);
		ObjRender_SetColor(obj,colSet[colKies][0],colSet[colKies][1],colSet[colKies][2]); 
		ObjPrim_SetTexture(obj,sterretje); 
	}
	if(type == 6) { ObjRender_SetColor(obj,255,64,64); ObjPrim_SetTexture(obj,sterretje); }
	if(type == 7) { ObjRender_SetColor(obj,64,64,255); ObjPrim_SetTexture(obj,sterretje); }
	if(type >= 8) { ObjRender_SetColor(obj,255,64,255); ObjPrim_SetTexture(obj,sterretje); }
	
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj,30);
	ObjRender_SetPosition(obj,x,y,0);
	ObjRender_SetAlpha(obj,155);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);	

	ObjMove_Special(obj,x,y,v,dir);
	
	while(!Obj_IsDeleted(obj)) {
		ObjRender_SetScaleXYZ(obj,parts,parts,0);
		ObjRender_SetAngleZ(obj,spinny);

		parts -= 0.01; 
		if(parts <= 0.1) { Obj_Delete(obj); break; } 
			
		if(randomspinny == 1 && randomspinny <= 1.5) { spinny+=4; }
		if(randomspinny > 1.5 && randomspinny < 2.0) { spinny-=4; }
		yield;
	}
}

// Fairy / enemy / etc summon effect
task enySummonEffect(x,y,dAlpha,dScale,type) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let scale = 0.5;
	let spin = 0;
	let alphaValue = 155;
	let dir = 0;
	let red = 0;
	let green = 0;
	let blue = 0;
	
	if(type == 0) { red = 255; green = 64; blue = 64; }
	if(type == 1) { red = 64; green = 255; blue = 64; }
	if(type == 2) { red = 64; green = 64; blue = 255; }
	if(type == 3) { red = 255; green = 64; blue = 255; }
	
	ObjPrim_SetTexture(obj,summonEffTex);
	Obj_SetRenderPriority(obj,0.65);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	ObjSprite2D_SetSourceRect(obj,1,1,127,127);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetColor(obj,red,green,blue);
	ObjRender_SetPosition(obj,x,y,0);

	loop(5) { 
		concenEffectHandler(obj,ObjRender_GetX(obj)+128*cos(dir),ObjRender_GetY(obj)+128*sin(dir),dir,1,red,green,blue); 
		dir+=360/5; 
	}
	
	while(scale > 0) {
		ObjRender_SetScaleXYZ(obj,scale,scale,1);
		ObjRender_SetAngleZ(obj,spin);
		spin+=5;

		scale -= dScale;
		alphaValue -= dAlpha;
		
		yield;
	}
	Obj_Delete(obj);
}

// Draws the fade in/out wait screen between transitions. 
task showCollectLine {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let scrAlpha = 0;
	
	ObjPrim_SetTexture(obj,collectLine);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,scrAlpha);
	Obj_SetRenderPriorityI(obj,50);
	ObjSprite2D_SetSourceRect(obj,0,0,1024,16);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetPosition(obj,GetCenterX,120,0);
	
	loop(30) { ObjRender_SetAlpha(obj,scrAlpha); scrAlpha+=205/30; yield; }
	loop(90) { yield; } 
	loop(15) { ObjRender_SetAlpha(obj,scrAlpha); scrAlpha-=205/15; yield; }
	
	Obj_Delete(obj);
}

// Draws the fade in/out wait screen between transitions. 
task fadeWaitScreen {
	SetForbidPlayerShot(true);
	SetForbidPlayerSpell(true);
	
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let scrAlpha = 0;
	let scrScroll = 0;
	ObjPrim_SetTexture(obj,imgWaitScr);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,scrAlpha);
	Obj_SetRenderPriorityI(obj,100);
	ObjSprite2D_SetSourceRect(obj,0,0,1024,1024);
	ObjSprite2D_SetDestRect(obj,0,0,1024,1024);
	
	loop(15) { ObjSprite2D_SetSourceRect(obj,0+scrScroll,0+scrScroll,1024+scrScroll,1024+scrScroll); scrScroll--; ObjRender_SetAlpha(obj,scrAlpha); scrAlpha+=255/15; yield; }
	loop(120) { ObjSprite2D_SetSourceRect(obj,0+scrScroll,0+scrScroll,1024+scrScroll,1024+scrScroll); scrScroll--; yield; } 
	loop(15) { ObjSprite2D_SetSourceRect(obj,0+scrScroll,0+scrScroll,1024+scrScroll,1024+scrScroll); scrScroll--; ObjRender_SetAlpha(obj,scrAlpha); scrAlpha-=255/15; yield; }
	
	SetForbidPlayerShot(false);
	SetForbidPlayerSpell(false);	
	
	Obj_Delete(obj);
}

// Draws the fade in/out ending screen.
task fadeEndScreen {
	SetForbidPlayerShot(true);
	SetForbidPlayerSpell(true);
	
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let scrAlpha = 0;
	
	ObjPrim_SetTexture(obj,minitex);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,scrAlpha);
	Obj_SetRenderPriorityI(obj,100);
	ObjSprite2D_SetSourceRect(obj,0,0,640,480);
	ObjSprite2D_SetDestRect(obj,0,0,640,480);
	
	loop(30) { ObjRender_SetAlpha(obj,scrAlpha); scrAlpha+=255/30; yield; }
	loop(180) { yield; } 
	loop(30) { ObjRender_SetAlpha(obj,scrAlpha); scrAlpha-=255/30; yield; }
	
	SetForbidPlayerShot(false);
	SetForbidPlayerSpell(false);	
	
	Obj_Delete(obj);
}