#TouhouDanmakufu[Single]
#ScriptVersion[3]
#Title["Dj spell 06 normal"]
#Text["Dj spell 06 normal"]

let objLaserMach = ObjEnemy_Create(OBJ_ENEMY); 
let famX = 0;
let famY = 0;
let laserTrackID = [];

let laserTex = "script/thdcs/system/enm03/laserfam.png";
let famTex = "script/thdcs/system/effects/fammer.png";
let smokeTex = "script/thdcs/system/effects/smoke.png";
let warnTex = "script/thdcs/system/effects/warninglaser.png";

// debug
let l1 = ObjText_Create;
let l2 = ObjText_Create;
let l3 = ObjText_Create;
let l4 = ObjText_Create;
let l5 = ObjText_Create;
	
#include "script/thdcs/system/shotlibrary.txt"
#include "script/thdcs/functions/function_common.txt"
#include "script/thdcs/functions/function_global.txt"
#include "script/thdcs/functions/function_bosseff.txt"

@Initialize {
	SetCommonData("spellScriptID",GetOwnScriptID);
	renderBoss(3);
	setAura(bossObj,64,255,128);
	SetCommonData("bossCircleType",3);
	SetCommonData("bossAttackType",2);
	SetCommonData("bossBgType",3);
	if(GetAreaCommonData("system","gameLang",0) == 0) { SetCommonData("cardName","ւƖ_@u[U@Bv"); } 
	if(GetAreaCommonData("system","gameLang",0) == 1) { SetCommonData("cardName","Pride and Honour uLaser Machinev"); } 		
	setInvulnerableTime(bossObj,360);
	
	ObjMove_SetDestAtSpeed(bossObj,GetCenterX,120,5);
	SetShotAutoDeleteClip(64,64,64,64);
	SetAutoDeleteObject(true);
	mainTask;
	
	ObjRender_SetPosition(l1,55,80,0);
	ObjRender_SetPosition(l2,55,100,0);
	ObjRender_SetPosition(l3,55,120,0);
	ObjRender_SetPosition(l4,55,140,0);
	ObjRender_SetPosition(l5,55,160,0);
} 

@Event { 
	alternative(GetEventType()) 
	case(EV_REQUEST_LIFE) { 
		SetScriptResult(440);
	}
	case(EV_REQUEST_TIMER) { 
		SetScriptResult(90);
	}
	case(EV_REQUEST_SPELL_SCORE) {
	    let spellCardBonus = calculateAndGetSpellCardBonus();
		SetScriptResult(spellCardBonus);
	}	
	case(EV_USER+9999) {
		SetCommonData("spellcardID","dj06norm"); 
	}
} 

@MainLoop { famX = ObjMove_GetX(objLaserMach); famY = ObjMove_GetY(objLaserMach); yield; } 
@Finalize { } 

task mainTask { 
	yield;
	scriptEnding;
	wait(60);
	effectDJ;
	laserFam(bossX-25,bossY);
	wait(120);
	//smokeFam(bossX,bossY,0);
	//smokeFam(bossX,bossY,1);	
	vuur;
	wait(160);
	vuur2;
} 

// Shows the warning sign
task warningSign {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj,warnTex);
	Obj_SetRenderPriorityI(obj,50);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,0);
	ObjSprite2D_SetSourceRect(obj,0,0,256,256);
	ObjRender_SetScaleXYZ(obj,0.7,0.7,0);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetPosition(obj,GetCenterX,GetCenterY+64,0);
	PlaySFX(SFX_ALERT);
	wait(15);
	ObjRender_SetAlpha(obj,205);
	wait(15);
	ObjRender_SetAlpha(obj,0);
	wait(15);
	ObjRender_SetAlpha(obj,205);
	wait(15);
	ObjRender_SetAlpha(obj,0);
	wait(15);
	ObjRender_SetAlpha(obj,205);
	wait(15);
	ObjRender_SetAlpha(obj,0);
	Obj_Delete(obj);
}

