#TouhouDanmakufu[Single]
#ScriptVersion[3]
#Title["Dj non-spell 04 lunatic"]
#Text["Dj non-spell 04 lunatic"]

// global gravity. Higher difficulty, more gravity?
let gravity_strength = 0.02;

let numBalloons = 0;

// crowd objects
let crowdObj = ObjPrim_Create(OBJ_SPRITE_2D);
let crowdObj2 = ObjPrim_Create(OBJ_SPRITE_2D);
let crowdObj3 = ObjPrim_Create(OBJ_SPRITE_2D);

// arrays
let crowdHoriArray = [crowdObj];
let crowdVertArray = [crowdObj2,crowdObj3];

// tex
let crowdTex = "script/thdcs/system/effects/crowdeff.png";
let warnTex = "script/thdcs/system/effects/warningcrowd.png";

#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 {
	renderBoss(3);
	setAura(bossObj,64,255,128);
	SetCommonData("bossAttackType",1);
	SetCommonData("bossCircleType",0);
	setInvulnerableTime(bossObj,180);
	
	ObjMove_SetDestAtSpeed(bossObj,192,120,5);
	SetShotAutoDeleteClip(16,16,16,16);
	SetAutoDeleteObject(true);
	mainTask;

} 

@Event { 
	alternative(GetEventType()) 
	case(EV_REQUEST_LIFE) { 
		SetScriptResult(350);
	}
	case(EV_REQUEST_TIMER) { 
		SetScriptResult(57);
	}
} 

@MainLoop { yield; } 
@Finalize { } 

task mainTask { 
	yield;
	scriptEnding;	
	warningSign;
	wait(120);
	PlaySFX(SFX_CROWD01);
	balloonKeeper;
	movement;
	fire;
	crowdSupportHorizontal(crowdObj,GetCenterX,GetClipMaxY,0);
	wait(60);
	crowdSupportVertical(crowdObj2,GetClipMinX,GetCenterY,90);	
	crowdSupportVertical(crowdObj3,GetClipMaxX,GetCenterY,270);	
	wait(30);
} 

// movement
task movement { 
	while(!Obj_IsDeleted(bossObj)) { 
		ObjMove_RandomPosWeight(bossObj,rand(10,20),rand(10,20),30,50,GetClipMinX+72,GetClipMinY+64,GetClipMaxX-72,GetCenterY-120);		
		wait(180);
	}
}

// Keeps the balloons at minimum of 3 (higher is difficult?) 
task balloonKeeper { 
	while(! Obj_IsDeleted(bossObj)) {
		if(numBalloons < 4) {
			balloonBullet(GetEnemyX,GetEnemyY,1,rand_int(0,359),rand_int(229,236));
			numBalloons++;
			wait(15);
		}
		yield;
	}
}

task fire {
	let dir = 0;
	while(!Obj_IsDeleted(bossObj)) {
		PlaySFX(SFX_TAN00);
		ascent(i in 0..24) { 
			CreateShotA1(bossX+32*cos(dir),bossY+32*sin(dir),1,dir,225,20);
			dir+=360/24;
		}
		dir+=13;
		wait(60);
	}
}


