//#TouhouDanmakufu[Single]
#ScriptVersion[3]
#Title["Spell #3"]
#Background["./BG/BG.dnh"]
#Player["./Player/AoCF_YukariReimu/AoCF_YukariReimu.dnh"]
#System["./System/System.dnh"]
#include "./LIB/Library_Index.dnh"

let bossObj;
let bossX = 0;
let bossY = 0;
let bosslife;

let bossImg = GetCurrentScriptDirectory ~ "IMG/Yabusame.png";

let diff = GetCommonData("Difficulty", 0);

let warning = false;

@Initialize{//Declare the boss and assign the texture
	bossObj = ObjEnemy_Create(OBJ_ENEMY_BOSS);
	ObjEnemy_Regist(bossObj);

	SetAreaCommonData("System", "CurrentActiveScript", GetOwnScriptID);

	CutinPythonA1("Psychokinesis Dream Sign \"Echoed Dream Psychexplosion\"", ["Easy", "Normal", "Hard", "Lunatic"][diff], GetCurrentScriptDirectory ~ "IMG/TwoCut.png", [192, 0, 128]);
	ObjEnemyBossScene_StartSpell(GetEnemyBossSceneObjectID);
	PlaySoundA1(13, 70, 0);

	//Move the boss onto the game field
	ObjMove_SetDestAtWeight(bossObj, GetCenterX, GetCenterY - 96, 10, 10);
	ObjEnemy_SetDamageRate(bossObj, 0, 0);
	mainTask;
	
	if(GetCommonData("Boss", "usami") == "usami"){Tag;} //switch to Doremy
	else{
		SetCommonData("Boss", "doremy");
		AnimateBoss_Doremy(bossObj);
	}

	SetShotAutoDeleteClip(256, 256, 256, 256);
}

@Event{
	alternative(GetEventType())
	case(EV_REQUEST_LIFE){
		SetScriptResult(3000);
	}
	case(EV_REQUEST_TIMER){
		SetScriptResult(60);
	}
	case(EV_REQUEST_SPELL_SCORE){
		SetScriptResult(6000000 + diff*100000);
	}
}

@Loading{
}

@MainLoop{
	bossX = ObjMove_GetX(bossObj);
	bossY = ObjMove_GetY(bossObj);

	ObjEnemy_SetIntersectionCircleToShot(bossObj, bossX, bossY, 40);
	ObjEnemy_SetIntersectionCircleToPlayer(bossObj, bossX, bossY, 20);
	yield;
}

@Finalize{

}

task mainTask{
	EnemyName(bossObj, "Sumireko & Doremy", 255, 0, 192);

	FlameAura(bossObj, [255, 0, 192], 2);
	BottomEnemyMarker(bossObj, bossObj);
	wait(90);
	PlaySoundA1(17, 70, 0);
	ConcentrationEffect(bossObj, "Cherry", 60, 5, 128, [255, 0, 192], BLEND_ADD_ARGB);
	wait(60);
	PlaySoundA1(30, 70, 0);
	loop(30){
		BossExplodeObject(bossX, bossY, "Cherry", rand(3, 6), rand(0, 360), [255, 0, 192], BLEND_ADD_ARGB);
		BossExplodeObject(bossX, bossY, "Cherry", rand(3, 6), rand(0, 360), [255, 255, 255], BLEND_ADD_ARGB);
	}
	wait(90);


	alternative(diff)
	case(0){
		fireE;
	}
	case(1){
		fireN;
	}
	case(2){
		fireH;
	}
	case(3){
		fireL;
	}

	endTask;
	wait(120);

	ObjEnemy_SetDamageRate(bossObj, 60, 50);
	ObjEnemy_PlayHitSound(bossObj);
}

task Tag{
	if(GetCommonData("Boss", "usami") == "usami"){
		PossessionTag(ObjMove_GetX(bossObj), ObjMove_GetY(bossObj));
		ObjAnim_ForceStop(bossObj);
		Obj_SetValue(bossObj, "anim_forcestop", false);

		SetCommonData("Boss", "doremy");
		AnimateBoss_Doremy(bossObj);
	}else if(GetCommonData("Boss", "usami") == "doremy"){
		PossessionTag(ObjMove_GetX(bossObj), ObjMove_GetY(bossObj));
		ObjAnim_ForceStop(bossObj);
		Obj_SetValue(bossObj, "anim_forcestop", false); 

		SetCommonData("Boss", "usami");
		AnimateBoss_Usami(bossObj);
	}
}

