let current = GetCurrentScriptDirectory;
let DEBUG = false;
let CutinDifficulty = "";
let SpellAttack_img = current ~ "SpellAttack.png"; 
let img_SpellAttack = current ~ "SpellAttackText.png"; // Spell Declare
let Alpha_HUD = 255;
 //top, bottom

let NAZRIN = "NAZRIN";
let BYAKUREN = "BYAKUREN";
let KANAKO = "KANAKO";
let MOKOU = "MOKOU";
let AYA = "AYA";
let YABUSAME = "LENEN";

let LENEN = "LENEN";

//If you have any questions or requests, send them to gtbot/TheGtbot (I go by either on different places)
//Version 1.3

task ObjCutin_SetSpellcardS4(SpellName, image, cuttype, R, G, B){
	let r = IntToString(R);
	let g = IntToString(G);
	let b = IntToString(B);
	let boss = GetEnemyBossObjectID[0];
	let spells = Obj_GetValueD(boss, "Spellcards", []);
	spells = spells ~ [[[SpellName, r, g, b], cuttype, image]];
	Obj_SetValue(boss, "Spellcards", spells);
}

task ObjText_LaunchS3(difficulty){TextS3(difficulty);}
task ObjCutin_LaunchS3(Type, image){CutinS3(Type, image);}