// Balloon object bullet with collision detection and gravity influence
task balloonBullet(x,y,v,dir,kleur) {

	let obj = ObjShot_Create(OBJ_SHOT);
	
	let x_speed = rand(-3, 3);
	let y_speed = 0;
	let old_x = x;
	let old_y = y;
	let new_x = old_x + x_speed;
	let new_y = old_y + y_speed;	
		
	ObjShot_Regist(obj);
	ObjMove_SetPosition(obj,x,y);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetAngle(obj,dir);
	ObjMove_SetSpeed(obj,1);
	ObjShot_SetGraphic(obj,kleur);
	ObjShot_SetDelay(obj,0);	

	while(!Obj_IsDeleted(obj)) {

		// gravity code (thanks to KimoKeine aka Blargel)
		let new_angle = atan2(new_y-old_y, new_x-old_x);
		ObjMove_SetPosition(obj, new_x, new_y);
		ObjMove_SetAngle(obj, new_angle);
		y_speed += gravity_strength;
		
		// collision checking for stage floor/ceiling
		if(ObjMove_GetY(obj) > GetClipMaxY) { y_speed *= -1; } 	
		if(ObjMove_GetY(obj) < GetClipMinY + 32) { y_speed *= -1; } 	
		if(new_x <= GetClipMinX + 32) { x_speed = rand(1.0,1.5); } 	
		if(new_x >= GetClipMaxX - 32) { x_speed = rand(-1.0,-1.5); } 	

		// movement code for gravity influence
		old_x = ObjMove_GetX(obj);
		old_y = ObjMove_GetY(obj);
		new_x = old_x + x_speed;
		new_y = old_y + y_speed;	
		
		descent(i in 0..length(crowdHoriArray)) {
			// Collision line and circle for horizontal crowd
			if(IsIntersected_Line_Circle(ObjRender_GetX(crowdHoriArray[i])-512,			// xpos begin rectangle
									ObjRender_GetY(crowdHoriArray[i])-64,				// ypos begin rectangle
									ObjRender_GetX(crowdHoriArray[i])+512, 				// xpos end rectangle
									ObjRender_GetY(crowdHoriArray[i])+64, 				// ypos end rectangle
									12,													// size of rectangle
									ObjMove_GetX(obj),									// xpos of balloon 
									ObjMove_GetY(obj),									// ypos of balloon
									12)													// radius of smoke part collision
									) { 
										y_speed = rand(-2,-3.5); 						// reverse speed (bounce back) by accelerate 
									}
		}
								
		descent(i in 0..length(crowdVertArray)) {
		// Collision line and circle for vertical crowd
			if(IsIntersected_Line_Circle(ObjRender_GetX(crowdVertArray[i])-64,			// xpos begin rectangle
									ObjRender_GetY(crowdVertArray[i])-512,				// ypos begin rectangle
									ObjRender_GetX(crowdVertArray[i])+64, 				// xpos end rectangle
									ObjRender_GetY(crowdVertArray[i])+512, 				// ypos end rectangle
									12,													// size of rectangle
									ObjMove_GetX(obj),									// xpos of balloon 
									ObjMove_GetY(obj),									// ypos of balloon
									12)													// radius of smoke part collision
									) { 
										
										if(crowdVertArray[i] == crowdObj2) { 
											x_speed = rand(+2,+3.5); 					// reverse speed (bounce back) by accelerate
										}
										if(crowdVertArray[i] == crowdObj3) { 
											x_speed = rand(-2,-3.5); 					// reverse speed (bounce back) by accelerate
										}
									}		
		}
		yield;
	}
	numBalloons--;
}

// Crowd eff horizontal (floor / ceiling)
task crowdSupportHorizontal(obj,x,y,dir) {

	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	
	let crowdFrameCount = 0;
	let crowdpos = 0;

	ObjPrim_SetTexture(obj,crowdTex);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj,30);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetPosition(obj,x,y);
	ObjRender_SetAlpha(obj,255);
	ObjRender_SetScaleXYZ(obj,1.0,1.0,0);
	ObjSprite2D_SetSourceRect(obj,0,1,512,128);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetAngleZ(obj,dir);

	ObjPrim_SetTexture(obj2,crowdTex);
	ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj2,30);
	ObjRender_SetPosition(obj2,x,y,0);
	ObjMove_SetPosition(obj2,x,y);
	ObjRender_SetAlpha(obj2,255);
	ObjRender_SetScaleXYZ(obj2,1.0,1.0,0);
	ObjSprite2D_SetSourceRect(obj2,0,1,512,128);
	ObjSprite2D_SetDestCenter(obj2);
	ObjRender_SetAngleZ(obj2,dir);	

	// invis laser stuff
	let objInvis = ObjShot_Create(OBJ_STRAIGHT_LASER);
	ObjShot_Regist(objInvis);
	
	ObjMove_SetPosition(objInvis,x,y);
	ObjMove_SetSpeed(objInvis,0);
	ObjMove_SetAngle(objInvis,0);
	ObjStLaser_SetAngle(objInvis,0);
	ObjShot_SetGraphic(objInvis,1);
	ObjShot_SetDelay(objInvis,0);
	ObjLaser_SetLength(objInvis,512);
	ObjLaser_SetRenderWidth(objInvis,4);
	ObjLaser_SetIntersectionWidth(objInvis,4);
	ObjStLaser_SetSource(objInvis,false);
	ObjShot_SetSpellResist(objInvis,true);
	ObjShot_SetAutoDelete(objInvis,false);
	
	while(!Obj_IsDeleted(obj)) {
		ObjMove_SetPosition(objInvis,x-256,y+crowdpos);
		
		ObjSprite2D_SetSourceRect(obj,0+crowdFrameCount/4,1,512+crowdFrameCount/4,128);
		ObjRender_SetPosition(obj,x,y+crowdpos,0);
		
		ObjSprite2D_SetSourceRect(obj2,0-crowdFrameCount/4,1,512-crowdFrameCount/4,128);
		ObjRender_SetPosition(obj2,x,y+crowdpos,0);		
		crowdpos = 64*sin(crowdFrameCount)/1;
		crowdFrameCount+=2;	
		
		yield;
	}
}

