#include "./../FunctionData/Function_Info.dnh"
#include "./../FunctionData/Function_Sound.dnh"

let CSD = GetCurrentScriptDirectory;

let objScene = ID_INVALID;

@Event{
	alternative(GetEventType)
	case(EV_START_BOSS_SPELL){
		ActiveThread_SetSpellCard;
	}
	case(EV_GAIN_SPELL){
		PlaySoundA1(SE_CAPTURE);
	}
	case(EV_PLAYER_SHOOTDOWN){
		ActiveThread_SetDeathWave;
	}
}

@Initialize{
	SystemThread_LoadResource;
	SystemThread_SetStgFrame;
	SystemThread_SetStgBorder;
	SystemThread_StepTimer;
	SystemThread_LifeCircle;
	SystemThread_SetBossMarker;
	SystemThread_SetPlayerCounters;
	SystemThread_SetFPS;
	
	SetPauseScriptPath(CSD ~ "./System_Pause.dnh");
}

@MainLoop{
	objScene = GetEnemyBossSceneObjectID;
	if(GetKeyState(KEY_I) == KEY_PUSH) { SetPlayerInvincibilityFrame(60*999); }
	if(GetKeyState(KEY_U) == KEY_PUSH) { SetPlayerInvincibilityFrame(0); }
	yield;
}

//---------------------------------------------------------------------------------
// Resource-Loading Subroutine
//---------------------------------------------------------------------------------

let SYSTEM_ASCII 		= CSD ~ "./../ImageData/ASCIISheet.png";
let	SYSTEM_MESSAGE 		= CSD ~ "./../ImageData/FontSheet.png";
let SYSTEM_SPELLNAME	= CSD ~ "./../ImageData/SpellCard/SpellNames.png";
let EFFECT_INVERSE 		= CSD ~ "./../ImageData/Inverse.png";

let SE_TIMEOUT 		= CSD ~ "./../SoundData/SE/SE_TIMEOUT.wav";
let SE_SPELLBREAK	= CSD ~ "./../SoundData/SE/SE_SPELLBREAK.wav";
let SE_CAPTURE 		= CSD ~ "./../SoundData/SE/SE_CAPTURE.wav";
let SE_FAILURE 		= CSD ~ "./../SoundData/SE/SE_FAILURE.wav";

sub SystemThread_LoadResource{
	LoadTexture(SYSTEM_ASCII);
	LoadTexture(SYSTEM_MESSAGE);
	LoadTexture(SYSTEM_SPELLNAME);
	LoadTexture(EFFECT_INVERSE);
	
	LoadSound(SE_TIMEOUT);
	LoadSound(SE_SPELLBREAK);
	LoadSound(SE_CAPTURE);
	LoadSound(SE_FAILURE);
}

//---------------------------------------------------------------------------------
// Screen Rect Retrieval
//---------------------------------------------------------------------------------

function GetStgFrameArray{
	return [NowMinX,NowMinY,NowMaxX,NowMaxY];
}

//---------------------------------------------------------------------------------
// Centered StgFrame + Border
//---------------------------------------------------------------------------------

task SystemThread_SetStgFrame{
//	STG Frame Initializing -----------------------

	let STG_FRAME = CSD ~ "./../ImageData/StgFrame_Kuda.png";
	SetStgFrame(AbsMinX,AbsMinY,AbsMaxX,AbsMaxY,20,80);
	
// 	STG Frame: Overlay ---------------------------

	let objFrame = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	ObjPrim_SetTexture(objFrame,STG_FRAME);
	Obj_SetRenderPriority(objFrame,0.80);
	ObjRender_SetBlendType(objFrame,BLEND_MULTIPLY);
//	ObjRender_SetAlpha(objFrame,255);
	
	loop{
		let LTRB = GetStgFrameArray;
		StgFrame_Render(objFrame,LTRB[0]-8,LTRB[1]-8,LTRB[2]+8,LTRB[3]+8);
		yield;
	}
	
	function StgFrame_Render(let objTarget, let L, let T, let R, let B){
		ObjSpriteList2D_ClearVertexCount(objTarget);
		
		ObjSpriteList2D_SetSourceRect(objTarget,0,0,L,480);
		ObjSpriteList2D_SetDestRect(objTarget,0,0,L,480);
		ObjSpriteList2D_AddVertex(objTarget);
		
		ObjSpriteList2D_SetSourceRect(objTarget,R,0,640,480);
		ObjSpriteList2D_SetDestRect(objTarget,R,0,640,480);
		ObjSpriteList2D_AddVertex(objTarget);
		
		ObjSpriteList2D_SetSourceRect(objTarget,R,0,L,T);
		ObjSpriteList2D_SetDestRect(objTarget,R,0,L,T);
		ObjSpriteList2D_AddVertex(objTarget);
		
		ObjSpriteList2D_SetSourceRect(objTarget,R,B,L,480);
		ObjSpriteList2D_SetDestRect(objTarget,R,B,L,480);
		ObjSpriteList2D_AddVertex(objTarget);
	}
}