// Effy 1
task effectDJ {
	let dir = 0;
	let r = 70;
	while(!Obj_IsDeleted(bossObj)) { 
		ascent(i in 0..12) { 
			let effyShot = CreateShotA(GetEnemyX+r*cos(dir),GetEnemyY+r*sin(dir),15);
			SetShotDataA(effyShot,0,0,0,0,0,0,151);
			DeleteShotA(effyShot,0);
			
			let effyShot2 = CreateShotA(GetEnemyX+r*cos(dir+120),GetEnemyY+r*sin(dir+120),15);
			SetShotDataA(effyShot2,0,0,0,0,0,0,150);
			DeleteShotA(effyShot2,0);	
			
			let effyShot3 = CreateShotA(GetEnemyX+r*cos(dir+240),GetEnemyY+r*sin(dir+240),15);
			SetShotDataA(effyShot3,0,0,0,0,0,0,152);
			DeleteShotA(effyShot3,0);	
			
			let effyShot4 = CreateShotA(GetEnemyX+r*cos(-dir),GetEnemyY+r*sin(-dir),10);
			SetShotDataA(effyShot4,0,0,0,0,0,0,155);
			DeleteShotA(effyShot4,0);
			
			let effyShot5 = CreateShotA(GetEnemyX+r*cos(-dir+120),GetEnemyY+r*sin(dir+120),10);
			SetShotDataA(effyShot5,0,0,0,0,0,0,155);
			DeleteShotA(effyShot5,0);	
			
			let effyShot6 = CreateShotA(GetEnemyX+r*cos(-dir+240),GetEnemyY+r*sin(dir+240),10);
			SetShotDataA(effyShot6,0,0,0,0,0,0,155);
			DeleteShotA(effyShot6,0);					
			dir+=6;
			wait(1);
		}
		yield;
	}
}

// Lasers shot by the laser machine
task vuur { 
	let dir = 90; 
	ascent(i in 0..5) { 
		machineLaser(famX+10,famY+5,0,dir,512,24,241,90,300);
		dir+=360/5;
	}
	wait(60);
	ascent(i in 0..5) { 
		CreateLooseLaserA1(famX+10,famY+5,15,dir,600,24,6,0);	
		dir+=360/5;
	}
	concenEffect(objLaserMach,60,3,64,255,128);	
	PlaySFX(SFX_LAZER02);	
}

// Bubbles being fired from DJ
task vuur2 {
	let dir = 0;
	while(!Obj_IsDeleted(bossObj)) {
		ascent(i in 0..12) {
			CreateShotA1(bossX,bossY,1,dir,rand_int(229,237),15);
			dir+=360/12;
		}
		PlaySFX(SFX_TAN00);	
		wait(120);
		dir = rand_int(0,359);
	}
}

// Laser
task machineLaser(x,y,v,dir,mlen,width,graphic,delay,lifetime) {

	let obj = ObjShot_Create(OBJ_STRAIGHT_LASER);
	let f = 0;
	let dir2 = 0;
	let c = 0;
	let r = 0;
	
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj,x,y);
	Obj_SetRenderPriorityI(obj,60);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjStLaser_SetAngle(obj,dir);
	ObjShot_SetGraphic(obj,graphic);
	ObjShot_SetDelay(obj,delay);
	ObjLaser_SetRenderWidth(obj,width);
	ObjLaser_SetIntersectionWidth(obj,width-10);
	ObjLaser_SetLength(obj,mlen);
	ObjLaser_SetInvalidLength(obj,0,0);
	
	// add laser to the array for tracking
	laserTrackID = laserTrackID ~ [obj];
	warningSign;
	wait(160);

	while(!Obj_IsDeleted(obj)) {
		ObjMove_SetPosition(obj,famX+10+r*cos(dir),famY+5+r*sin(dir));		
		ObjStLaser_SetAngle(obj,dir);
		dir+=0.2;
		yield;
	}
}

// Function to delete the objLaser to prevent unwanted collision detection which drops fps.
function removeLaserID(obj) {
	descent(i in 0..length(laserTrackID)) {
		if(obj == laserTrackID[i]) { 
			laserTrackID = erase(laserTrackID,i);
		}		
	}
}