task TextS3(difficulty){
	let spells = Obj_GetValueD(GetEnemyBossObjectID[0], "Spellcards", []);
	let boss = GetEnemyBossObjectID[0]; let spcount = length(spells);

	if(!IsCommonDataAreaExists("cutinHistory")){
		CreateCommonDataArea("cutinHistory");
	}
	LoadCommonDataAreaA1("cutinHistory");

	descent(i in 0..spcount){SpellText(6*i, i);} let delay = 6;
	while(!Obj_IsDeleted(boss)){
		spells = Obj_GetValueD(GetEnemyBossObjectID[0], "Spellcards", []);
		if(length(spells) != spcount && delay == 0){
			delay = 6;
			SpellText(0, spcount);
			spcount++;
		}
		delay = max(delay-1, 0);
		yield;
	}

	task SpellText(delay, num){
		CutinDifficulty = difficulty;

		let TSpell = spells[num][0];
		let SpellName = TSpell[0];
		let r = atoi(TSpell[1]);
		let g = atoi(TSpell[2]);
		let b = atoi(TSpell[3]);
		
		let Colors = [[r,g,b]];
		
		//These are long-looking common data group names
		let SpellDataAttempt = SpellName~"|"~CutinDifficulty~"|"~GetPlayerID~"|"~"Attempt";
		let SpellDataGet = SpellName~"|"~CutinDifficulty~"|"~GetPlayerID~"|"~"Get";
		//This is actually the common data retrieval
		let SpellValueAttempt = GetAreaCommonData("cutinHistory", SpellDataAttempt, 0);
		let SpellValueGet = GetAreaCommonData("cutinHistory", SpellDataGet, 0);
		
		if(!IsReplay && !DEBUG && num == 0){
			SpellValueAttempt++;
			SetAreaCommonData("cutinHistory", SpellDataAttempt, SpellValueAttempt);
			SaveCommonDataAreaA1("cutinHistory");
		}
	
		let SpellBG = CreateSimple2DImageA2(0.79+0.01*max(0, 1-num), SpellAttack_img, 0, 0, 255, 31);
		ObjSprite2D_SetDestRect(SpellBG, -224, -12, 32, 20);
		ObjRender_SetPosition(SpellBG, 520, 360+40*num, 0);
		ObjRender_SetAlpha(SpellBG, 0);
		ObjRender_SetColor(SpellBG, Colors[0][0], Colors[0][1], Colors[0][2]);
		
		let SpellText = ObjText_Create;
		ObjText_SetText(SpellText,SpellName);
		ObjText_SetFontSize(SpellText,12);
		ObjText_SetFontColorTop(SpellText,255,255,255);
		ObjText_SetFontColorBottom(SpellText, Colors[0][0], Colors[0][1], Colors[0][2]);
		ObjText_SetFontBorderType(SpellText,BORDER_FULL);
		ObjText_SetFontBorderColor(SpellText,32,32,32);
		ObjText_SetFontBorderWidth(SpellText,1);
		ObjText_SetHorizontalAlignment(SpellText, ALIGNMENT_RIGHT);
		ObjText_SetMaxWidth(SpellText, GetStgFrameWidth-130);
		Obj_SetRenderPriority(SpellText, 0.79+0.01*max(0, 1-num));
		ObjRender_SetPosition(SpellText, 200, 360+40*num, 0);
		ObjRender_SetAlpha(SpellText, 0);
		
		
		let SpellInfo = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
		let bonus = 0;
		let count = GetNumSize(bonus);
		let scount = max(2, GetNumSize(SpellValueAttempt));
		ObjPrim_SetTexture(SpellInfo, SpellAttack_img);
		ObjRender_SetBlendType(SpellInfo, BLEND_ALPHA);
		Obj_SetRenderPriority(SpellInfo, 0.8);
		ObjRender_SetY(SpellInfo, 48);
		ObjRender_SetAlpha(SpellInfo, 0);
		
		//-------------Introduction--------------------------
		
		loop(delay){yield;}
		let len = 30;
		ascent(i in 0..len){
			let mod = i/len;
			let tmod = min(1, ((i*2)/len));
			ObjRender_SetScaleXYZ(SpellBG, 4-3*mod, 4-3*mod, 1);
			ObjRender_SetAlpha(SpellBG, 255*mod);
			ObjRender_SetX(SpellText, 800*(1-mod));
			//ObjRender_SetScaleXYZ(SpellText, 4-3*tmod, 4-3*tmod, 1);
			ObjRender_SetAlpha(SpellText, 255*tmod);
			yield;
		}
		loop(40){yield;}
		let mov = 0;
		
		//if(Type == "MOKOU"){SpellcardDeclareMovement([ObjRender_GetY(SpellText), 48+32*num, 0.175, 9]);loop(60){yield;}}
		RegularSpellCardDeclare([ObjRender_GetY(SpellText), 60+32*num, 0.135, 12]);
		//32 is the offset from the top of the screen
		//If using a system where the lifebar is on the boss rather than the top of the screen, 12 is a good value

		
		loop(delay*0.65){yield;}
		
		ascent(i in 0..80){
			let endspeed = 0.5+i/2.5;
			ObjRender_SetX(SpellBG, ObjRender_GetX(SpellBG)+endspeed);
			ObjRender_SetX(SpellText, ObjRender_GetX(SpellText)+endspeed);
			yield;
		}
		
		Obj_Delete(SpellBG);
		Obj_Delete(SpellText);
		
		function SpellcardDeclareMovement(dest){
			ObjRender_SetY(SpellInfo, 24+dest[1]);
			while(dest[0]>dest[1]){
				dest[0] = ObjRender_GetY(SpellText);
				mov = min(mov+dest[2], (dest[0]-dest[1])/dest[3]+0.125);
				ObjRender_SetY(SpellBG, dest[0]-mov);
				ObjRender_SetY(SpellText, dest[0]-mov);
				yield;
			}
		}
		
		function RegularSpellCardDeclare(dest){
			if(num!=0){Obj_Delete(SpellInfo);}
			SpellcardDeclareMovement(dest);
			ascent(i in 0..20){
				ObjRender_SetAlpha(SpellInfo, 255/20*i);
				DrawScoreBonus;
				yield;
			}
			let timerf = ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_ORGTIMERF);
			let startdiff = timerf-(timerf-5*60);
			while(!Obj_IsDeleted(boss)){
				ObjRender_SetAlpha(SpellBG, Alpha_HUD);
				ObjRender_SetAlpha(SpellText, Alpha_HUD);
				ObjRender_SetAlpha(SpellInfo, Alpha_HUD);
				
			//	let modif = min(1, ((ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_TIMERF))/(ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_ORGTIMERF)-startdiff)));
			//	bonus = ((sscore*0.20)+(sscore*((modif)*0.80)));
				DrawScoreBonus;
				yield;
			}
			Obj_Delete(SpellInfo);
			
			if(bonus>=1 && ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_TIMERF) > 0){
			//	GotSpellCard(bonus);
			//	AddScore(bonus);
				if(!IsReplay && !DEBUG && num == 0){
					SpellValueGet++;
					SetAreaCommonData("cutinHistory", SpellDataGet, SpellValueGet);
					SaveCommonDataAreaA1("cutinHistory");
				}
			}else{
			//	FailedSpellCard;
			}
		}
		sub DrawScoreBonus{
			if(GetPlayerY<128+32*length(spells)){Alpha_HUD = max(Alpha_HUD-10, 85);}else{Alpha_HUD = min(Alpha_HUD+11, 255);}
			
			ObjSpriteList2D_ClearVertexCount(SpellInfo);
			
			//340 + 42
			ObjSpriteList2D_SetSourceRect(SpellInfo, 0, 48, 128, 60);
			ObjSpriteList2D_SetDestCenter(SpellInfo);
			ObjRender_SetX(SpellInfo, 542-130);
			ObjSpriteList2D_AddVertex(SpellInfo);
			//Bonus Score
			bonus = ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_SPELL_SCORE);
			count = GetNumSize(bonus);
			let listNum = DigitToArray(min(99999999, bonus), count);
			let objScene = GetEnemyBossSceneObjectID;
			if(ObjEnemyBossScene_GetInfo(objScene, INFO_PLAYER_SHOOTDOWN_COUNT) + ObjEnemyBossScene_GetInfo(objScene, INFO_PLAYER_SPELL_COUNT) == 0){
				ascent(iObj in 0 .. count){
					let num = listNum[iObj];
					ObjRender_SetX(SpellInfo, 542-94-(8*count) + iObj * 7);
					ObjSpriteList2D_SetSourceRect(SpellInfo, num * 8, 64, (num + 1) * 8, 76);
					ObjSpriteList2D_SetDestCenter(SpellInfo);
					ObjSpriteList2D_AddVertex(SpellInfo);
				}
			}else{
					bonus = 0;
					ObjRender_SetX(SpellInfo, 542-131);
					ObjSpriteList2D_SetSourceRect(SpellInfo, 144, 48, 176, 60);
					ObjSpriteList2D_SetDestCenter(SpellInfo);
					ObjSpriteList2D_AddVertex(SpellInfo);
			}
			//History
			listNum = DigitToArray(SpellValueGet, scount) ~ [10] ~ DigitToArray(SpellValueAttempt, scount);
				
			ascent(iObj in 0 .. scount*2+1){
				let num = listNum[iObj];
				ObjRender_SetX(SpellInfo, 542-58 + iObj * 8);
				ObjSpriteList2D_SetSourceRect(SpellInfo, num * 8, 64, (num + 1) * 8, 76);
				ObjSpriteList2D_SetDestCenter(SpellInfo);
				ObjSpriteList2D_AddVertex(SpellInfo);
			}
		}
	}
}