task SystemThread_SetStgBorder{
	let W = 4;

	let objBorder = ObjPrim_Create(OBJ_PRIMITIVE_2D);
	ObjPrim_SetPrimitiveType(objBorder,PRIMITIVE_TRIANGLESTRIP);
	ObjPrim_SetVertexCount(objBorder,10);
	Obj_SetRenderPriority(objBorder,0.81);
	ObjRender_SetBlendType(objBorder,BLEND_INV_DESTRGB);
	ObjRender_SetColor(objBorder,192,192,192);
	
//	let tY = 0;
	while(!Obj_IsDeleted(objBorder)){
		let LTRB = GetStgFrameArray;
		ObjPrim_SetVertexPosition(objBorder,0,(LTRB[0]-W*2)  ,(LTRB[1]-W*2)  ,0);
		ObjPrim_SetVertexPosition(objBorder,1,(LTRB[0]-W*2)+W,(LTRB[1]-W*2)+W,0);
		ObjPrim_SetVertexPosition(objBorder,2,(LTRB[2]+W*2)  ,(LTRB[1]-W*2)  ,0);
		ObjPrim_SetVertexPosition(objBorder,3,(LTRB[2]+W*2)-W,(LTRB[1]-W*2)+W,0);
		ObjPrim_SetVertexPosition(objBorder,4,(LTRB[2]+W*2)  ,(LTRB[3]+W*2)  ,0);
		ObjPrim_SetVertexPosition(objBorder,5,(LTRB[2]+W*2)-W,(LTRB[3]+W*2)-W,0);
		ObjPrim_SetVertexPosition(objBorder,6,(LTRB[0]-W*2)  ,(LTRB[3]+W*2)  ,0);
		ObjPrim_SetVertexPosition(objBorder,7,(LTRB[0]-W*2)+W,(LTRB[3]+W*2)-W,0);
		ObjPrim_SetVertexPosition(objBorder,8,(LTRB[0]-W*2)  ,(LTRB[1]-W*2)  ,0);
		ObjPrim_SetVertexPosition(objBorder,9,(LTRB[0]-W*2)+W,(LTRB[1]-W*2)+W,0);
		/*
		ascent(let vtCount in 0..5){
			ObjPrim_SetVertexUVT(objBorder,2*vtCount,vtCount*8,tY);
			ObjPrim_SetVertexUVT(objBorder,2*vtCount+1,vtCount*8,tY+W);
		}
		tY = modc(tY+0.25,32);
		*/
		yield;
	}
}

//---------------------------------------------------------------------------------
// Boss Step Timer
//---------------------------------------------------------------------------------