// Crowd eff vertical (walls)
task crowdSupportVertical(obj,x,y,dir) {

	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	
	let crowdFrameCount = 0;
	let crowdpos = 0;

	ObjPrim_SetTexture(obj,crowdTex);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj,30 );
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetPosition(obj,x,y);
	ObjRender_SetAlpha(obj,255);
	ObjRender_SetScaleXYZ(obj,1.0,1.0,0);
	ObjSprite2D_SetSourceRect(obj,0,1,512,128);
	ObjSprite2D_SetDestCenter(obj);
	ObjMove_SetAngle(obj,dir);	
	ObjRender_SetAngleZ(obj,dir);
	ObjRender_SetAngleXYZ(obj,0,0,dir);

	ObjPrim_SetTexture(obj2,crowdTex);
	ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj2,30);
	ObjRender_SetPosition(obj2,x,y,0);
	ObjMove_SetPosition(obj2,x,y);
	ObjRender_SetAlpha(obj2,255);
	ObjRender_SetScaleXYZ(obj2,1.0,1.0,0);
	ObjSprite2D_SetSourceRect(obj2,0,1,512,128);
	ObjSprite2D_SetDestCenter(obj2);
	ObjMove_SetAngle(obj2,dir);	
	ObjRender_SetAngleZ(obj2,dir);	
	
	// invis laser stuff
	let objInvis = ObjShot_Create(OBJ_STRAIGHT_LASER);
	ObjShot_Regist(objInvis);
	ObjMove_SetPosition(objInvis,x,y);
	ObjMove_SetSpeed(objInvis,0);
	ObjMove_SetAngle(objInvis,90);
	ObjStLaser_SetAngle(objInvis,90);
	ObjShot_SetGraphic(objInvis,268);
	ObjShot_SetDelay(objInvis,0);
	ObjLaser_SetLength(objInvis,512);
	ObjLaser_SetRenderWidth(objInvis,4);
	ObjLaser_SetIntersectionWidth(objInvis,4);
	ObjStLaser_SetSource(objInvis,false);
	ObjShot_SetSpellResist(objInvis,true);
	ObjShot_SetAutoDelete(objInvis,false);	

	while(!Obj_IsDeleted(obj)) {
		ObjMove_SetPosition(objInvis,x+crowdpos,y-256);
		
		ObjSprite2D_SetSourceRect(obj,0+crowdFrameCount/4,1,512+crowdFrameCount/4,128);
		ObjRender_SetPosition(obj,x+crowdpos,y,0);
		
		ObjSprite2D_SetSourceRect(obj2,0-crowdFrameCount/4,1,512-crowdFrameCount/4,128);
		ObjRender_SetPosition(obj2,x+crowdpos,y,0);		
		crowdpos = 64*sin(crowdFrameCount)/1;
		crowdFrameCount+=3;	
		
		yield;
	}
}

// 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_ADD_ARGB);
	ObjRender_SetAlpha(obj,0);
	ObjSprite2D_SetSourceRect(obj,0,0,512,512);
	ObjRender_SetScaleXYZ(obj,0.4,0.4,0);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);
	PlaySFX(SFX_ALERT);
	wait(30);
	ObjRender_SetAlpha(obj,205);
	wait(30);
	ObjRender_SetAlpha(obj,0);
	wait(30);
	ObjRender_SetAlpha(obj,205);
	wait(30);
	ObjRender_SetAlpha(obj,0);
	wait(30);
	ObjRender_SetAlpha(obj,205);
	wait(30);
	ObjRender_SetAlpha(obj,0);
	Obj_Delete(obj);
}

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

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

	CloseScript(GetOwnScriptID());
}
 