task CutinS3(Type, mimage){
	let spells = Obj_GetValueD(GetEnemyBossObjectID[0], "Spellcards", []);
	let boss = GetEnemyBossObjectID[0];
	let spcount = length(spells);
	
	let IsSpellAttackAnimation = false;
	SpawnCutinImage(Type, mimage);
	
	let delay = 6;
	while(!Obj_IsDeleted(boss)){spells = Obj_GetValueD(GetEnemyBossObjectID[0], "Spellcards", []); yield;}

	task FireCutinA2(x, y, alpha, img, details){
		if(IsSpellAttackAnimation){return;}
		//[spd, spdinc, ang, anginc, alphachange, time]
		let SpellCutin = CreateSimple2DImageA1(0.4, img);
		ObjRender_SetPosition(SpellCutin, x, y, 0);
		ObjRender_SetAlpha(SpellCutin, alpha);
		
		ascent(i in 0..length(details)){
			let nx = ObjRender_GetX(SpellCutin);
			let ny = ObjRender_GetY(SpellCutin);
			let info = details[i];
			let len = info[5];
			let alphinc = -(alpha-info[4])/len;
			let spdinc = -(info[0]-info[1])/len;
			let mspeed = info[0];
			let cangle = info[2];
			ascent(x in 0..len){
				mspeed+=spdinc;
				cangle+=info[3];
				nx += mspeed*cos(cangle);
				ny += mspeed*sin(cangle);
				ObjRender_SetPosition(SpellCutin, nx, ny, 0);
				yield;
				alpha = min(max(alpha+alphinc, 0), 255);
				ObjRender_SetAlpha(SpellCutin, alpha);
			}
		}
		Obj_Delete(SpellCutin);
	}

	task FireCutinA3(x, y, alpha, img, scale, details, blendType, colorr){
		if(IsSpellAttackAnimation){return;} let hsvColor = ColorRGBtoHSV(colorr[0], colorr[1], colorr[2]);
		//[spd, spdinc, ang, anginc, alphachange, time]
		let SpellCutin = CreateSimple2DImageA1(0.279, img);
		ObjRender_SetPosition(SpellCutin, x, y, 0);
		ObjRender_SetAlpha(SpellCutin, alpha);
		ObjRender_SetScaleXYZ(SpellCutin, scale, scale, 0);

		ObjRender_SetBlendType(SpellCutin, blendType);
		ObjRender_SetColorHSV(SpellCutin, hsvColor[0], hsvColor[1], hsvColor[2]);
		
		ascent(i in 0..length(details)){
			let nx = ObjRender_GetX(SpellCutin);
			let ny = ObjRender_GetY(SpellCutin);
			let info = details[i];
			let len = info[5];
			let alphinc = -(alpha-info[4])/len;
			let spdinc = -(info[0]-info[1])/len;
			let mspeed = info[0];
			let cangle = info[2];
			ascent(x in 0..len){
				mspeed+=spdinc;
				cangle+=info[3];
				nx += mspeed*cos(cangle);
				ny += mspeed*sin(cangle);
				ObjRender_SetPosition(SpellCutin, nx, ny, 0);
				yield;
				alpha = min(max(alpha+alphinc, 0), 255);
				ObjRender_SetAlpha(SpellCutin, alpha);
			}
		}
		Obj_Delete(SpellCutin);
	}

	function SpawnCutinImage(type, image){
		//We use another "type" variable (lowercase t) so that
		//spellcards set after the root function is called will play the
		//new set cutin type as opposed to the original one
		// same for image
		
		if(type == "C_YOUMU"){
			FireCutinA2(-256, GetStgFrameHeight/2, 0, image,
			[
				[18, 18, 0, 0, 255, 30],
				[0.5, 0.5, 0, 0, 255, 100],
				[18, 18, 0, 0, 0, 35]
			]
			);

			ascent(i in 1..7){
				FireCutinA3(-256, GetStgFrameHeight/2, 0, image, 1 + i/120,
				[
					[18, 18-i/20, 0, 0, 75, 30],
					[0.5, 0.5, 0, 0, 75, 100],
					[18, 18, 0, 0, 0, 35]
				],
				BLEND_ADD_ARGB, [46, 184, 46]
				);
			}
		}

		else if(type == "C_GHOST"){
			FireCutinA2(-256, GetStgFrameHeight/2, 60, image,
			[
				[18, 18, 0, 0, 0, 30],
				[0.5, 0.5, 0, 0, 255, 45],
				[0.5, 0.5, 0, 0, 255, 100-45],
				[18, 18, 0, 0, 0, 35]
			]
			);

			ascent(i in 1..10){
				FireCutinA3(-256, GetStgFrameHeight/2, 15, image, 1 + i/100,
				[
					[18, 18-i/20, 0, 0, 15, 30],
					[0.5, 0.5, 0, 0, 150, 45],
					[0.5, 0.5, 0, 0, 150, 100-45],
					[18, 18, 0, 0, 0, 35]
				],
				BLEND_ADD_ARGB, [190, 144, 213]
				);
			}
		}
		
		else{RaiseError("Not a valid cutin type.");}
		SpellAttackEffect(175);
	}
	
	task SpellAttackEffect(alphamax){
		if(IsSpellAttackAnimation){return;}
		IsSpellAttackAnimation = true;
		let alpha = 1;
		let GetCenterX = GetStgFrameWidth/2;
		let GetCenterY = GetStgFrameHeight/2;
		Octagon(GetCenterX*2, GetCenterY*2, -1.15, 180, 1);
		Octagon(GetCenterX*2, GetCenterY*2, 1.05, 240, 0);
		Octagon(GetCenterX*2, GetCenterY*2, 1.05, 295, 0);
		Octagon(GetCenterX/5, GetCenterY/5, 0.75, 170, 1);
		
		ascent (i in 0..5){
			Line(GetCenterX, GetCenterY+i*75-75-95, 1.5);
		}
		ascent (i in 0..5){
			Line(GetCenterX, GetCenterY+i*75-37.5-95, -1.5);
		}
		
		loop(15){yield;}
		ascent(i in 0..20){
			alpha = 0.1+alphamax/20*i;
			yield;
		}
		loop(110){yield;}
		descent(i in 0..20){
			alpha = alphamax/20*i;
			yield;
		}
		
		IsSpellAttackAnimation = false;
		
		task Line(mx, my, posinc){
			let objSpellAttack = ObjPrim_Create(OBJ_SPRITE_2D);
			ObjRender_SetBlendType(objSpellAttack, BLEND_ALPHA);
			Obj_SetRenderPriority(objSpellAttack, 0.25);
			ObjPrim_SetTexture(objSpellAttack, img_SpellAttack);
			ObjSprite2D_SetSourceRect(objSpellAttack, 0, 0, 512, 16);
			ObjSprite2D_SetDestRect(objSpellAttack, -256, -8, 256, 8);
			let LineX = 0;
			ObjRender_SetPosition(objSpellAttack, mx, my, 0);
			ObjRender_SetAngleZ(objSpellAttack, -35);
			while(alpha>0){
				LineX += posinc;
				ObjSprite2D_SetSourceRect(objSpellAttack, LineX, 0, 512+LineX, 16);
				ObjRender_SetAlpha(objSpellAttack, alpha);
				yield;
			}
			Obj_Delete(objSpellAttack);
		}
	
		task Octagon(mx, my, spininc, dist, size){
		
			let countVertex = 16;
			let listRadius = [];
			loop(countVertex){
				listRadius = listRadius ~ [0];
			}

			let objOutline = ObjPrim_Create(OBJ_PRIMITIVE_2D);
			ObjPrim_SetPrimitiveType(objOutline, PRIMITIVE_TRIANGLESTRIP);
			ObjPrim_SetVertexCount(objOutline, countVertex);
			ObjRender_SetBlendType(objOutline, BLEND_ALPHA);
			Obj_SetRenderPriority(objOutline, 0.75);
			ObjPrim_SetTexture(objOutline, img_SpellAttack);
	
			ascent (iVert in 0..countVertex/2){
				let left = iVert * 128;
				let indexVert = iVert * 2;
				ObjPrim_SetVertexUVT(objOutline, indexVert + 0, left, 0);
				ObjPrim_SetVertexUVT(objOutline, indexVert + 1, left, 16);
			}			
	
			let frame = 0;
			let rRate = 1;
			let spin = 0;
	
			while(alpha>0){
				spin+=spininc;
				VertexSize;
				ObjRender_SetPosition(objOutline, mx, my, 0);
				ObjRender_SetAngleZ(objOutline, spin);
				ObjRender_SetAlpha(objOutline, alpha);
				frame++;
				yield;
			}
			Obj_Delete(objOutline);
			
			task VertexSize{	
				if(frame>=35){return;}
				ascent (iVert in 0..countVertex/2){
					let indexVert = iVert * 2;
					let angle = (360 / (countVertex / 2 - 1) * iVert);

					let vx1 = listRadius[indexVert] * cos(angle);
					let vy1 = listRadius[indexVert] * sin(angle);
					ObjPrim_SetVertexPosition(objOutline, indexVert + 0, vx1, vy1, 0);

					let vx2 = listRadius[indexVert+1] * cos(angle);
					let vy2 = listRadius[indexVert+1] * sin(angle);
					ObjPrim_SetVertexPosition(objOutline, indexVert + 1, vx2, vy2, 0);

					let dr = (dist * rRate - listRadius[indexVert]) / 16;
					listRadius[indexVert] = listRadius[indexVert] + dr;
					if(frame>size){
						listRadius[indexVert + 1] = listRadius[indexVert + 1] + dr;
					}
				}
			}
		}
	}
}

	task FadeInA1(obj, ftime){
	ascent(i in 0..ftime){
		ObjRender_SetAlpha(obj, 255/ftime*i);
		yield;
	}
}
task FadeInB1(obj, alpha, ftime){
	ascent(i in 0..ftime){
		ObjRender_SetAlpha(obj, alpha/ftime*i);
		yield;
	}
}