task fireE{
	let dir = 0;
	let switch = 1;
	loop{
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		ObjAnim_SetAttackA2(bossObj, 210);
		dir = GetAngleToPlayer(bossObj);
		loop(5){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
			Wheel(bossX, bossY, 1.5, dir, [DOT_DPINK, SMALL_MAGENTA, LARGE_PURPLE], 8, 16, 0.15, 0.5);
			dir += 360/5;
			wait(20);
		}
		wait(150);
		warning = true;
		wait(90);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		PlaySoundA1(113, 100, 0);
		warning = false;
		Tag;
		wait(120);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		Tag;
		wait(30);
	}
}

task fireN{
	let dir = 0;
	let switch = 1;
	loop{
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		ObjAnim_SetAttackA2(bossObj, 210);
		dir = GetAngleToPlayer(bossObj);
		loop(6){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
			Wheel(bossX, bossY, 1.5, dir, [DOT_DPINK, SMALL_MAGENTA, LARGE_PURPLE], 8, 16, 0.15, 0.5);
			dir += 360/6;
			wait(20);
		}
		wait(150);
		warning = true;
		wait(90);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		PlaySoundA1(113, 100, 0);
		warning = false;
		Tag;
		wait(120);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		Tag;
		wait(30);
	}
}

task fireH{
	let dir = 0;
	let switch = 1;
	loop{
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		ObjAnim_SetAttackA2(bossObj, 210);
		dir = GetAngleToPlayer(bossObj);
		loop(7){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
			Wheel(bossX, bossY, 2, dir, [DOT_DPINK, SMALL_MAGENTA, LARGE_PURPLE, ORB_BLACK], 8, 16, 0.15, 0.5);
			dir += 360/7;
			wait(20);
		}
		wait(240);
		warning = true;
		wait(90);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		PlaySoundA1(113, 100, 0);
		warning = false;
		Tag;
		wait(120);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		Tag;
		wait(30);
	}
}

task fireL{
	let dir = 0;
	let switch = 1;
	loop{
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		ObjAnim_SetAttackA2(bossObj, 210);
		dir = GetAngleToPlayer(bossObj);
		loop(9){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
			Wheel(bossX, bossY, 2, dir, [DOT_DPINK, SMALL_MAGENTA, LARGE_PURPLE, ORB_BLACK], 8, 16, 0.15, 0.5);
			dir += 360/9;
			wait(15);
		}
		wait(240);
		warning = true;
		wait(90);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		PlaySoundA1(113, 100, 0);
		warning = false;
		Tag;
		wait(120);

		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
		Tag;
		wait(30);
	}
}