task SystemThread_StepTimer{
	let objTimer = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	ObjPrim_SetTexture(objTimer,SYSTEM_ASCII);
	ObjRender_SetY(objTimer,MinY);
	Obj_SetRenderPriority(objTimer,0.72);
	ObjRender_SetScaleXYZ(objTimer,0.80,0.80,0.00);
	
	let objFrame = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	ObjPrim_SetTexture(objFrame,SYSTEM_ASCII);
	ObjRender_SetY(objFrame,MinY+8);
	Obj_SetRenderPriority(objFrame,0.72);
	ObjRender_SetScaleXYZ(objFrame,0.80,0.80,0.00);
	
	let BeforeTime = ObjEnemyBossScene_GetInfo(objScene,INFO_TIMERF);
	StepTimer_Control;
	StepTimer_Spell;
	loop{
		let StepTime = ObjEnemyBossScene_GetInfo(objScene,INFO_TIMER);
		let FrameTime = modc(ObjEnemyBossScene_GetInfo(objScene,INFO_TIMERF),60);
		if(StepTime > 99){ FrameTime = 60; }
		ObjSpriteList2D_ClearVertexCount(objTimer);
		ObjSpriteList2D_ClearVertexCount(objFrame);
		if(objScene != ID_INVALID){
			StepTimer_Seconds(min(StepTime,99));
			StepTimer_Frames(FrameTime);
		}
		if(GetCommonData("IS_TIMESTOP",false)){
			ObjEnemyBossScene_SetSpellTimer(objScene,BeforeTime);
		}else{
			BeforeTime = ObjEnemyBossScene_GetInfo(objScene,INFO_TIMERF);
		}
		yield;
	}
	
	task StepTimer_Control{
		loop{
			let StepTime = ObjEnemyBossScene_GetInfo(objScene,INFO_TIMERF);
			if(StepTime/60 <= 11 && objScene != ID_INVALID){
				if(!modc(StepTime+1,60) && StepTime > 0){
					PlaySoundA1(SE_TIMEOUT);
				}
				if(StepTime/60 < 4){
					ObjRender_SetColor(objTimer,255,64,64);
					ObjRender_SetColor(objFrame,255,64,64);
				}else{
					ObjRender_SetColor(objTimer,255,128,128);
					ObjRender_SetColor(objFrame,255,128,128);
				}
			}else{
				ObjRender_SetColor(objTimer,255,255,255);
				ObjRender_SetColor(objFrame,255,255,255);
			}
			yield;
		}
	}

	function StepTimer_Seconds(StepTime){
		let listArray = dtoa(StepTime,2);
		ObjSpriteList2D_ClearVertexCount(objTimer);
		ascent(let a in 0..2){
			let listNum = listArray[a];
			ObjRender_SetX(objTimer,(CenX-32)+a*16);
			ObjSpriteList2D_SetSourceRect(objTimer,listNum*24,216,(listNum+1)*24,240);
			ObjSpriteList2D_SetDestRect(objTimer,0,0,24,24);
			ObjSpriteList2D_AddVertex(objTimer);
		}
		ObjRender_SetX(objTimer,(CenX-32)+29);
		ObjSpriteList2D_SetSourceRect(objTimer,11*24,216,12*24,240);
		ObjSpriteList2D_SetDestRect(objTimer,0,0,24,24);
		ObjSpriteList2D_AddVertex(objTimer);
	}
	
	function StepTimer_Frames(FrameTime){
		let listArray = dtoa(FrameTime,2);
		ObjSpriteList2D_ClearVertexCount(objFrame);
		ascent(let a in 0..2){
			let listNum = listArray[a];
			ObjRender_SetX(objFrame,((CenX-32)+42)+a*10);
			ObjSpriteList2D_SetSourceRect(objFrame,listNum*12,192,(listNum+1)*12,208);
			ObjSpriteList2D_SetDestRect(objFrame,0,0,12,16);
			ObjSpriteList2D_AddVertex(objFrame);
		}
	}
	
	task StepTimer_Spell{
		let maxCount = 90;
		loop{
			while(!ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){ 
				ObjRender_SetY(objTimer,NowMinY);
				ObjRender_SetY(objFrame,NowMinY+8);
				yield;
			}
			if(ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){
				let pY1 = ObjRender_GetY(objTimer);
				let pY2 = ObjRender_GetY(objFrame);
				let rY1 = (NowMinY+40)-pY1;
				let rY2 = (NowMinY+40+8)-pY2;
				let sinRate = 90/maxCount;
				ascent(let a in 1..maxCount+1){
					ObjRender_SetY(objTimer,GetGapY(pY1,rY1,a*sinRate));
					ObjRender_SetY(objFrame,GetGapY(pY2,rY2,a*sinRate));
					if(!ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){ break; }
					yield;
				}
			}
			while(ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){ 
				ObjRender_SetY(objTimer,NowMinY+40);
				ObjRender_SetY(objFrame,NowMinY+40+8);
				yield;
			}
			if(!ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){
				let pY1 = ObjRender_GetY(objTimer);
				let pY2 = ObjRender_GetY(objFrame);
				let rY1 = (NowMinY)-pY1;
				let rY2 = (NowMinY+8)-pY2;
				let sinRate = 90/maxCount;
				ascent(let a in 1..maxCount+1){
					ObjRender_SetY(objTimer,GetGapY(pY1,rY1,a*sinRate));
					ObjRender_SetY(objFrame,GetGapY(pY2,rY2,a*sinRate));
					if(ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)){ break; }
					yield;
				}
			}
			yield;
		}
	}
}

//---------------------------------------------------------------------------------
// Boss Life Circle (Extra Boss Rush)
//---------------------------------------------------------------------------------