task FadeOutA1(obj, ftime){
	descent(i in 0..ftime){
		ObjRender_SetAlpha(obj, 255/ftime*i);
		yield;
	}
}

task FadeOutB1(obj, initalpha, ftime){
	descent(i in 0..ftime){
		ObjRender_SetAlpha(obj, initalpha/ftime*i);
		yield;
	}
}



function CreateSimple2DImageA1(pri, image){
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjRender_SetBlendType(obj, BLEND_ALPHA);
	Obj_SetRenderPriority(obj, pri);
	ObjPrim_SetTexture(obj, image);
	let test = [GetTextureWidth(image), GetTextureHeight(image)];
	ObjSprite2D_SetSourceRect(obj, 0, 0, test[0]-1, test[1]-1);
	ObjSprite2D_SetDestRect(obj, -(test[0]/2+0.5), -(test[1]/2), (test[0]/2), (test[1]/2));
	return obj;
}

function CreateSimple2DImageA2(pri, image, x1, y1, x2, y2){
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjRender_SetBlendType(obj, BLEND_ALPHA);
	Obj_SetRenderPriority(obj, pri);
	ObjPrim_SetTexture(obj, image);
	ObjSprite2D_SetSourceRect(obj, x1, y1, x2, y2);
	ObjSprite2D_SetDestCenter(obj);
	return obj;
}


function DigitToArray(digit, count){
	let res = [];
	digit = truncate(digit);

	loop{
		let tnum = truncate(digit % 10);
		digit /= 10;
		res = [tnum] ~ res;
		if(truncate(digit) == 0){break;}
	}

	loop(max(0, count - length(res))){
		res = [0] ~ res;
	}

	return res;
}

function GetNumSize(value){
	if(value<=1){return 1;}
	else{return truncate(log10(value))+1;}
}