function Wheel(x, y, v, a, g, num, startrad, radplus, rot){
	let base = CreateShotA2(x, y, -v, a, 0.05, v, 0, 5);
	ObjShot_SetIntersectionEnable(base, false);
	ObjShot_SetSpellResist(base, true);
	Obj_SetVisible(base, false);

	let dream = DreamPortal(x, y, startrad/32);

	let wheelDeletionTrigger = false;
	doThisShit;

	return base;

	task doThisShit{
		let globalrad = startrad;
		let globalangle = 0;

		portal;

		ascent(i in 0 .. length(g)){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
			if(GetCommonData("Boss", "usami") == "usami"){return;}
			wheelDeletionTrigger = false;

			PlaySoundA1(97, 70, 0);
			loop(num){
				WheelBullet(globalrad, globalangle, g[i]);
				globalangle += 360/num;
			}
			if(i >= length(g) - 1){NoCheck; return;}
			while(CheckForBorderIntersection(ObjMove_GetX(base), ObjMove_GetY(base), globalrad) == "None"){
				if(Obj_IsDeleted(base)){return;}
				if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
				if(GetCommonData("Boss", "usami") == "usami"){return;}

				globalangle += rot;
				globalrad += radplus;
				yield;
			}
			wheelDeletionTrigger = true;
			if(CheckForBorderIntersection(ObjMove_GetX(base), ObjMove_GetY(base), globalrad) == "Left" || CheckForBorderIntersection(ObjMove_GetX(base), ObjMove_GetY(base), globalrad) == "Right"){
				ObjMove_SetAngle(base, ReflectionAngle(ObjMove_GetAngle(base), 90));
			}else{
				ObjMove_SetAngle(base, ReflectionAngle(ObjMove_GetAngle(base), 0));
			}
			wait(5);
		}

		task portal{
			let c = 0;
			while(!Obj_IsDeleted(base)){
				if(GetCommonData("Boss", "usami") == "usami"){break;}

				if(warning == true){
					if(c % 30 == 0){
						ConcentrationEffect(base, "Cherry", 60, 5, globalrad*1.25, [255, 0, 192], BLEND_ADD_ARGB);
					}
					c++;
				}

				ObjRender_SetPosition(dream, ObjMove_GetX(base), ObjMove_GetY(base), 0);
				Obj_SetValue(dream, "size", globalrad/32);
				yield;
			}
			if(GetCommonData("Boss", "usami") == "usami"){
				Explosion(ObjRender_GetX(dream), ObjRender_GetY(dream), globalrad/91);

				let dir = GetAngleToPlayer(dream);
				let num = [12, 14, 16, 18][diff];
				let basespeed = [1.5, 2, 2, 2.5][diff];
				loop(num){
					ShotA1(ObjRender_GetX(dream), ObjRender_GetY(dream), basespeed, dir, FIRE_PURPLE+1000, 10);
					ShotA1(ObjRender_GetX(dream), ObjRender_GetY(dream), basespeed + 0.15, dir, FIRE_PURPLE+1000, 10);
					ShotA1(ObjRender_GetX(dream), ObjRender_GetY(dream), basespeed + 0.3, dir, FIRE_PURPLE+1000, 10);

					ShotA1(ObjRender_GetX(dream), ObjRender_GetY(dream), rand(0.5, 1.5), dir, BL_SMALL_PURPLE+1000, 10);
					dir += 360/num;
				}

				wait(30);
			}
			
			Obj_SetValue(dream, "KillSwitch", true);
			
		}

		task NoCheck{
			while(!Obj_IsDeleted(base)){
				if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){return;}
				if(GetCommonData("Boss", "usami") == "usami"){return;}
				globalangle += rot;
				globalrad += radplus;
				yield;
			}
		}
	}

	task WheelBullet(rad, aa, graphic){
		let obj = ShotA1(ObjMove_GetX(base) + rad*cos(aa), ObjMove_GetY(base) + rad * sin(aa), 0, aa, graphic, 10);
		ObjShot_SetSpellResist(obj, true);
		ObjShot_SetAutoDelete(obj, false);

		while(!Obj_IsDeleted(base) && !Obj_IsDeleted(obj)){
			if(wheelDeletionTrigger){Obj_Delete(obj);}
			if(GetCommonData("Boss", "usami") == "usami"){break;}

			ObjMove_SetPosition(obj, ObjMove_GetX(base) + rad*cos(aa), ObjMove_GetY(base) + rad*sin(aa));
			ObjMove_SetAngle(obj, aa);

			rad += radplus;
			aa += rot;
			yield;
		}

		loop(10){
			ObjMove_SetSpeed(obj, 3);
			ObjShot_FadeDelete(obj);
			yield;
		}
	}

	task Explosion(x, y, ss){
		let obj = CreateSunShotA1(x, y, 0, 0, 0, [160, 0, 255]);
		let c = 0;
		loop(30){
			if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){break;}
			Obj_SetValue(obj, "SunSize", deceleration(0, ss, c/30));
			c++;
			yield;
		}
		c = 0;
		loop(30){
			Obj_SetValue(obj, "SunSize", acceleration(ss, 0, c/30));
			c++;
			yield;
		}
		Obj_Delete(obj);
	}
}