task SystemThread_LifeCircle{
	let SYSTEM_LIFEBAR = CSD ~ "./../ImageData/LifeCircle.png";
	let SYSTEM_DELIMIT = CSD ~ "./../ImageData/BossLife.png";

	let objLife = [];
	let g_way = 24;

	let lastRemStep = -1;
	let lifeRateRender = 0;
	
	let objLim = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	ObjPrim_SetTexture(objLim, SYSTEM_DELIMIT);
	Obj_SetRenderPriority(objLim, 0.69);

	let fadeAlpha = 255;
	loop{
		ObjSpriteList2D_ClearVertexCount(objLim);
		let LifeLength = length(objLife);
		if(objScene != ID_INVALID && !ObjEnemyBossScene_GetInfo(objScene, INFO_IS_DURABLE_SPELL)){
			if(LifeLength <= 0){
				CreateLifeGauge;
			}
			RenderLife;
		}else{
			if(LifeLength > 0){
				descent(i in 0 .. LifeLength){
					Obj_Delete(objLife[i]);
				}
				objLife = [];
			}
		}
		if(LifeLength > 0 && length(GetEnemyBossObjectID) > 0){
			let objBoss = GetEnemyBossObjectID[0];
			let ex = ObjRender_GetX(objBoss);
			let ey = ObjRender_GetY(objBoss);
			let pDist = GetDistance(GetPlayerX,GetPlayerY,ex,ey);
			if(pDist < 96){
				if(fadeAlpha > 64){
					fadeAlpha -= (255-64)/20;
				}
				ObjRender_SetAlpha(objLim,fadeAlpha);
				ObjRender_SetAlpha(objLife[1],fadeAlpha);
				ObjRender_SetColor(objLife[0],fadeAlpha,fadeAlpha,fadeAlpha);
			}else{
				if(fadeAlpha < 255){
					fadeAlpha += (255-64)/20;
				}
				ObjRender_SetAlpha(objLim,fadeAlpha);
				ObjRender_SetAlpha(objLife[1],fadeAlpha);
				ObjRender_SetColor(objLife[0],fadeAlpha,fadeAlpha,fadeAlpha);
			}
		}
		yield;
	}
	
	function CreateLifeGauge{
		objLife = objLife ~ [ObjPrim_Create(OBJ_PRIMITIVE_2D), ObjPrim_Create(OBJ_PRIMITIVE_2D)];
		ascent(j in 0 .. length(objLife)){
			ObjPrim_SetTexture(objLife[j],SYSTEM_LIFEBAR);
			Obj_SetRenderPriority(objLife[j],0.68);
			ObjPrim_SetVertexCount(objLife[j], g_way+2);
			ObjPrim_SetPrimitiveType(objLife[j], PRIMITIVE_TRIANGLEFAN);
			ObjPrim_SetVertexUVT(objLife[j], 0, 128+256*j, 384);
			ascent(i in 0 .. g_way+1){
				ObjPrim_SetVertexUVT(objLife[j], i+1,128+256*j+128*cos(360*i/g_way), 384+128*sin(360*i/g_way));
			}
			ObjRender_SetAlpha(objLife[j], 255);
		}
		ObjRender_SetBlendType(objLife[0],BLEND_INV_DESTRGB);
		ObjRender_SetColor(objLife[1],255,0,0);
	}

	function RenderLife{
		if(length(GetEnemyBossObjectID()) <= 0){ return; }
		let objBoss = GetEnemyBossObjectID()[0];
		let ex = ObjRender_GetX(objBoss);
		let ey = ObjRender_GetY(objBoss);
		
		let countRemStep = ObjEnemyBossScene_GetInfo(objScene, INFO_REMAIN_STEP_COUNT);
		if(lastRemStep != countRemStep){
			lifeRateRender = 0;
		}

		let lifeTotalMax = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_TOTAL_MAX_LIFE);
		let lifeTotal = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_TOTAL_LIFE);
		let lifeRate = min((lifeTotal-1) / (lifeTotalMax-1), lifeRateRender);

		RenderLifeGauge;
		
		// Life Step Delimiter
		ObjSpriteList2D_SetSourceRect(objLim, 19, -1, 27, 14);
		let listLifeDiv = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_LIFE_RATE_LIST);
		ascent(iDiv in 0 .. length(listLifeDiv)){
			let rate = listLifeDiv[iDiv];
			let angle = -360 * (1-rate);
			ObjSpriteList2D_SetDestRect(objLim, -4, -7, 4, 7);
			ObjRender_SetAngleZ(objLim, angle);
			let pX = GetGapX(ex,68,angle-90);
			let pY = GetGapY(ey,68,angle-90);
			ObjRender_SetX(objLim, pX);
			ObjRender_SetY(objLim, pY);
			ObjSpriteList2D_AddVertex(objLim);
		}

		lifeRateRender += 0.02;
		lifeRateRender = min(lifeRateRender, 1);
		lastRemStep = countRemStep;
		
		function RenderLifeGauge{
			ascent(j in 0 .. length(objLife)){
				ObjRender_SetAlpha(objLife[j], 255);
				ObjRender_SetX(objLife[j], ex);
				ObjRender_SetY(objLife[j], ey);
				ObjPrim_SetVertexPosition(objLife[j], 0, 0, 0, 0);
			}
			ascent(i in 0 .. g_way+1){
				ObjPrim_SetVertexPosition(objLife[0], i+1, -128*sin(360*i/g_way * lifeRate), -128*cos(360*i/g_way * lifeRate), 0);
				ObjPrim_SetVertexPosition(objLife[1], i+1, -128*sin(360*i/g_way * lifeRateRender), -128*cos(360*i/g_way * lifeRateRender), 0);
			}
		}
	}
}