// laser fam
task laserFam(x,y) {

	let dir = 0;
	let r = 0;
	let r2 = 0;
	let scale = 0.3;
	let laserFrame = 0;
	let laserPos = 0;
	
	ObjEnemy_Regist(objLaserMach);
	ObjPrim_SetTexture(objLaserMach,laserTex);
	Obj_SetRenderPriorityI(objLaserMach, 30);
	ObjRender_SetScaleXYZ(objLaserMach,scale,scale,0);	
	ObjSprite2D_SetSourceRect(objLaserMach,0,0,256,128);
	ObjSprite2D_SetDestRect(objLaserMach,-128,-64,128,64);
	ObjEnemy_SetLife(objLaserMach,9999);
	ObjMove_SetPosition(objLaserMach,x,y);	
	
	shareLifeHandler(bossObj,objLaserMach);
	ouch3SFX(objLaserMach); 
	
	exploEffect(GetEnemyX-25,GetEnemyY,1.9,3);
	PlaySFX(SFX_BOON01);	
	PlaySFX(SFX_BZZ0);	
	PlaySFX(SFX_CAT00);	
	concenEffect(objLaserMach,240,1,64,64,255);
	concenEffect(objLaserMach,80,3,64,255,64);	
	PlaySFX(SFX_BOON01);	
	PlaySFX(SFX_CH00);	
	concenEffect(objLaserMach,30,3,255,64,64);	
	concenEffect(objLaserMach,15,4,64,255,128);	
	concenEffect(objLaserMach,60,1,64,64,255);		
	ObjMove_SetDestAtSpeed(objLaserMach,GetCenterX,40,2);
	ObjMove_SetDestAtSpeed(bossObj,GetCenterX,GetCenterY-64,2);
	r = 135;
	r2 = 170;
	dir = 270;
	wait(380);
	while(!Obj_IsDeleted(objLaserMach)) {
		ObjEnemy_SetIntersectionCircleToShot(objLaserMach,ObjMove_GetX(objLaserMach),ObjMove_GetY(objLaserMach),16);
		ObjEnemy_SetIntersectionCircleToPlayer(objLaserMach,ObjMove_GetX(objLaserMach),ObjMove_GetY(objLaserMach),16);
		
		if(ObjEnemy_GetInfo(objLaserMach, INFO_LIFE) <= 0) { 
			break;
		}	
		laserPos = 42*sin(laserFrame)/5;
		laserFrame+=5;
		ObjSprite2D_SetDestRect(objLaserMach,-128,-64+laserPos,128,64+laserPos);
		ObjMove_SetPosition(objLaserMach,GetCenterX+r*cos(dir),GetCenterY+r2*sin(dir));	
		dir-=0.2;
		yield;
	}
	Obj_Delete(objLaserMach);
}


// ===================================================================================================

// smoke fam
task smokeFam(x,y,side) {
	let obj = ObjEnemy_Create(OBJ_ENEMY); 
	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	let spin = 0;
	
	ObjEnemy_Regist(obj);
	ObjPrim_SetTexture(obj,famTex); 
	ObjPrim_SetTexture(obj2,famTex); 
	ObjRender_SetAlpha(obj,205);
	ObjRender_SetAlpha(obj2,150);
	Obj_SetRenderPriorityI(obj,30);
	Obj_SetRenderPriorityI(obj2,31);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	ObjRender_SetScaleXYZ(obj2,1,1,0);
	ObjSprite2D_SetSourceRect(obj,31,0,64,31); 
	ObjSprite2D_SetSourceRect(obj2,31,0,64,31); 
	ObjSprite2D_SetDestCenter(obj);
	ObjSprite2D_SetDestCenter(obj2);
	ObjEnemy_SetLife(obj,200);
	ObjRender_SetPosition(obj,x,y,0);	
	ObjMove_SetPosition(obj,x,y);
	
	PlaySFX(SFX_OPTION);
	if(side == 0) {
		ObjMove_SetDestAtSpeed(obj,GetClipMinX+16,GetClipMaxY,6);
	}
	if(side == 1) { 
		ObjMove_SetDestAtSpeed(obj,GetClipMaxX-16,GetClipMaxY,6);
	}
	
	smokeEmit(obj,side);
	
	while(!Obj_IsDeleted(bossObj)) { 
		ObjRender_SetPosition(obj2,ObjMove_GetX(obj),ObjMove_GetY(obj),0);	
		ObjRender_SetAngleZ(obj,-spin/4);	
		ObjRender_SetAngleZ(obj2,spin);	
		spin+=10;
		yield;
	}
	Obj_Delete(obj); Obj_Delete(obj2);
}

// ===================================================================================================

// smoke emitter, aprox 400 tasks will be running which is for me no slowdown. Anything close to 800 will cause fps drop.
// But this doesn't work in stage runs I noticed due to multiple threads. So need to be careful.
task smokeEmit(obj,side) {
	wait(60);
	while(!Obj_IsDeleted(bossObj)) { 
		if(side == 0) { 
			smokePart(ObjMove_GetX(obj),ObjMove_GetY(obj),rand(0.5,1.2),0,rand(0.3,0.9),0.1,255,255,255,255); 
		}
		if(side == 1) { 
			smokePart(ObjMove_GetX(obj),ObjMove_GetY(obj),rand(-0.5,-1.2),0,rand(0.3,0.9),0.1,255,255,255,255); 
		}
		wait(30);
	}
}