function DreamPortal(x, y, size){
	let v_count = 32;

	let obj = ObjPrim_Create(OBJ_PRIMITIVE_2D);
	Obj_SetRenderPriorityI(obj, 30);
	ObjPrim_SetPrimitiveType(obj, PRIMITIVE_TRIANGLEFAN);
	ObjPrim_SetVertexCount(obj, v_count+2);
	ObjPrim_SetTexture(obj, GetCurrentScriptDirectory ~ "IMG/dream_world.png");
	ObjRender_SetPosition(obj, x, y, 0);
	ObjRender_SetColor(obj, 0, 0, 0);
	Obj_SetValue(obj, "size", size);

	Render;

	return obj;

	task Render{
		let sc = 0;
		let c = 255;
		let dir = 0;
		ScaleUp;

		while(!Obj_IsDeleted(obj)){
			size = Obj_GetValueD(obj, "size", 0);

			ObjPrim_SetVertexUVT(obj, 0, ObjRender_GetX(obj) + GetStgFrameLeft, ObjRender_GetY(obj) + GetStgFrameTop);
			ObjPrim_SetVertexPosition(obj, 0, 0, 0, 0);
			ascent(i in 0 .. v_count+1){
				ObjPrim_SetVertexUVT(obj, i, ObjRender_GetX(obj) + GetStgFrameLeft + sc*32*cos(dir), ObjRender_GetY(obj) + GetStgFrameTop + sc*32*sin(dir));
				ObjPrim_SetVertexPosition(obj, i, sc*32*cos(dir), sc*32*sin(dir), 0);
				dir += 360/v_count;
			}
			yield;
		}

		task ScaleUp{
			ascent(i in 0 .. 21){
				sc = linear(0, size, i/20);

				if(i <= 10){
					c = linear(0, 255, i/10);
					ObjRender_SetColor(obj, c, c, c);
				}
				yield;
			}
			while(Obj_GetValueD(obj, "KillSwitch", false) == false){
				sc = size;
				yield;
			}

			
			ascent(i in 0 .. 21){
				sc = linear(size, 0, i/20);

				if(i <= 10){
					c = linear(255, 0, i/10);
					ObjRender_SetColor(obj, c, c, c);
				}
				yield;
			}
			Obj_Delete(obj);
		}
	}
}

function CheckForBorderIntersection(x, y, rad){
	if(IsIntersected_Line_Circle(0, 0, GetClipMaxX, 0, 1, x, y, rad)){return "Top";}
	else if(IsIntersected_Line_Circle(GetClipMaxX, 0, GetClipMaxX, GetClipMaxY, 1, x, y, rad)){return "Right";}
	else if(IsIntersected_Line_Circle(GetClipMaxX, GetClipMaxY, 0, GetClipMaxY, 1, x, y, rad)){return "Bottom";}
	else if(IsIntersected_Line_Circle(0, GetClipMaxY, 0, 0, 1, x, y, rad)){return "Left";}
	else{return "None";}
}

task endTask{
	while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0) {
		yield;
	}
	PlaySoundA1(29, 60, 0);
	PlaySoundA1(29, 30, 60);
	DeleteShotAll(TYPE_ALL, TYPE_ITEM);
	ScreenShakeA1(20, 10);
	loop(30){
		PlaySoundA1(95, 50, 0);
		BossExplodeObject(bossX, bossY, "Cherry", rand(3, 5), rand(0, 360), [255, 0, 192], BLEND_ADD_ARGB);
		BossExplodeObject(bossX, bossY, "Cherry", rand(3, 5), rand(0, 360), [255, 255, 255], BLEND_ADD_ARGB);
		wait(4);
	}
	BossExplosionEffect(bossObj, "Cherry", [255, 0, 192], [255, 0, 192], BLEND_ADD_ARGB);
	PlaySoundA1(29, 80, 0);

	ScreenShakeA1(60, 10);
	NotifyEventAll(EV_USER+4, 0);
	StopSlow(TARGET_ALL);
	SetAutoDeleteObject(true);
	Obj_Delete(bossObj);
	wait(120);
	CloseScript(GetOwnScriptID());
}