//---------------------------------------------------------------------------------
// Boss Marker
//---------------------------------------------------------------------------------

task SystemThread_SetBossMarker{
	let objMarker = ObjPrim_Create(OBJ_SPRITE_2D);
	
	ObjPrim_SetTexture(objMarker,SYSTEM_ASCII);
	Obj_SetRenderPriority(objMarker,0.81);
	ObjRender_SetPosition(objMarker,-32,-32,0);
//	ObjRender_SetBlendType(objMarker,BLEND_ADD_ARGB);
//	ObjRender_SetColor(objMarker,255,0,0);
	
	ObjRender_SetScaleXYZ(objMarker,0.75,0.75,0);
	ObjSprite2D_SetSourceRect(objMarker,315,360,384,384);
	ObjSprite2D_SetDestCenter(objMarker);
	
	yield;
	let fadeAlpha = 0;
	let objBoss = GetEnemyBossObjectID;
	loop{
		while(objBoss == [ID_INVALID]){
			objBoss = GetEnemyBossObjectID;
			yield;
		}
		let oX = ObjMove_GetX(objBoss[0]);
		ObjRender_SetPosition(objMarker,oX,NowMaxY+16,0);
		if(oX < MinX || oX > MaxX){
			if(fadeAlpha > 0){
				fadeAlpha -= 255/15;
			}
		}else if(fadeAlpha < 255){
			fadeAlpha += 255/15;
		}
		ObjRender_SetAlpha(objMarker,fadeAlpha);
		yield;
	}
}

//---------------------------------------------------------------------------------
// Life/Bomb Display
//---------------------------------------------------------------------------------