// smoke part
task smokePart(x,y,v,dir,dirv,parts,alphaValue,red,green,blue) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;
	let smokeSpin = 0; 
	let vx = v * cos(dir);
	let vy = v * sin(dir);
	let smokeRandMove = 0;
	if(v > 0) { smokeRandMove = rand_int(-44,-130); }
	if(v < 0) { smokeRandMove = rand_int(44,130); }

	ObjPrim_SetTexture(obj,circglit);
	ObjRender_SetBlendType(obj,BLEND_INV_DESTRGB);
	Obj_SetRenderPriorityI(obj,50);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetPosition(obj,x,y);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);
		
	while(! Obj_IsDeleted(obj)) {
		// Check if there are any lasers colliding to evaporate. 
		// This method is quite heavy for the engine as each particle is checked on collision. Therefore the maximum
		// number of lasers I can spawn is 10. But I don't need that many for this SC, though it is always wise to know.
		// It doesn't matter whether the collision check is done at the laser or at the particle. 
		descent(i in 0..length(laserTrackID)) {
		
			// Isintersectedline compares a line with a defined width to see whether it collides with a given circle. 
			// In this case, the line is the laser and the circle is the smoke particle itself.
			// This is why the array info is called for the line (laser) and local obj pos for the circle (smoke)
			if(IsIntersected_Line_Circle(ObjMove_GetX(laserTrackID[i]),																							// xpos of the laserObj
											ObjMove_GetY(laserTrackID[i]),																						// ypos of the laserObj
											ObjMove_GetX(laserTrackID[i]) + cos(ObjStLaser_GetAngle(laserTrackID[i])) * ObjLaser_GetLength(laserTrackID[i]), 	// calc dir of laser based 
											ObjMove_GetY(laserTrackID[i]) + sin(ObjStLaser_GetAngle(laserTrackID[i])) * ObjLaser_GetLength(laserTrackID[i]), 	// calc dir of laser based 
											32,																													// width of collision detection for the laser
											ObjRender_GetX(obj),																								// xpos of smoke part
											ObjRender_GetY(obj),																								// ypos of smoke part
											32)																													// radius of smoke part collision
											) { 																		
												if(parts > 0.1) { parts-=0.6; } 																				// vaporate part (resize to 0.1)
											}
		}

		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);
		ObjRender_SetAngleZ(obj,smokeSpin);	
		ObjRender_SetPosition(obj,x+v*cos(dir),y+v*sin(dir),0);
		ObjMove_SetPosition(obj,x+v*cos(dir),y+v*sin(dir));
		vx = v * cos(dir); vy = v * sin(dir);
		x += vx; y += vy; 
		if(dir > smokeRandMove) { dir-=dirv; } 
		if(dir < smokeRandMove) { dir+=dirv; } 
		if(parts < 3) { parts+=0.3; }
		smokeSpin++;
		if(partc > round(rand(90,180))){ Obj_Delete(obj); }
		
		// Kill objects leaving the screen to keep FPS at decent rates.
		if(ObjRender_GetX(obj) > GetClipMaxX+32 || ObjRender_GetX(obj) < GetClipMinX-32 || ObjRender_GetY(obj) > GetClipMaxY+32 || ObjRender_GetY(obj) < GetClipMinY-32) { 
			Obj_Delete(obj); break;
		}
		yield;
	}
}

// Handles the getting hit sound for the partner. Below 10% of max HP it plays the 'almost dead' sound.
task ouch3SFX(obj) {
    let hpL = ObjEnemy_GetInfo(obj, INFO_LIFE) / 100 * 10;
    let brr = 0;	
    while(!Obj_IsDeleted(obj)) {
		if(ObjEnemy_GetInfo(obj,INFO_SHOT_HIT_COUNT) > 0) {
			wait(3.3);
			if(ObjEnemy_GetInfo(obj, INFO_LIFE) > hpL) { }
			if(ObjEnemy_GetInfo(obj, INFO_LIFE) <= hpL) {  }
		}	
		yield;
 	}
}

task scriptEnding {
	while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0) {
		yield;
	}

	DeleteShotAll(TYPE_ALL, TYPE_ITEM);
	Obj_Delete(bossObj);

	CloseScript(GetOwnScriptID());
}
 