task SystemThread_SetPlayerCounters{
	let SYSTEM_RESOURCE_HEADER	= CSD ~ "./../ImageData/LifeHeader.png";
	let SYSTEM_RESOURCE_ICON 	= CSD ~ "./../ImageData/LifeIcon.png";

	SubThread_SetLifeCounter;
	SubThread_SetBombCounter;
	SubThread_SetGrazeCounter;
	
	task SubThread_SetLifeCounter{
	//	Life Header Object ---------------------------

		let objHeader = ObjPrim_Create(OBJ_SPRITE_2D);
		
		ObjPrim_SetTexture(objHeader,SYSTEM_RESOURCE_HEADER);
		Obj_SetRenderPriority(objHeader,0.70);
		ObjRender_SetScaleXYZ(objHeader,0.50,0.50,0.00);
		ObjSprite2D_SetSourceRect(objHeader,0,72,144,108);
		ObjSprite2D_SetDestCenter(objHeader);

	//	Life Counter Object --------------------------
		
		let objLife = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
		
		ObjPrim_SetTexture(objLife,SYSTEM_RESOURCE_ICON);
		Obj_SetRenderPriority(objLife,0.70);
		ObjRender_SetScaleXYZ(objLife,0.50,0.50,0.00);
		
		let LIFE_MAX = 5;
		let LIFE_PLAYER = GetPlayerLife;
		let fadeAlpha = 255;
		loop{
			let pX = NowMinX+68;
			let pY = NowMaxY-24;
			if(GetPlayerLife != LIFE_PLAYER){
				LIFE_PLAYER = min(GetPlayerLife,5);
			}
			ObjRender_SetPosition(objHeader,NowMinX+36,NowMaxY-24,0);
			ObjSpriteList2D_ClearVertexCount(objLife);
			ascent(let i in 0..LIFE_PLAYER){
				ObjRender_SetPosition(objLife,pX+i*16,pY,0);
				ObjSpriteList2D_SetSourceRect(objLife,160,0,192,32);
				ObjSpriteList2D_SetDestCenter(objLife);
				ObjSpriteList2D_AddVertex(objLife);
			}
			ascent(let j in max(0,LIFE_PLAYER)..LIFE_MAX){
				ObjRender_SetPosition(objLife,pX+j*16,pY,0);
				ObjSpriteList2D_SetSourceRect(objLife,0,0,32,32);
				ObjSpriteList2D_SetDestCenter(objLife);
				ObjSpriteList2D_AddVertex(objLife);
			}
			if(GetPlayerX < NowMinX+152 && GetPlayerY > NowMaxY-48){
				if(fadeAlpha > 64){
					fadeAlpha -= (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objLife,fadeAlpha);
			}else{
				if(fadeAlpha < 255){
					fadeAlpha += (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objLife,fadeAlpha);
			}
			yield;
		}
	}
	
	task SubThread_SetBombCounter{
	//	Bomb Header Object ---------------------------
	
		let objHeader = ObjPrim_Create(OBJ_SPRITE_2D);
		
		ObjPrim_SetTexture(objHeader,SYSTEM_RESOURCE_HEADER);
		Obj_SetRenderPriority(objHeader,0.70);
		ObjRender_SetScaleXYZ(objHeader,0.50,0.50,0.00);
		ObjSprite2D_SetSourceRect(objHeader,144,0,288,36);
		ObjSprite2D_SetDestCenter(objHeader);
		
	//	Bomb Counter Object --------------------------
		
		let objBomb = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
		
		ObjPrim_SetTexture(objBomb,SYSTEM_RESOURCE_ICON);
		Obj_SetRenderPriority(objBomb,0.70);
		ObjRender_SetScaleXYZ(objBomb,0.50,0.50,0.00);
		
		let BOMB_MAX = 5;
		let BOMB_PLAYER = GetPlayerSpell;
		let fadeAlpha = 255;
		loop{
			let pX = NowMinX+68;
			let pY = NowMaxY-8;
			if(GetPlayerSpell != BOMB_PLAYER){
				BOMB_PLAYER = min(GetPlayerSpell,5);
			}
			ObjRender_SetPosition(objHeader,NowMinX+36,NowMaxY-8,0);
			ObjSpriteList2D_ClearVertexCount(objBomb);
			ascent(let i in 0..BOMB_PLAYER){
				ObjRender_SetPosition(objBomb,pX+i*16,pY,0);
				ObjSpriteList2D_SetSourceRect(objBomb,160,32,192,64);
				ObjSpriteList2D_SetDestCenter(objBomb);
				ObjSpriteList2D_AddVertex(objBomb);
			}
			ascent(let j in max(0,BOMB_PLAYER)..BOMB_MAX){
				ObjRender_SetPosition(objBomb,pX+j*16,pY,0);
				ObjSpriteList2D_SetSourceRect(objBomb,0,32,32,64);
				ObjSpriteList2D_SetDestCenter(objBomb);
				ObjSpriteList2D_AddVertex(objBomb);
			}
			if(GetPlayerX < NowMinX+152 && GetPlayerY > NowMaxY-48){
				if(fadeAlpha > 64){
					fadeAlpha -= (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objBomb,fadeAlpha);
			}else{
				if(fadeAlpha < 255){
					fadeAlpha += (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objBomb,fadeAlpha);
			}
			yield;
		}
	}
	
	task SubThread_SetGrazeCounter{
	//	Graze Header Object ----------------------
	
		let objHeader = ObjPrim_Create(OBJ_SPRITE_2D);
		
		ObjPrim_SetTexture(objHeader,SYSTEM_RESOURCE_HEADER);
		Obj_SetRenderPriority(objHeader,0.70);
		ObjRender_SetScaleXYZ(objHeader,0.50,0.50,0.00);
		ObjSprite2D_SetSourceRect(objHeader,144+27,36,288,72);
		ObjSprite2D_SetDestCenter(objHeader);
	
	// Graze Counter Object ----------------------
	
		let objGraze = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
		
		ObjPrim_SetTexture(objGraze,SYSTEM_ASCII);
		Obj_SetRenderPriority(objGraze,0.70);
		ObjRender_SetScaleXYZ(objGraze,0.75,0.75,0.00);
		ObjRender_SetColor(objGraze,192,192,192);
		
		let fadeAlpha = 255;
		loop{
			let GRAZE_COUNT = min(GetGraze,9999);
			let listArray = dtoa(GRAZE_COUNT,4);
			ObjRender_SetPosition(objHeader,NowMaxX-16,NowMaxY-24,0);
			ObjSpriteList2D_ClearVertexCount(objGraze);
			ascent(let a in 0..4){
				let listNum = listArray[a];
				ObjRender_SetPosition(objGraze,NowMaxX-56+a*16,NowMaxY-8,0);
				ObjSpriteList2D_SetSourceRect(objGraze,listNum*24,216,(listNum+1)*24,240);
				ObjSpriteList2D_SetDestCenter(objGraze);
				ObjSpriteList2D_AddVertex(objGraze);
			}
			if(GetPlayerX > NowMaxX-72 && GetPlayerY > NowMaxY-48){
				if(fadeAlpha > 64){
					fadeAlpha -= (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objGraze,fadeAlpha);
			}else{
				if(fadeAlpha < 255){
					fadeAlpha += (255-64)/15;
				}
				ObjRender_SetAlpha(objHeader,fadeAlpha);
				ObjRender_SetAlpha(objGraze,fadeAlpha);
			}
			yield;
		}
	}
}

//---------------------------------------------------------------------------------
// FPS Counter
//---------------------------------------------------------------------------------

task SystemThread_SetFPS{
	let objFPS = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	ObjPrim_SetTexture(objFPS,SYSTEM_ASCII);
	Obj_SetRenderPriority(objFPS,0.81);
	
//	let aX = [560-4,572-4,590-4,602-4];
	let aX = [0,12,12+10+8,12+10+8+12];
	let pX = (NowMaxX+52);
	let pY = NowMaxY;
	let fadeFlag = true;
	loop{
		let FPSCount = GetCurrentFps*1000;
		let listArray = dtoa(FPSCount,4);
		pX = (NowMaxX+52);
		pY = NowMaxY;
		if(NowMaxX > AbsMaxX-16){
			pX = AbsMinX+57;
			pY = MinY;
			if(fadeFlag){
				ObjRender_FadeInNewPosition(objFPS);
				fadeFlag = false;
			}
		}
		ObjSpriteList2D_ClearVertexCount(objFPS);
		ascent(let a in 0..length(aX)){
			let listNum = listArray[a];
			ObjRender_SetPosition(objFPS,pX+aX[a],pY,0);
			ObjSpriteList2D_SetSourceRect(objFPS,listNum*12,192,(listNum+1)*12,208);
			ObjSpriteList2D_SetDestCenter(objFPS);
			ObjSpriteList2D_AddVertex(objFPS);
		}
		local{
			ObjRender_SetPosition(objFPS,pX+12+10,pY,0);
			ObjSpriteList2D_SetSourceRect(objFPS,15*12,192,16*12,208);
			ObjSpriteList2D_SetDestCenter(objFPS);
			ObjSpriteList2D_AddVertex(objFPS);
		}
		yield;
	}
	
	task ObjRender_FadeInNewPosition(let objTarget){
		ObjRender_SetAlpha(objTarget,0);
		wait(10);
		ascent(let a in 1..31){
			let addAlpha = a*255/30;
			ObjRender_SetAlpha(objTarget,addAlpha);
			yield;
		}
	}
}

//---------------------------------------------------------------------------------
// Spell Card Setup
//---------------------------------------------------------------------------------

task ActiveThread_SetSpellCard{
	let objLine = ObjPrim_Create(OBJ_SPRITE_2D);

	ObjPrim_SetTexture(objLine,SYSTEM_ASCII);
	Obj_SetRenderPriority(objLine,0.71);
	ObjRender_SetPosition(objLine,NowMaxX-152,NowMaxY-48,0);
	ObjSprite2D_SetSourceRect(objLine,0,290,384,354);
	ObjSprite2D_SetDestCenter(objLine);

	let objName = ObjPrim_Create(OBJ_SPRITE_2D);

	ObjPrim_SetTexture(objName,SYSTEM_SPELLNAME);
	Obj_SetRenderPriority(objName,0.72);
	ObjRender_SetPosition(objName,NowMaxX-152,NowMaxY-48,0);
	local{
		let SpellCardID = GetCommonData("Spell_Number",0);
		let T = 1+(SpellCardID-1)*32;
		let B = SpellCardID*32;
		ObjSprite2D_SetSourceRect(objName,1,T,384,B);
	}
	ObjSprite2D_SetDestCenter(objName);
	
	let objArray = [objLine,objName];
	
	let fadeTime = 30;
	ascent(a in 1..fadeTime+1){
		let decScale = 0.75+(fadeTime-a)*(1.25-0.75)/fadeTime;
		let addAlpha = a*255/fadeTime;
		ascent(let i in 0..length(objArray)){
			ObjRender_SetPosition(objArray[i],NowMaxX-152,NowMaxY-48,0);
			ObjRender_SetScaleXYZ(objArray[i],decScale,decScale,0);
			ObjRender_SetAlpha(objArray[i],addAlpha);
		}
		yield;
	}
	loop(30){
		ascent(let i in 0..length(objArray)){
			ObjRender_SetPosition(objArray[i],NowMaxX-152,NowMaxY-48,0);
		}
		yield;
	}
	let mvTime = 60;
	let sinRate = 90/mvTime;
	ascent(a in 1..mvTime+1){
		let mY = GetGapY(NowMaxY-48,(NowMinY+16)-(NowMaxY-48),a*sinRate);
		ascent(let i in 0..length(objArray)){
			ObjRender_SetPosition(objArray[i],NowMaxX-152,mY,0);
		}
		yield;
	}
	while(ObjEnemyBossScene_GetInfo(objScene,INFO_ACTIVE_STEP_TOTAL_LIFE) > 0){
		ascent(let i in 0..length(objArray)){
			ObjRender_SetPosition(objArray[i],NowMaxX-152,NowMinY+16,0);
		}
		yield; 
	}
	PlaySoundA1(SE_SPELLBREAK);
	let oX = NowMaxX-152;
	loop(mvTime){
		oX += 10;
		ascent(let i in 0..length(objArray)){
			ObjRender_SetX(objArray[i],oX);
		}
		yield;
	}
	Obj_Delete(objLine);
}

//---------------------------------------------------------------------------------
// Player Death Wave
//---------------------------------------------------------------------------------

task ActiveThread_SetDeathWave{
	let sX = GetPlayerX;
	let sY = GetPlayerY;
	ascent(let agCount in 0..4){
		let pX = GetGapX(sX,48,agCount*90);
		let pY = GetGapY(sY,48,agCount*90);
		SetInverseWave(pX,pY,32,120);
	}
	ascent(let ccCount in 0..2){
		SetInverseWave(sX,sY,(32+16)-ccCount*16,120-ccCount*20);
		wait(20);
	}
	wait(25);
	loop(30){
		let objArray = GetShotIdInCircleA2(CenX,CenY,768,TARGET_ENEMY);
		ascent(let i in 0..length(objArray)){
			if(!ObjShot_IsSpellResist(objArray[i])){
				Obj_Delete(objArray[i]);
			}
		}
		yield;
	}
	
	task SetInverseWave(let pX, let pY, let maxSpeed, let maxCount){
		let objInv = ObjInverse_SetProperties;
		ObjRender_SetPosition(objInv,pX,pY,0);
		
		let expValue = 0;
		let waveSpeed = 0;
		loop(maxCount){
			ObjRender_SetScaleXYZ(objInv,expValue/512,expValue/512,0);
			expValue += waveSpeed;
			if(waveSpeed < maxSpeed){
				waveSpeed += maxSpeed/(45-1);
			}else{
				waveSpeed = maxSpeed;
			}
			yield;
		}
		Obj_Delete(objInv);
	}
	
	function ObjInverse_SetProperties{
		let objInv = ObjPrim_Create(OBJ_SPRITE_2D);
		
		ObjPrim_SetTexture(objInv,EFFECT_INVERSE);
		Obj_SetRenderPriority(objInv,0.69);
		ObjRender_SetBlendType(objInv,BLEND_INV_DESTRGB);
		ObjSprite2D_SetSourceRect(objInv,0,0,512,512);
		ObjSprite2D_SetDestCenter(objInv);
		
		return objInv;
	}
}

//---------------------------------------------------------------------------------
// Digit-To-Array Function
//---------------------------------------------------------------------------------

function dtoa(let numValue, let ccLength){
	let resArray = [];
	numValue = truncate(numValue);

	while(truncate(numValue) != 0){
		let arNum = truncate(numValue%10);
		numValue /= 10;
		resArray = concatenate([arNum],resArray);
	}
	loop(max(0,ccLength-length(resArray))){
		resArray = concatenate([0],resArray);
	}

	return resArray;
}