//***************************************************************************************************
//	Touhou Hou Enbu system file
//	Author: Helepolis
//	Version: 3.0
//
//	The great tracking script for handling effects, animations and such during boss fights
//	Has unique behaviour for each game mode: Stage play, training, single spell training.
//
//
//	Explanation:
//	This script is booted during the game is always running in the background 
//	Threads which need to idle or be held are set to ID_INVALID to avoid game throwing errors
//	This method has been chosen because ph3 has awkward method of handling post-attack routine
//	Be aware that this system script is very big but follows roughly the Rumia example in ph3 original
//	
//  Threads:
//		@Initialize						- Initialize
//		@MainLoop						- Updates x/y coordinates as long as the boss lives
//		@Event							- Complex events for effects
//		
//
//	Library:
//		bossFunkyCircle					- Spawns the boss funky circles. Called in @Event. Is separate script (function_spellcircle.txt).
//		bossMagicCircle					- Red magic circle handler. Uses SetCommonData("bossCircleType",<value>); for setting types.
//		breakEffect						- Function to summon the glitter explosion for funky circle.
//		breakEffectGlitter				- Handles the glitters for funky circle and custom.
//		diffFlash						- Animation task for the Difficulty sprite. Is called from hudStatics. 
//		distortCirc						- Handles distortion animation for red magic circle when spell card breaks. 
//		explosioncustom					- Creates a circular explosion using maple leaf.
//		explosionspray					- Creates a directional spray of maple going 360 degrees around.
//		GetCenterX						- Gets the centre X value of the game field.
//		GetCenterY						- Gets the centre Y value of the game field.
//		GetClipMaxX						- Gets the maximum X value of the game field.
//		GetClipMaxY						- Gets the maximum Y value of the game field.
//		GetClipMinX						- Gets the minimum X value of the game field (usually 0).
//		GetClipMinY						- Gets the minimum Y value of the game field (usually 0).
//		GetDistanceXY					- Gets the distance between two given points.
//		GetEnemyX						- Gets the X position of the boss.
//		GetEnemyY						- Gets the Y position of the boss.
//		GetPointToPointAngle			- Gets the angle between two given points.
//		GetTimer						- Retrieves the timer.
//		hudBallGlitter					- Creates glitters around the mirror ball on the HUD (bottom right corner)
//		hudFever						- Draws and handles the current and required fever counter. Animates the treasure icon upon meeting requirements.
//		hudFPS							- Draws and handles the FPS counter.
//		hudGraze						- Draws and handles the graze counter.
//		hudGlitter						- Task which defines and handles the glitters for the HUD. Similar code to the break effect glitters.
//		hudHighScore					- Draws and handles the highscore counter.
//		hudLife							- Draws and handles the life hearts.
//		hudPIV							- Draws and handles the PIV.
//		hudScore						- Draws and handles the current score counter.
//		hudSkin							- Draws the HUD background image.
//		hudSpell						- Draws and handles the bomb stars.
//		hudSpellInfo					- Draws and handles the Spell Card text.
//		hudSpellTimer					- Draws and handles the Spell Card timer. 
//		hudStatics						- Draws all static sprite images such as 'Spell' 'Life' (In Japanese).
//		hudStripes						- Draws one-time animating sprites as decoration. 
//		locateBossID					- Relocate bossID for Obj listeners to work proper. Checks whether it is a duet card or not for second ID. 
//		mapleexplo						- Handles the maple sprites for the explosion.
//		miniCardGlitter					- Draws and handles the glitters for the mini spell card.
//		ObjMove_Special					- Special movement rendering for objects when ObjMove isn't sufficient. 
//		ouchSFX							- Handles the getting hit sound for the boss. Below 10% of max HP it plays the 'almost dead' sound.
//		ouchSFX2						- Handles the getting hit sound for second boss (duet). Below 10% of max HP it plays the 'almost dead' sound.
//		pieceHUD						- Function to draw a specific sprite from the menu_items.png. 
//		rand_int						- Returns a truncated random number. Self made ph3 implementation of 0.12m's rand_int. 
//		renderBG						- Renders the background for spellcard attacks. Uses SetCommonData("bossBgType",<value>); for setting types.
//		showBulletCol					- Shows collision for all bullets in the game. Can be toggled on/off. Be aware that lots of bullets can cause huge FPS drop. 
//										  Use it only for testing briefly instead of letting it run the entire game. [Created by Drake].
//
//		TBossLife						- Draws and handles the life bar including phases. [Created by Drake].
//		timerSFX						- Plays the 'almost out of spell card time' warning sound. 
//		updateCardCapture				- When spell card is captured in the game, updates the counter. (Practise & Story mode are separate) 
//		updateCardHistory				- Keeps track of the number of times the player has attempted or seen this spell card. (Practise & Story mode are separate) 
//		wait							- Where called, yields the thread. Can take in a parameter for yielding N-frames.
//
//***************************************************************************************************

// Essential variables
let bossObj = ID_INVALID;
let boss2Obj = ID_INVALID;  
let bossX = 0;
let bossY = 0;
let boss2X = 0;
let boss2Y = 0;
SetCommonData("boss2X",0); 								// dirty fix for X/Y tracking
SetCommonData("boss2Y",0); 
let getResultCard = "";									// In order to communicate with spell cards for history / capture.

// Step vars
let isDuetCard = GetCommonData("isDuet", false);
let isBossFight = false;								// Tracks whether a boss fight is currently going on or not.
let isTimedOut = false;									// Tracks whether the spell card was timed out.		
let alreadyMagicCirc = false;							// Tracks whether there is already a magic circle present. 
SetCommonData("cardTracker",0);							// Card tracker 		
SetCommonData("needNumCards",0);						// Required cards for meeting conditions
SetCommonData("numCardsCaptured",0);					// Number of cards captured
SetCommonData("mainPlural",false);						// Tracker for main plural

// spell card related var
let isPichuun = false;									// Required to decide if a spell bonus failed or not.
let infoAnimOnce = false;

// Vars to define the boss circle / bg
SetCommonData("bossAttackType",0);						// 0 = no attack, 1 = nonspell, 2 = spellcard
SetCommonData("bossCircleType",0);						// 0 = red circle, 1 = ballerina, 2 = afro, 3 = dj
SetCommonData("bossBgType",0);							// 1 = ballbg, 2 = afrobg, 3 = djbg 
	
// Variables for animating the magic circle
let circblur = 0;
let circblur2 = 0;

// Variables for treasure image
let hasUnlockedTreasure = false;

#include "script/thdcs/functions/function_loaddata.txt"
#include "script/thdcs/functions/function_cutin.txt"
#include "script/thdcs/functions/const_sound.txt"

@Initialize {
	SetAutoDeleteObject(true);	
	
	// Main HUD
	hudSkin();		
	hudBallGlitter(); 
	hudStripes(520,60,128,128,128,0);		// highscore
	hudStripes(520,84,255,255,128,10);		// score
	hudStripes(520,120,255,128,128,20);		// lives
	hudStripes(520,158,128,255,128,30);		// spells
	hudStripes(520,190,128,128,255,40);		// piv
	hudStripes(520,220,128,128,128,50);		// graze
	hudStripes(520,250,255,64,255,60);		// fever
	hudStatics();
	hudHighScore();
	hudScore();
	hudLife();
	hudSpell();	
	hudPIV();
	hudGraze();
	hudFever();
	miniSpellCardDraw();
	
	// Boss related HUDs
	TBossLife();
	hudSpellTimer();
	hudSpellInfo();
	timerSFX();

	// Core related HUDs
	hudFPS();
	ouchSFX();
	ouch2SFX();

	bossMagicCircle();

	grazeBonusHandler();
	
	// Other useful 
	//showBulletCol;
}

@MainLoop {
	if(isBossFight) {
		if(!Obj_IsDeleted(bossObj)) {
			bossX = ObjMove_GetX(bossObj);
			bossY = ObjMove_GetY(bossObj);
			if(isDuetCard) {
				boss2X = ObjMove_GetX(boss2Obj);
				boss2Y = ObjMove_GetY(boss2Obj);
				SetCommonData("boss2X", boss2X);
				SetCommonData("boss2Y", boss2Y);
			}
		}
	}
	yield; 
}

@Event {
	alternative(GetEventType)
	// Event is triggered when any attack begins, regardless of spell or not.
	case(EV_START_BOSS_STEP) {
		if(!GetCommonData("isDialogue",false)) {
			isBossFight = true; 
			isTimedOut = false;	
			isPichuun = false;
			isDuetCard = GetCommonData("isDuet", false);
			locateBossID;
		}
	}
	
	// Event is triggered when any attack ends, regardless of spell or not.
	case(EV_END_BOSS_STEP) {
		if(!GetCommonData("isDialogue",false)) { 	
			if(isPichuun && GetCommonData("bossAttackType",false) == 2) { hudAnnounce("failed"); } 
			isBossFight = false;
			infoAnimOnce = false;
			SetCommonData("isDuet", false);
			DeleteShotAll(TYPE_ALL, TYPE_ITEM);

			if(!isTimedOut) {
			    if(GetCommonData("bossAttackType",false) == 2) {
			        distortCirc(90,15); PlaySFX(SFX_ACK3);
                }
            }
		}
	}
	
	// Event is triggered when there is a spell card is starting.
	//		Render the background using renderBG - Type is decided by commondata.
	//		Render the funky spell circle.
	//		Subtract 1 spell card counter. Required for post-bossfight effects.
	case(EV_START_BOSS_SPELL) {
		isPichuun = false;

		updateCardHistory();

		let cardTracker = 0;
		cardTracker = GetCommonData("cardTracker",0);
		cardTracker++;
		SetCommonData("cardTracker",cardTracker);

		renderBG(GetCommonData("bossBgType",0));
		bossFunkyCircle;

		if(GetCommonData("bossCircleType",0) == 1) { cutin(NAZRIN,syscut,0,0,1024,1024,0.4); }
		if(GetCommonData("bossCircleType",0) == 2) { cutin(BYAKUREN,syscut2,0,0,1024,1024,0.45); }
		if(GetCommonData("bossCircleType",0) == 3) { cutin(BYAKUREN,syscut3,0,0,1024,1024,0.4); }
		PlaySFX(SFX_CH00);
		PlaySFX(SFX_CAT00);
	}
	
	// Event is triggered when a spell card is captured. Related to StartSpell(bossScene);
	//		If the spellcard is captured, but bossfight is still going, do the breakEffect, distortCirc and SFX
	//		Always play SFX for getting a spell card.
	case(EV_GAIN_SPELL) {
		if(GetCommonData("bossCircleType",0) == 0) { breakEffect(255,64,64); PlaySFX(SFX_ACK); }
		if(GetCommonData("bossCircleType",0) == 1) { breakEffect(255,64,255); PlaySFX(SFX_ACK); }
		if(GetCommonData("bossCircleType",0) == 2) { breakEffect(64,64,255); PlaySFX(SFX_ACK3); }
		if(GetCommonData("bossCircleType",0) == 3) { breakEffect(64,255,64); PlaySFX(SFX_ACK3); }
		distortCirc(90,15);

		// Score calculation after spell card
		let getSpellBonus = ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_SPELL_SCORE);
		AddScore(getSpellBonus); 
		hudAnnounce("bonus"); 
		PlaySFX(SFX_CARDGET);
		PlaySFX(SFX_ACK2);

		updateCardCapture;
		
		// Check for true boss conditions
		let numberOfCaptures = GetCommonData("numCardsCaptured", 0);
		numberOfCaptures++;
		SetCommonData("numCardsCaptured", numberOfCaptures);
		
		if(!isDuetCard && GetCommonData("mainPlural",false)) { 
			if(GetAreaCommonData("game","stageNum",1) == 1 && GetCommonData("cardTracker",0) == 3) {
				if(numberOfCaptures >= GetCommonData("needNumCards",0) && GetAreaCommonData("game","cannotUnlock",0) == 0 && GetAreaCommonData("game","feverpoint",0) >= 45) {
					SetAreaCommonData("game","fightHina",true);						
				}
				else { SetAreaCommonData("game","cannotUnlock",1); }					
			}	
			if(GetAreaCommonData("game","stageNum",1) == 2 && GetCommonData("cardTracker",0) == 6) {
				if(numberOfCaptures >= GetCommonData("needNumCards",0) && GetAreaCommonData("game","cannotUnlock",0) == 0 && GetAreaCommonData("game","feverpoint",0) >= 50) {
					SetAreaCommonData("game","fightIku",true);							
				}
				else { SetAreaCommonData("game","cannotUnlock",1); }					
			}	
			if(GetAreaCommonData("game","stageNum",1) == 3 && GetCommonData("cardTracker",0) == 6) {
				if(numberOfCaptures >= GetCommonData("needNumCards",0) && GetAreaCommonData("game","cannotUnlock",0) == 0 && GetAreaCommonData("game","feverpoint",0) >= 80) {
					SetAreaCommonData("game","fightTewi",true);							
				}
				else { SetAreaCommonData("game","cannotUnlock",1); }					
			}
		}
	}
	
	// Event is triggered when a spell card is timed out. In case it is survival, no 'fail' sfx is played.
	// 		Always play SFX for failing to capture due to time-out.
	case(EV_TIMEOUT) { 
		if(!ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_IS_DURABLE_SPELL)) {
			if(GetCommonData("bossAttackType",false) == 2) { PlaySFX(SFX_FAULT); }
			isTimedOut = true; 
			hudAnnounce("failed"); 
		}
		else {
			isTimedOut = true; 
		}
	}
	case(EV_PAUSE_ENTER) {
		
	}
	case(EV_PAUSE_LEAVE ) {
	
	}	
}

// Update the card history
task updateCardHistory() {
	let spellScriptID = GetCommonData("spellScriptID", 0);
	NotifyEvent(spellScriptID, EV_USER+9999, 0);
	getResultCard = GetCommonData("spellcardID", "NULL");
	let getCommonSpellCardData = []; 
	getCommonSpellCardData = GetAreaCommonData("core", getResultCard, [0,0,0,0,0,0,0,0,0,0,0]);
	
	if(GetAreaCommonData("game","menuFlow",0) == 0) { 
		let cardStatus = getCommonSpellCardData[0];
		let stageCaptures = getCommonSpellCardData[1]; 
		let stageHistory = getCommonSpellCardData[2]; 
		let practiceCaptures = getCommonSpellCardData[3]; 
		let practiceHistory = getCommonSpellCardData[4];
		let hiScore0 = getCommonSpellCardData[5];
		let hiScore1 = getCommonSpellCardData[6];
		let hiScore2 = getCommonSpellCardData[7];
		let hiScore3 = getCommonSpellCardData[8];
		let hiScore4 = getCommonSpellCardData[9];
		let hiScore5 = getCommonSpellCardData[10];

        if(cardStatus == 0) { cardStatus = 1; }

		stageHistory++;

		SetAreaCommonData("core",getResultCard,[cardStatus, stageCaptures, stageHistory, practiceCaptures, practiceHistory, hiScore0, hiScore1, hiScore2, hiScore3, hiScore4, hiScore5]);
		SaveCommonDataAreaA1("core");
	}
	if(GetAreaCommonData("game","menuFlow",0) == 4) { 
		let cardStatus = getCommonSpellCardData[0];
		let stageCaptures = getCommonSpellCardData[1]; 
		let stageHistory = getCommonSpellCardData[2]; 
		let practiceCaptures = getCommonSpellCardData[3]; 
		let practiceHistory = getCommonSpellCardData[4];
		let hiScore0 = getCommonSpellCardData[5];
		let hiScore1 = getCommonSpellCardData[6];
		let hiScore2 = getCommonSpellCardData[7];
		let hiScore3 = getCommonSpellCardData[8];
		let hiScore4 = getCommonSpellCardData[9];
		let hiScore5 = getCommonSpellCardData[10];

		practiceHistory++;

		SetAreaCommonData("core",getResultCard,[cardStatus, stageCaptures, stageHistory, practiceCaptures, practiceHistory, hiScore0, hiScore1, hiScore2, hiScore3, hiScore4, hiScore5]);
		SaveCommonDataAreaA1("core");	
	}
	
	getCommonSpellCardData = GetAreaCommonData("core", getResultCard, [0,0,0,0,0,0,0,0,0,0,0]);
	DeleteCommonData("spellcardID");
}

// Update the capture history
task updateCardCapture() {
	let spellScriptID = GetCommonData("spellScriptID",0);
	NotifyEvent(spellScriptID,EV_USER+9999,0);
	getResultCard = GetCommonData("spellcardID","NULL"); 
	let getCommonSpellCardData = []; 
	getCommonSpellCardData = GetAreaCommonData("core",getResultCard, [0,0,0,0,0,0,0,0,0,0,0]);
	
	if(GetAreaCommonData("game","menuFlow",0) == 0) { 
		let cardStatus = getCommonSpellCardData[0];
		let stageCaptures = getCommonSpellCardData[1]; 
		let stageHistory = getCommonSpellCardData[2]; 
		let practiceCaptures = getCommonSpellCardData[3]; 
		let practiceHistory = getCommonSpellCardData[4];
		let hiScore0 = getCommonSpellCardData[5];
		let hiScore1 = getCommonSpellCardData[6];
		let hiScore2 = getCommonSpellCardData[7];
		let hiScore3 = getCommonSpellCardData[8];
		let hiScore4 = getCommonSpellCardData[9];
		let hiScore5 = getCommonSpellCardData[10];

		if(cardStatus == 0) { cardStatus = 1; }

		stageCaptures++;

		SetAreaCommonData("core",getResultCard,[cardStatus, stageCaptures, stageHistory, practiceCaptures, practiceHistory, hiScore0, hiScore1, hiScore2, hiScore3, hiScore4, hiScore5]);
		SaveCommonDataAreaA1("core");
	}
	if(GetAreaCommonData("game","menuFlow",0) == 4) { 
		let cardStatus = getCommonSpellCardData[0];
		let stageCaptures = getCommonSpellCardData[1]; 
		let stageHistory = getCommonSpellCardData[2]; 
		let practiceCaptures = getCommonSpellCardData[3]; 
		let practiceHistory = getCommonSpellCardData[4];
		let hiScore0 = getCommonSpellCardData[5];
		let hiScore1 = getCommonSpellCardData[6];
		let hiScore2 = getCommonSpellCardData[7];
		let hiScore3 = getCommonSpellCardData[8];
		let hiScore4 = getCommonSpellCardData[9];
		let hiScore5 = getCommonSpellCardData[10];

		practiceCaptures++;

        let currentScore = GetScore();
        if(GetAreaCommonData("game","team",0) == 0) {
            hiScore0 = checkAndCalculateHighScore(currentScore, hiScore0);
        }
        if(GetAreaCommonData("game","team",0) == 1) {
            hiScore1 = checkAndCalculateHighScore(currentScore, hiScore1);
        }

        function checkAndCalculateHighScore(currentScore, currentHighScore) {
            if(currentScore > currentHighScore) {
                currentHighScore = currentScore;
                return currentHighScore;
            } else {
                return currentHighScore;
            }
        }

		SetAreaCommonData("core",getResultCard,[cardStatus, stageCaptures, stageHistory, practiceCaptures, practiceHistory, hiScore0, hiScore1, hiScore2, hiScore3, hiScore4, hiScore5]);
		SaveCommonDataAreaA1("core");	
	}
	
	getCommonSpellCardData = GetAreaCommonData("core", getResultCard, [0,0,0,0,0,0,0,0,0,0,0]);
	DeleteCommonData("spellcardID");
}

//------------------------------------------------------------------------------------------------------------------------------------------
// HUD system

// Draw main skin 
function hudSkin() {
	let hudskin = "script/thdcs/system/mainskin.png";
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj,hudskin);
	Obj_SetRenderPriority(obj,0);
	ObjSprite2D_SetSourceRect(obj,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
	ObjSprite2D_SetDestRect(obj,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
}

task hudStripes(x,y,r,g,b,w) {
	loop(w) { yield; } 
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	
	let flipY = 90;
	let xmove = 0;
	let alphaValue = 0;
	
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj,55);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,1.6,1,0);
	ObjRender_SetAngleY(obj,90);
	ObjSprite2D_SetSourceRect(obj,384,256,512,288);
	ObjSprite2D_SetDestCenter(obj);	
	ObjRender_SetPosition(obj,x,y,0);	
	ObjRender_SetColor(obj,r,g,b);

	ObjPrim_SetTexture(obj2,menuitems);
	ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj2,alphaValue);
	Obj_SetRenderPriorityI(obj2,89);
	ObjRender_SetScaleXYZ(obj2,1.5,1.5,0);
	ObjRender_SetAngleY(obj2,0);
	ObjSprite2D_SetSourceRect(obj2,400,256,410,288);
	ObjSprite2D_SetDestCenter(obj2);	
	ObjRender_SetPosition(obj2,x-64,y,0);	
	ObjRender_SetColor(obj2,r,g,b);
	
	while(flipY > 0) { 
		ObjRender_SetAngleY(obj,flipY);
		ObjRender_SetAngleX(obj,flipY);
		flipY-=4;
		yield;
	}
	while(alphaValue < 250) { alphaValue+=10; ObjRender_SetAlpha(obj2,alphaValue); }
	loop(32) {
		ObjRender_SetPosition(obj2,x-64+xmove,y,0);	
		xmove+=4;
		yield;
	}
	while(alphaValue > 0) { alphaValue-=10; ObjRender_SetAlpha(obj2,alphaValue); }
	Obj_Delete(obj2);
}

// Draws the static text like live, bombs, etc. 
function hudStatics() {
	LoadCommonDataAreaA1("game");
	
	let curDifficulty = 0; 
	
	if(GetAreaCommonData("game","menuFlow",0) == 4) { 
		curDifficulty = GetCommonData("tryDifficulty",0); 
	}
	else { curDifficulty = GetAreaCommonData("game","difficulty",0); }
	
	// Difficulty 
	if(IsReplay) { let diffStatic = pieceHUD(530,30,1,255,0,352,128,384); diffFlash(diffStatic); }
	else if(curDifficulty == 0 && !IsReplay) { let diffStatic = pieceHUD(530,30,1,255,128,352,256,384); diffFlash(diffStatic); }
	else if(curDifficulty == 1 && !IsReplay) { let diffStatic = pieceHUD(530,30,1,255,256,352,384,384); diffFlash(diffStatic); }
	else if(curDifficulty == 2 && !IsReplay) { let diffStatic = pieceHUD(530,30,1,255,384,352,512,384); diffFlash(diffStatic); }
	pieceHUD(464,52,1,255,0,384,128,416);		// High score texture
	pieceHUD(454,78,1,255,0,416,128,448);		// Score texture
	pieceHUD(454,108,1,255,128,384,256,416);	// Lives texture
	pieceHUD(469,146,1,255,128,416,256,448);	// Spells texture
	pieceHUD(444,196,1,205,406,288,422,320);	// Ten show texture
	pieceHUD(484,180,1,255,256,416,384,448);	// PIV texture
	pieceHUD(484,210,1,255,256,384,384,416);	// Graze texture
	pieceHUD(484,240,1,255,384,416,512,448);	// Fever texture
}

// Anim for difficulty sprite
task diffFlash(obj) {
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	let rgb = 104;
	let flashf = 0;
	loop(120) {
		ObjRender_SetColor(obj,rgb,rgb,rgb);
		rgb += cos(flashf)*32;
		flashf+=20;
		yield;
	}
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetColor(obj,255,255,255);
}

// function to summon a piece of the HUD.
function pieceHUD(x,y,scale,alpha,left,top,right,bottom) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,alpha);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,scale,scale,0);
	ObjSprite2D_SetSourceRect(obj,left,top,right,bottom);
	ObjSprite2D_SetDestCenter(obj);	
	ObjRender_SetPosition(obj,x,y,0);
	return obj;
}

task hudBallGlitter() {
	// red, green, blue, cyan, purple, yellow, orange
	let colSet = [[255, 16, 16],[16,255,16],[16,16,255],[16,255,255],[255,16,255],[255,255,16],[255,128,16]]; 
	let colKies = 0;	
	let dir = 0;
	
	loop(24) { 
		colKies = rand_int(0,7);
		hudGlitter(530+72*cos(dir),380+72*sin(dir),rand(0.5,1.0),rand_int(0,360),rand(0.2,3.5),255,colSet[colKies][0],colSet[colKies][1],colSet[colKies][2]);
		hudGlitter(530+72*cos(dir+180),380+72*sin(dir+180),rand(0.5,1.0),rand_int(0,360),rand(0.2,3.5),255,colSet[colKies][0],colSet[colKies][1],colSet[colKies][2]);
		dir+=360/36;
		yield;
	}
}

// Draws the high score digits
task hudHighScore() {
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let maxDigit = 1;
	let destRectX = 0;
	
	ObjPrim_SetTexture(obj, menuitems);
	ObjRender_SetBlendType(obj, BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj, 10);
	ObjRender_SetY(obj, 34);
	ObjRender_SetColor(obj, 200, 200, 200);

	let highScore = 0;

    // TODO: Implement the highscore to be displayed depending on mode + difficulty. New common datas have been made and ready.
    // Set the highscore to 0 if it is Spell Practise, otherwise retrieve from highscore history based on difficulty
	if(GetAreaCommonData("game","menuFlow",0) == 4) { highScore = 0; }
	else {
	    highScore = GetAreaCommonData("core","hiscore",0);
	}
	
	while(true) {
		if(highScore < GetScore) { highScore = GetScore; }
		SetAreaCommonData("core","hiscore",highScore);
		
		// Maybe inefficient, but tracks the value then decides how many digits to show. Similar use in other tasks.
		if(highScore < 9) { maxDigit = 1; highScore = min(highScore,9); } 
		if(highScore > 9 && highScore < 99) { maxDigit = 2; highScore = min(highScore,99); } 
		if(highScore > 99 && highScore < 999) { maxDigit = 3; highScore = min(highScore,999); }
		if(highScore > 999 && highScore < 9999) { maxDigit = 4; highScore = min(highScore,9999); }	
		if(highScore > 9999 && highScore < 99999) { maxDigit = 5; highScore = min(highScore,99999); }			
		if(highScore > 99999 && highScore < 999999) { maxDigit = 6; highScore = min(highScore,999999); } 
		if(highScore > 999999 && highScore < 9999999) { maxDigit = 7; highScore = min(highScore,9999999); } 
		if(highScore > 9999999 && highScore < 99999999) { maxDigit = 8; highScore = min(highScore,99999999); } 
		if(highScore > 99999999 && highScore < 999999999) { maxDigit = 9; highScore = min(highScore,999999999); } 
		if(highScore > 999999999 && highScore < 9999999999) { maxDigit = 10; highScore = min(highScore,9999999999); } 
		if(highScore > 9999999999 && highScore < 99999999999) { maxDigit = 11; highScore = min(highScore,99999999999); } 
		if(highScore > 99999999999 && highScore < 999999999999) { maxDigit = 12; highScore = min(highScore,999999999999); } 
		if(highScore > 999999999999 && highScore < 9999999999999) { maxDigit = 13; highScore = min(highScore,9999999999999); } 
		if(highScore > 9999999999999 && highScore < 99999999999999) { maxDigit = 14; highScore = min(highScore,99999999999999); } 
		
		let digitList = DigitToArray(highScore,maxDigit);
		ObjSpriteList2D_ClearVertexCount(obj);
		ascent(i in 0..maxDigit) {
			let num = digitList[i];
			// If lesser digits, adjust X-pos. Similar use in other tasks.
			if(maxDigit == 1) { ObjRender_SetX(obj,606+i*12); }
			if(maxDigit == 2) { ObjRender_SetX(obj,594+i*12); }
			if(maxDigit == 3) { ObjRender_SetX(obj,582+i*12); }
			if(maxDigit == 4) { ObjRender_SetX(obj,570+i*12); }
			if(maxDigit == 5) { ObjRender_SetX(obj,558+i*12); }
			if(maxDigit == 6) { ObjRender_SetX(obj,546+i*12); }
			if(maxDigit == 7) { ObjRender_SetX(obj,534+i*12); }
			if(maxDigit == 8) { ObjRender_SetX(obj,522+i*12); }
			if(maxDigit == 9) { ObjRender_SetX(obj,510+i*12); }
			if(maxDigit == 10) { ObjRender_SetX(obj,498+i*12); }
			if(maxDigit == 11) { ObjRender_SetX(obj,486+i*12); }
			if(maxDigit == 12) { ObjRender_SetX(obj,474+i*12); }
			if(maxDigit == 13) { ObjRender_SetX(obj,462+i*12); }
			if(maxDigit == 14) { ObjRender_SetX(obj,450+i*12); }
			
			ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
			ObjSpriteList2D_SetDestRect(obj,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj);
			
			if(destRectX < 20) { destRectX++; }
		}	
		yield;
	}
}

// Draws the regular score
task hudScore() { 
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	// score
	let maxDigit = 1;
	let destRectX = 0;
	
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,10);
	ObjRender_SetY(obj,58);
	
	while(true) {
		let score = GetScore;

		if(score < 9) { maxDigit = 1; score = min(score,9); } 
		if(score > 9 && score < 99) { maxDigit = 2; score = min(score,99); } 
		if(score > 99 && score < 999) { maxDigit = 3; score = min(score,999); }
		if(score > 999 && score < 9999) { maxDigit = 4; score = min(score,9999); }	
		if(score > 9999 && score < 99999) { maxDigit = 5; score = min(score,99999); }			
		if(score > 99999 && score < 999999) { maxDigit = 6; score = min(score,999999); } 
		if(score > 999999 && score < 9999999) { maxDigit = 7; score = min(score,9999999); } 
		if(score > 9999999 && score < 99999999) { maxDigit = 8; score = min(score,99999999); } 
		if(score > 99999999 && score < 999999999) { maxDigit = 9; score = min(score,999999999); } 
		if(score > 999999999 && score < 9999999999) { maxDigit = 10; score = min(score,9999999999); } 
		if(score > 9999999999 && score < 99999999999) { maxDigit = 11; score = min(score,99999999999); } 
		if(score > 99999999999 && score < 999999999999) { maxDigit = 12; score = min(score,999999999999); } 
		if(score > 999999999999 && score < 9999999999999) { maxDigit = 13; score = min(score,9999999999999); } 
		if(score > 9999999999999 && score < 99999999999999) { maxDigit = 14; score = min(score,99999999999999); } 
		
		let digitList = DigitToArray(score,maxDigit);
		ObjSpriteList2D_ClearVertexCount(obj);

		ascent(i in 0..maxDigit) {
			let num = digitList[i];
			if(maxDigit == 1) { ObjRender_SetX(obj,606+i*12); }
			if(maxDigit == 2) { ObjRender_SetX(obj,594+i*12); }
			if(maxDigit == 3) { ObjRender_SetX(obj,582+i*12); }
			if(maxDigit == 4) { ObjRender_SetX(obj,570+i*12); }
			if(maxDigit == 5) { ObjRender_SetX(obj,558+i*12); }
			if(maxDigit == 6) { ObjRender_SetX(obj,546+i*12); }
			if(maxDigit == 7) { ObjRender_SetX(obj,534+i*12); }
			if(maxDigit == 8) { ObjRender_SetX(obj,522+i*12); }
			if(maxDigit == 9) { ObjRender_SetX(obj,510+i*12); }
			if(maxDigit == 10) { ObjRender_SetX(obj,498+i*12); }
			if(maxDigit == 11) { ObjRender_SetX(obj,486+i*12); }
			if(maxDigit == 12) { ObjRender_SetX(obj,474+i*12); }
			if(maxDigit == 13) { ObjRender_SetX(obj,462+i*12); }
			if(maxDigit == 14) { ObjRender_SetX(obj,450+i*12); }
			ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
			ObjSpriteList2D_SetDestRect(obj,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj);
			if(destRectX < 20) { destRectX++; }
		}
		yield;
	}
}

// Note: CurrentPlayerLife will deduct '1' in its calculation to display correct number of hearts.
//       This is in order to support the Continue System regarding STATE_END prevention.
task hudLife() {
	let maxPlayerLife = 8;
	let currentPlayerLife = GetPlayerLife - 1;
	let lifeArray = [];
	let nextX = 520;

	// Summon 8x lifeCount function and store in Array (similar mechanics used in spell counter)
	ascent(i in 0..maxPlayerLife) {
		lifeArray = lifeArray ~ [lifeCount];
	}
	// Loop array and render the positions of the hearts with their 'empty' texture.
	ascent(i in 0..length(lifeArray)) {
		ObjRender_SetPosition(lifeArray[i],nextX,108,0);
		nextX+=13;
		wait(3);
	}
	// Loop the array again with current lives and check how many hearts need to be filled.
	ascent(i in 0..currentPlayerLife) {
		ObjSprite2D_SetSourceRect(lifeArray[i],256,288,288,320);
		wait(3);
	}
	while(true) { 
		// If player loses a life
		if(GetPlayerLife - 1 < currentPlayerLife) {
			ascent(i in 0..length(lifeArray)) { ObjSprite2D_SetSourceRect(lifeArray[i],288,288,320,320); }
			ascent(j in 0..GetPlayerLife - 1) {
				ObjSprite2D_SetSourceRect(lifeArray[j],256,288,288,320);
			}	
			currentPlayerLife = GetPlayerLife - 1;
		}
		// If player gains a life
		if(GetPlayerLife - 1 > currentPlayerLife) {
			ascent(i in 0..length(lifeArray)) { ObjSprite2D_SetSourceRect(lifeArray[i],288,288,320,320); }
			ascent(j in 0..GetPlayerLife - 1) {
				ObjSprite2D_SetSourceRect(lifeArray[j],256,288,288,320);
			}	
			currentPlayerLife = GetPlayerLife - 1;
		}
		yield;
	}
	ascent(i in 0..length(lifeArray)) { Obj_Delete(lifeArray[i]); }
}

function lifeCount() {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,255);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	//ObjSprite2D_SetSourceRect(obj,256,288,288,320);	// filled
	ObjSprite2D_SetSourceRect(obj,288,288,320,320);		// empty
	ObjSprite2D_SetDestCenter(obj);	
	
	return obj;
}

task hudSpell() {
	let maxPSpell = 8;
	let curPSpell = GetPlayerSpell;
	let spellArr = [];
	let nextX = 520;

	ascent(i in 0..maxPSpell) { 
		spellArr = spellArr ~ [spellCount];
	}
	ascent(i in 0..length(spellArr)) {
		ObjRender_SetPosition(spellArr[i],nextX,144,0);
		nextX+=13;
		wait(3);
	}
	ascent(i in 0..GetPlayerSpell) {
		ObjSprite2D_SetSourceRect(spellArr[i],320,288,352,320);
		wait(3);
	}		
	while(true) {
		// If player uses spell
		if(GetPlayerSpell < curPSpell) {
			ascent(i in 0..length(spellArr)) { ObjSprite2D_SetSourceRect(spellArr[i],352,288,384,320); }
			ascent(j in 0..GetPlayerSpell) {
				ObjSprite2D_SetSourceRect(spellArr[j],320,288,352,320);
			}	
			curPSpell = GetPlayerSpell; 
		}
		// If player gains a spell
		if(GetPlayerSpell > curPSpell) {
			ascent(i in 0..length(spellArr)) { ObjSprite2D_SetSourceRect(spellArr[i],352,288,384,320); }
			ascent(j in 0..GetPlayerSpell) {
				ObjSprite2D_SetSourceRect(spellArr[j],320,288,352,320);
			}	
			curPSpell = GetPlayerSpell; 
		}		
		yield;
	}
	ascent(i in 0..length(spellArr)) { Obj_Delete(spellArr[i]); } 
}

function spellCount() {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,255);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	//ObjSprite2D_SetSourceRect(obj,320,288,352,320);	// filled
	ObjSprite2D_SetSourceRect(obj,352,288,384,320);		// empty
	ObjSprite2D_SetDestCenter(obj);	
	
	return obj;
}

task hudPIV() {
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let maxDigit = 1;
	let destRectX = 0;
	let isCounted = false; 
	let piv = 0; 
		
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,10);
	ObjRender_SetY(obj,165);

	while(true) {
		if(!isCounted) { if(piv < GetAreaCommonData("game","piv",10000)) { piv+=200; } if(piv == 10000) { isCounted = true; } }
		if(isCounted) { piv = GetAreaCommonData("game","piv",10000); }
		
		if(piv < 9) { maxDigit = 1; piv = min(piv,9); } 
		if(piv > 9 && piv < 99) { maxDigit = 2; piv = min(piv,99); } 
		if(piv > 99 && piv < 999) { maxDigit = 3; piv = min(piv,999); }
		if(piv > 999 && piv < 9999) { maxDigit = 4; piv = min(piv,9999); }	
		if(piv > 9999 && piv < 99999) { maxDigit = 5; piv = min(piv,99999); }
		
		let digitList = DigitToArray(piv,maxDigit);
		ObjSpriteList2D_ClearVertexCount(obj);
		
		ascent(i in 0..maxDigit) {
			let num = digitList[i];
			if(maxDigit == 1) { ObjRender_SetX(obj,606+i*12); }
			if(maxDigit == 2) { ObjRender_SetX(obj,594+i*12); }
			if(maxDigit == 3) { ObjRender_SetX(obj,582+i*12); }
			if(maxDigit == 4) { ObjRender_SetX(obj,570+i*12); }
			if(maxDigit == 5) { ObjRender_SetX(obj,558+i*12); }
			ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
			ObjSpriteList2D_SetDestRect(obj,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj);
			if(destRectX < 20) { destRectX++; }
		}
		yield;
	}
}

task hudGraze() { 
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let maxDigit = 5;
	let destRectX = 0;
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,10);
	ObjRender_SetY(obj,196);

	while(true) {
		let graze = GetGraze;
	
		if(graze < 9) { maxDigit = 1; graze = min(graze,9); } 
		if(graze > 9 && graze < 99) { maxDigit = 2; graze = min(graze,99); } 
		if(graze > 99 && graze < 999) { maxDigit = 3; graze = min(graze,999); }
		if(graze > 999 && graze < 9999) { maxDigit = 4; graze = min(graze,9999); }	
		if(graze > 9999 && graze < 99999) { maxDigit = 5; graze = min(graze,99999); }	

		let digitList = DigitToArray(graze,maxDigit);	
		ObjSpriteList2D_ClearVertexCount(obj);
		ascent(i in 0..maxDigit) {
			let num = digitList[i];
			if(maxDigit == 1) { ObjRender_SetX(obj,606+i*12); }
			if(maxDigit == 2) { ObjRender_SetX(obj,594+i*12); }
			if(maxDigit == 3) { ObjRender_SetX(obj,582+i*12); }
			if(maxDigit == 4) { ObjRender_SetX(obj,570+i*12); }
			if(maxDigit == 5) { ObjRender_SetX(obj,558+i*12); }
			ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
			ObjSpriteList2D_SetDestRect(obj,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj);
			if(destRectX < 20) { destRectX++; }			
		}

		let incPIV = GetGraze * 10; 
		SetAreaCommonData("game","piv",10000+incPIV);
		yield;
	}
}

task bulletGrazeEffect(obj) {
    let isBeingGrazed = false;
    let currentGrazeTimeFrame = 0;
    let oldGrazeTimeFrame = 0;

    while(!Obj_IsDeleted(obj) && currentGrazeTimeFrame < 120) {
        currentGrazeTimeFrame = Obj_GetValue(obj,"grazeTimeFrame");

        if(currentGrazeTimeFrame > oldGrazeTimeFrame) {
            isBeingGrazed = true;
            oldGrazeTimeFrame = currentGrazeTimeFrame;
        }
        else {
            isBeingGrazed = false;
            yield;
        }

        if(isBeingGrazed) {
            ObjRender_SetColor(obj,255,128,128);
            yield;
            ObjRender_SetColor(obj,255,255,255);
            yield;
        }
    }
    ObjRender_SetColor(obj,255,255,255);
}

task grazeBonusHandler() {
    let bulletID = 0;
    let isFound = false;
    let nearbyBulletsArray = [];
    let storedBulletsArray = [];

    while(true) {
        nearbyBulletsArray = GetShotIdInCircleA2(GetPlayerX, GetPlayerY, 34, TARGET_ENEMY);

        if(length(nearbyBulletsArray) != 0) {
            ascent(i in 0..length(nearbyBulletsArray)) {
                bulletID = nearbyBulletsArray[i];

                ascent(k in 0..length(storedBulletsArray)) {
                    if(bulletID == storedBulletsArray[k]) {
                        let increaseGrazeTimeFrame = Obj_GetValue(storedBulletsArray[k],"grazeTimeFrame");
                        increaseGrazeTimeFrame++;
                        Obj_SetValue(bulletID,"grazeTimeFrame",increaseGrazeTimeFrame);

                        if(increaseGrazeTimeFrame == 120) {
                            AddGraze(5);
                            PlaySFX(SFX_ITEM01);
                        }
                    }
                }

                ascent(j in 0..length(storedBulletsArray)) {
                    if(storedBulletsArray[j] == bulletID) {
                        isFound = true;
                    }
                }

                if(!isFound) {
                    Obj_SetValue(bulletID,"grazeTimeFrame",0);
                    storedBulletsArray = storedBulletsArray ~ [bulletID];
                    bulletGrazeEffect(bulletID);
                }

                isFound = false;
            }
        }

        ascent(p in 0..length(storedBulletsArray)) {
            if(Obj_IsDeleted(storedBulletsArray[p])) {
                Obj_DeleteValue(storedBulletsArray[p],"grazeTimeFrame");
                storedBulletsArray = erase(storedBulletsArray,p);
                break;
            }
        }

        yield;
    }
}


task hudFever() {
	let maxDigit = 5;
	let maxDigit2 = 5;
	let destRectX = 0;
	let feverRequirement = [999, 45, 60, 80];
	let captureRequirement = [999, 3, 5, 5];
	let fever = GetAreaCommonData("game","feverpoint",0);
	let feverMax = 0;
	let feverSwitch = 0;
	let stageCurrent = GetAreaCommonData("game","stageNum",1);
	
	// current fever
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,10);
	ObjRender_SetColor(obj,255,255,255);
	ObjRender_SetY(obj,224);
	
	// required fever 
	let obj2 = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	
	ObjPrim_SetTexture(obj2,menuitems);
	ObjRender_SetBlendType(obj2,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj2,10);
	ObjRender_SetColor(obj2,255,255,255);
	ObjRender_SetY(obj2,224);
	
	// char slash
	let obj3 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj3,90); 
	ObjPrim_SetTexture(obj3,menuitems); 
	ObjRender_SetBlendType(obj3,BLEND_ALPHA);
	ObjRender_SetAlpha(obj3,255);
	ObjSprite2D_SetSourceRect(obj3,320,320,340,352);
	ObjRender_SetColor(obj3,128,128,255);
	ObjRender_SetScaleXYZ(obj3,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj3);
	ObjRender_SetPosition(obj3,589,240,0);	
	
	// Treasure image
	let obj4 = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj4, imgTreasure);
	ObjRender_SetBlendType(obj4, BLEND_ALPHA);
	ObjRender_SetAlpha(obj4, 0);
	Obj_SetRenderPriorityI(obj4, 90);
	ObjRender_SetScaleXYZ(obj4, 0.75, 0.75,0);
	ObjSprite2D_SetSourceRect(obj4, 0, 0, 128, 128);
	ObjSprite2D_SetDestCenter(obj4);	
	ObjRender_SetPosition(obj4, 534, 372, 0);

	// Treasure glow image effect object
	let obj5 = ObjPrim_Create(OBJ_SPRITE_2D);
	ObjPrim_SetTexture(obj5, imgTreasure);
	ObjRender_SetBlendType(obj5, BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj5, 0);
	Obj_SetRenderPriorityI(obj5, 89);
	ObjRender_SetScaleXYZ(obj5, 0.75, 0.75,0);
	ObjSprite2D_SetSourceRect(obj5, 0, 0, 128, 128);
	ObjSprite2D_SetDestCenter(obj5);
	ObjRender_SetPosition(obj5, 534, 372, 0);

    treasureWobbleAnimation(obj4);
    treasureWobbleAnimation(obj5);
    treasureGlowAnimation(obj5);

	while(true) {
		fever = GetAreaCommonData("game", "feverpoint", 0);
		SetAreaCommonData("game", "feverpoint", fever);
        feverMax = feverRequirement[GetAreaCommonData("game", "stageNum", 1)];

		// For resetting the treasure SFX, check current stage vs stageCurrent
		if(stageCurrent != GetAreaCommonData("game", "stageNum", 1)) {
			feverSwitch = 0;
			stageCurrent = GetAreaCommonData("game", "stageNum", 1);
		}

		// Set treasure type based on stage number
		if(stageCurrent == 0) {
		    ObjSprite2D_SetSourceRect(obj5, 0, 0, 0, 0);
		    ObjSprite2D_SetSourceRect(obj5, 0, 0, 0, 0);
		}
		else if(stageCurrent == 1) {
            ObjSprite2D_SetSourceRect(obj4, 0, 0, 128, 128);
            ObjSprite2D_SetSourceRect(obj5, 0, 0, 128, 128);
		}
		else if(stageCurrent == 2) {
            ObjSprite2D_SetSourceRect(obj4, 128, 0, 256, 128);
            ObjSprite2D_SetSourceRect(obj5, 128, 0, 256, 128);
		}
		else if(stageCurrent == 3) {
            ObjSprite2D_SetSourceRect(obj4, 256, 0, 384, 128);
            ObjSprite2D_SetSourceRect(obj5, 256, 0, 384, 128);
		}
		
		// Checks whether requirements are met to draw the treasure on screen
		if((GetCommonData("numCardsCaptured",0) == captureRequirement[GetAreaCommonData("game", "stageNum", 1)]) && (fever >= feverMax) && GetAreaCommonData("game","cannotUnlock",0) == 0) {
			if(feverSwitch == 0) {
			    hasUnlockedTreasure = true;
				hudBallGlitter();
				ObjRender_SetAlpha(obj4,255);
				ObjRender_SetAlpha(obj5,255);
				feverSwitch = 1;
			}
		} else {
		    hasUnlockedTreasure = false;
			feverSwitch = 0;
			ObjRender_SetAlpha(obj4,0);
			ObjRender_SetAlpha(obj5,0);
		}

		// Updates the counters for fever/required fever
		if(fever < 9) { maxDigit = 1; fever = min(fever,9); } 
		if(fever > 9 && fever < 99) { maxDigit = 2; fever = min(fever,99); } 
		if(fever > 99 && fever < 999) { maxDigit = 3; fever = min(fever,999); }
		if(fever > 999 && fever < 9999) { maxDigit = 4; fever = min(fever,9999); }	
		if(fever > 9999 && fever < 99999) { maxDigit = 5; fever = min(fever,99999); }	

		if(feverMax < 9) { maxDigit2 = 1; maxDigit2 = min(feverMax,9); } 
		if(feverMax > 9 && feverMax < 99) { maxDigit2 = 2; feverMax = min(feverMax,99); } 
		if(feverMax > 99 && feverMax < 999) { maxDigit2 = 3; feverMax = min(feverMax,999); }
		if(feverMax > 999 && feverMax < 9999) { maxDigit2 = 4; feverMax = min(feverMax,9999); }	
		if(feverMax > 9999 && feverMax < 99999) { maxDigit2 = 5; feverMax = min(feverMax,99999); }	
		
		let digitList = DigitToArray(fever,maxDigit);
		let digitList2 = DigitToArray(feverMax,maxDigit2);
		
		ObjSpriteList2D_ClearVertexCount(obj);
		ObjSpriteList2D_ClearVertexCount(obj2);
		
		ascent(i in 0..maxDigit) {
			let num = digitList[i];
			if(maxDigit == 1) { ObjRender_SetX(obj,564+i*12); }
			if(maxDigit == 2) { ObjRender_SetX(obj,552+i*12); }
			if(maxDigit == 3) { ObjRender_SetX(obj,540+i*12); }
			if(maxDigit == 4) { ObjRender_SetX(obj,528+i*12); }
			if(maxDigit == 5) { ObjRender_SetX(obj,516+i*12); }
			ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
			ObjSpriteList2D_SetDestRect(obj,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj);
			if(destRectX < 20) { destRectX++; }			
		}
		ascent(i in 0..maxDigit2) {
			let num = digitList2[i];
			if(maxDigit2 == 1) { ObjRender_SetX(obj2,606+i*12); }
			if(maxDigit2 == 2) { ObjRender_SetX(obj2,594+i*12); }
			if(maxDigit2 == 3) { ObjRender_SetX(obj2,582+i*12); }
			if(maxDigit2 == 4) { ObjRender_SetX(obj2,570+i*12); }
			if(maxDigit2 == 5) { ObjRender_SetX(obj2,558+i*12); }

			ObjSpriteList2D_SetSourceRect(obj2,num*20,321,(num + 1)*20,352);			
			ObjSpriteList2D_SetDestRect(obj2,0,0,destRectX,32);
			ObjSpriteList2D_AddVertex(obj2);
			
			if(destRectX < 20) { destRectX++; }			
		}
		yield;
	}
}

task treasureWobbleAnimation(obj) {
    let frameCounter = 0;
    let angleZ = 0;

    while(true) {
        if(hasUnlockedTreasure) {
            ObjRender_SetAngleZ(obj, angleZ);
            angleZ = 32*sin(frameCounter)/8;
            frameCounter += 1;
        }
        yield;
    }
}

task treasureGlowAnimation(obj) {
    let alpha = 0;
    let scale = 0.75;
    let switchAnimation = false;
    while(true) {
        if(hasUnlockedTreasure) {
            if(alpha < 250 && !switchAnimation) {
                alpha += 250/20;
                scale += 0.0025;
            }

            if(alpha >= 250 && !switchAnimation) {
                switchAnimation = true;
            }

            if(alpha > 0 && switchAnimation) {
                alpha -= 250/20;
                scale += 0.0025;
            }

            if(alpha == 0 && switchAnimation) {
                alpha = 0;
                scale = 0.75;
                wait(120);
                switchAnimation = false;
            }

            ObjRender_SetScaleXYZ(obj, scale, scale, 0);
            ObjRender_SetAlpha(obj, alpha);
        }
        yield;
    }
}

task hudAnnounce(type) {
	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let aAlpha = 0;
	
	// Bg
	ObjPrim_SetTexture(obj2,menuitems);
	ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);
	ObjRender_SetAlpha(obj2,aAlpha);
	Obj_SetRenderPriorityI(obj2,90);
	ObjRender_SetScaleXYZ(obj2,1,1,0);
	ObjSprite2D_SetSourceRect(obj2,160,960,512,1024); 
	ObjSprite2D_SetDestCenter(obj2);	
	ObjRender_SetPosition(obj2,224,200,0);
		
	// Text
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,aAlpha);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	if(type == "bonus") { ObjSprite2D_SetSourceRect(obj,512,576,768,608); }			// Get spell card bonus
	if(type == "failed") { ObjSprite2D_SetSourceRect(obj,768,576,1024,608); }		// Bonus failed
	if(type == "extend") { ObjSprite2D_SetSourceRect(obj,512,608,768,640); }		// Extend
	if(type == "bomb") { ObjSprite2D_SetSourceRect(obj,768,608,1024,640); }			// Bomb
	if(type == "fever") { ObjSprite2D_SetSourceRect(obj,512,640,768,672); }			// Max fever
	if(type == "next") { ObjSprite2D_SetSourceRect(obj,768,640,1024,672); }			// Next stage
	ObjSprite2D_SetDestCenter(obj);	
	ObjRender_SetPosition(obj,214,200,0);
	
	loop(15) { 
		aAlpha+=250/15;
		ObjRender_SetAlpha(obj,aAlpha); ObjRender_SetAlpha(obj2,aAlpha);
		yield;
	}
	loop(75) { yield; } 
	loop(15) { 
		aAlpha-=250/15;
		ObjRender_SetAlpha(obj,aAlpha); ObjRender_SetAlpha(obj2,aAlpha);
		yield;
	}
	Obj_Delete(obj); Obj_Delete(obj2);
}

task hudFPS() {
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let maxDigit = 3;

	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,10);
	ObjRender_SetScaleXYZ(obj,0.68,0.68,0);
	ObjRender_SetY(obj,GetScreenHeight-30);
	
	loop {
		let fps = GetCurrentFps;
		let calc = vtos("1.2f", fps) ~ "fps";  
		if(fps <= 9) { maxDigit = 1; fps = min(fps,9); }
		if(fps > 9 && fps < 99) { maxDigit = 2; fps = min(fps,99); }
		
		let listNum = DigitToArray(fps,maxDigit);
		ObjSpriteList2D_ClearVertexCount(obj);
		ascent(i in 0..maxDigit) {
			let num = listNum[i];
			if(maxDigit == 1) { ObjRender_SetX(obj, 608+i*8); }
			if(maxDigit == 2) { ObjRender_SetX(obj, 608+i*8); }
			ObjSpriteList2D_SetSourceRect(obj, num*20, 321, (num + 1)*20, 352);
			ObjSpriteList2D_SetDestRect(obj, 0, 0, 20, 32);
			ObjSpriteList2D_AddVertex(obj);
		}
		yield;
	}
}

function DigitToArray(let digit,let 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;
}

task hudGlitter(x,y,v,dir,parts,alphaValue,red,green,blue) {

	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;
	let partSizeScale = parts;
	
	ObjPrim_SetTexture(obj,circglit);
	ObjRender_SetBlendType(obj,BLEND_ADD_RGB);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);

	ObjMove_Special(obj,x,y,v,dir);
	
	while(! Obj_IsDeleted(obj)) {
		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);

		parts = rand(partSizeScale,partSizeScale+0.5)*sin(partc*round(rand(10,20)));
		partc++;

		if(partc > round(rand(90,180))){ Obj_Delete(obj); }
		
		yield;
	}
}

// Drake's boss lifebar code + Helepolis' bossname code mixed in.
task TBossLife() {
	let path = "script/thdcs/system/effects/wit.png";
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);

	// Boss name
	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj2,90); 
	ObjPrim_SetTexture(obj2,menuitems); 
	ObjRender_SetBlendType(obj2,BLEND_ALPHA);
	ObjRender_SetAlpha(obj2,0);
	ObjSprite2D_SetSourceRect(obj2,512,512,640,528);	// default fifi-chan
	ObjRender_SetColor(obj2,255,255,255);
	ObjRender_SetScaleXYZ(obj2,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj2);
	ObjRender_SetPosition(obj2,100,32,0);	
	
	// Second boss name
	let obj3 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj3,90); 
	ObjPrim_SetTexture(obj3,menuitems); 
	ObjRender_SetBlendType(obj3,BLEND_ALPHA);
	ObjRender_SetAlpha(obj3,0);
	ObjSprite2D_SetSourceRect(obj3,512,512,640,528);	// default fifi-chan
	ObjRender_SetColor(obj3,255,255,255);
	ObjRender_SetScaleXYZ(obj3,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj3);
	ObjRender_SetPosition(obj3,100,48,0);		
	
	ObjPrim_SetTexture(obj, path);
	Obj_SetRenderPriority(obj, 0.7);
	
	let last_step = -1;
	let rate_fill = 0;
 
	let objScene = ID_INVALID;
	
	loop{
		objScene = GetEnemyBossSceneObjectID();
		ObjSpriteList2D_ClearVertexCount(obj);
		if(objScene != ID_INVALID && !GetCommonData("isDialogue",false) && isBossFight) {
			RenderLife();
		}
		else { 
			ObjRender_SetAlpha(obj2, 0); ObjRender_SetAlpha(obj3, 0);
		}
		yield;
	}
 
	function RenderLife() {
		// Singular fights (render 1)
		ObjRender_SetAlpha(obj2,255); 
		ObjRender_SetAlpha(obj3,0); 
		if(GetCommonData("bossRenderType",1) == 1) { ObjSprite2D_SetSourceRect(obj2,512,528,640,544); }			// Pierre
		if(GetCommonData("bossRenderType",1) == 10) { ObjSprite2D_SetSourceRect(obj2,512,544,640,560); }		// Hina
		if(GetCommonData("bossRenderType",1) == 11) { ObjSprite2D_SetSourceRect(obj2,512,512,640,528); }		// Fifi
		if(GetCommonData("bossRenderType",1) == 2) { ObjSprite2D_SetSourceRect(obj2,640,528,768,544); }			// Tenji
		if(GetCommonData("bossRenderType",1) == 20) { ObjSprite2D_SetSourceRect(obj2,640,544,768,560); }		// Iku
		if(GetCommonData("bossRenderType",1) == 22) { ObjSprite2D_SetSourceRect(obj2,896,528,1024,544); }		// Ufo
		if(GetCommonData("bossRenderType",1) == 23) { ObjSprite2D_SetSourceRect(obj2,512,560,640,576); }		// Nue
		if(GetCommonData("bossRenderType",1) == 24) { ObjSprite2D_SetSourceRect(obj2,640,512,768,528); }		// Kogasa
		if(GetCommonData("bossRenderType",1) == 3) { ObjSprite2D_SetSourceRect(obj2,640,560,768,576); }			// Dj
		if(GetCommonData("bossRenderType",1) == 30) { ObjSprite2D_SetSourceRect(obj2,768,512,896,528); }		// Tewi
		if(GetCommonData("bossRenderType",1) == 31) { ObjSprite2D_SetSourceRect(obj2,768,560,896,576); }		// Reimu
		if(GetCommonData("bossRenderType",1) == 32) { ObjSprite2D_SetSourceRect(obj2,896,512,1024,528); }		// Yukari
		if(GetCommonData("bossRenderType",1) == 33) { ObjSprite2D_SetSourceRect(obj2,768,528,896,544); }		// Marisa
		if(GetCommonData("bossRenderType",1) == 34) { ObjSprite2D_SetSourceRect(obj2,768,544,896,560); }		// Arisu

		// Partners in duets (render 2)
		if(isDuetCard) {
			ObjRender_SetAlpha(obj2,255);
			ObjRender_SetAlpha(obj3,255);
			if(GetCommonData("boss2RenderType",10) == 10) { ObjSprite2D_SetSourceRect(obj3,512,544,640,560); }		// Hina
			if(GetCommonData("boss2RenderType",10) == 20) { ObjSprite2D_SetSourceRect(obj3,640,544,768,560); } 		// Iku
			if(GetCommonData("boss2RenderType",10) == 24) { ObjSprite2D_SetSourceRect(obj3,640,512,768,528); }		// Kogasa
			if(GetCommonData("boss2RenderType",10) == 30) { ObjSprite2D_SetSourceRect(obj3,768,512,896,528); }		// Tewi
			if(GetCommonData("boss2RenderType",10) == 32) { ObjSprite2D_SetSourceRect(obj3,896,512,1024,528); }		// Yukari
			if(GetCommonData("boss2RenderType",10) == 34) { ObjSprite2D_SetSourceRect(obj3,768,544,896,560); }		// Arisu
		}	

		let rem_steps = ObjEnemyBossScene_GetInfo(objScene, INFO_REMAIN_STEP_COUNT);
		if(last_step != rem_steps){
			rate_fill = 0;
		}
 
		// active bar
		ObjSpriteList2D_SetSourceRect(obj, 0, 0, 1, 1);
		let life_divs;
		let real_divs = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_LIFE_RATE_LIST);
 
		// get user life divs if set, otherwise get default divs
		if(Obj_IsValueExists(objScene, "LIFEBAR_DIVS")){
			let user_divs = Obj_GetValue(objScene, "LIFEBAR_DIVS");
			let j = length(user_divs)-1-rem_steps;
			if(j > length(user_divs)-1 || j < 0){ RaiseError("Defined divs do not match actual ones: " ~ itoa(length(user_divs)) ~ " steps"); }
			life_divs = user_divs[j];
			if(length(life_divs) != length(real_divs)){ RaiseError("Defined divs do not match actual ones: " ~ itoa(length(life_divs)) ~ " divs vs " ~ itoa(length(real_divs)) ~ " actual divs"); }
		}else{
			life_divs = real_divs;
		}
 
		// life info
		let life_max = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_TOTAL_MAX_LIFE);
		let life_now = ObjEnemyBossScene_GetInfo(objScene, INFO_ACTIVE_STEP_TOTAL_LIFE);
		let life_phase_now = ObjEnemyBossScene_GetInfo(objScene, INFO_CURRENT_LIFE);
		let life_phase_max = ObjEnemyBossScene_GetInfo(objScene, INFO_CURRENT_LIFE_MAX);
		let phase_rate;
 
		descent(i in 0..length(real_divs)){
 
			if(1 - (life_now / life_max) < real_divs[i]) { // if current life more than this div (phase not completed)
				if(i == 0){ // active first phase
					phase_rate = life_phase_now / life_phase_max;
				} else if(i > 0 && 1 - (life_now / life_max) > real_divs[i-1]) { // active other phase
					phase_rate = life_phase_now / life_phase_max;
				} else { // inactive phase
					phase_rate = 1;
				}
			} else { // completed phase
				phase_rate = 0;
			}
 
			// calculate beginning and end points of div in the lifebar
			let a_rate = 1-life_divs[i];
			let b_rate = a_rate + life_divs[i] * phase_rate;
			if(i > 0) {
				b_rate = a_rate + (life_divs[i] - life_divs[i-1]) * phase_rate;
			}
			b_rate = min(max(a_rate, rate_fill), b_rate);
 
			// actual pixel lengths
			let a = 10 + 328 * a_rate;
			let b = 10 + 328 * b_rate;
 
			// default colors
			let c = [255-(i+1)*48, 255-(i+1)*48, 255-(i+1)*48];
 
			// get user colors if set
			if(Obj_IsValueExists(objScene, "LIFEBAR_COLORS")) {
				let colors = Obj_GetValue(objScene, "LIFEBAR_COLORS");
				let j = length(colors)-1-rem_steps;
				if(j >= 0 && i < length(colors[j]) && length(colors[j][i]) == 3) {
					c = colors[j][i];
				}
			}
			ObjRender_SetColor(obj, 0, 0, 0);
			ObjSpriteList2D_SetDestRect(obj, a+1, 6, b+1, 9);
			ObjSpriteList2D_AddVertex(obj);
			ObjRender_SetColor(obj, c[0], c[1], c[2]);
			ObjSpriteList2D_SetDestRect(obj, a, 6, b, 8);
			ObjSpriteList2D_AddVertex(obj);
		}
		rate_fill = min(rate_fill + 0.01, 1);
		last_step = rem_steps;
	}
}

task miniSpellCardDraw() {
	let maxCards = 0;
	let currentCards = 0;
	let cardArray = [];
	let nextX = 48;
	let objScene = ID_INVALID;
	let oneTime = false; 
	let cardSpin = 0;
	let cardGlow = 0;
	let cardFrame = 0;
	let hasAnimated = false;
	
	while(true) {
		objScene = GetEnemyBossSceneObjectID();
		if(objScene != ID_INVALID && !GetCommonData("isDialogue",false) && isBossFight) {
			if(!oneTime) { setMaxCards(); oneTime = true; } 
			renderMiniCards();
		} else {
			oneTime = false; 
			ascent(i in 0..length(cardArray)) { Obj_Delete(cardArray[i]); } 
			cardSpin = 0;
			cardGlow = 0;
			cardFrame = 0;
			maxCards = 0;
			currentCards = 0;
			cardArray = [];
		}
		yield;
	}
	
	// Renders the mini cards. 
	function renderMiniCards() {
		currentCards = ObjEnemyBossScene_GetInfo(objScene, INFO_REMAIN_STEP_COUNT);

		if(currentCards < maxCards && currentCards != 0) { 
			Obj_Delete(cardArray[currentCards]); 
			maxCards = currentCards;
		}
		
		// Only execute the animation if the attack is a spell. Otherwise nothing happens. 
		if(ObjEnemyBossScene_GetInfo(objScene, INFO_IS_SPELL)) { 
			if(!hasAnimated) {
				if(currentCards != 0) { 
					miniCardGlitter(cardArray[currentCards-1]); 
				}
				else { 
					miniCardGlitter(cardArray[currentCards]); 
				}
				hasAnimated = true;
			}
			if(currentCards != 0) {
				ObjRender_SetAngleY(cardArray[currentCards-1],cardSpin);
				ObjRender_SetColor(cardArray[currentCards-1],255,255,cardGlow);
			}
			else { 
				ObjRender_SetAngleY(cardArray[currentCards],cardSpin);
				ObjRender_SetColor(cardArray[currentCards],255,255,cardGlow);			
			}
			
			cardGlow += sin(cardFrame)*10;
			cardFrame+=6;
			cardSpin+=5;
		} 
		else { 
			ascent(i in 0..maxCards) {
				ObjRender_SetColor(cardArray[i],255,255,255);
			}
			hasAnimated = false;
		}
		yield;
	}
	
	// Sets one time the maximum number of cards for display.
	function setMaxCards() {
		currentCards = ObjEnemyBossScene_GetInfo(objScene, INFO_REMAIN_STEP_COUNT);
		
		// This is required because the weird method I used for dialogue and attack scripts.
		// Hard to explain, but for example inside balmid_main, there are 3 scenes defined:
		// fifi's normal attack, fifi's spell card then finally a dialogue.
		// All three scenes mark the step as 0. So when this function runs, the array will be prepared based
		// on the maximum steps. To avoid arrayindexoutofbound errors, I'm making sure the length of the array
		// is always 1 when the number of steps is actually 0. This is because INFO_REMAIN_STEP_COUNT returns 
		// the number of steps. For Fifi-chan it would be 0. For Pierre it would be 4, but since it is unknown
		// whether the player unlocked Hina, it will show up as 3. The same goes for Tenji and DJ who have 6 initial cards
		// and the 7th duet card.
		if(currentCards == 0) { 
			maxCards = 1; 	
		} else {
			maxCards = currentCards; 	
		}
		
		ascent(i in 0..maxCards) {
			cardArray = cardArray ~ [miniSpellCard];
			if(!isDuetCard) {
				ObjRender_SetPosition(cardArray[i],nextX+i*10,48,0);
			} else {
				ObjRender_SetPosition(cardArray[i],nextX+i*10,68,0);
			}
		}
	}
	ascent(i in 0..length(cardArray)) { Obj_Delete(cardArray[i]); } 
}

function miniSpellCard() {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj,90); 
	ObjPrim_SetTexture(obj,imgMiniCard); 
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	ObjRender_SetAlpha(obj,255);
	ObjSprite2D_SetSourceRect(obj,0,0,8,12);
	ObjRender_SetColor(obj,255,255,255);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	ObjSprite2D_SetDestCenter(obj);
	ObjRender_SetPosition(obj,48,48,0);
	
	return obj;
}

task hudSpellTimer() {
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let maxDigit = 1;

	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,0.68,0.68,0);
	ObjRender_SetY(obj,12);
	
	let objScene = ID_INVALID;
	
	loop {
		objScene = GetEnemyBossSceneObjectID;
		ObjSpriteList2D_ClearVertexCount(obj);
		if(objScene != ID_INVALID && !GetCommonData("isDialogue",false)) {
			drawSpellTime;
		}
		else {

		}
		
		function drawSpellTime {
			let spellTime = ObjEnemyBossScene_GetInfo(objScene,INFO_TIMER);
			if(spellTime < 99) { maxDigit = 2; spellTime = min(spellTime,99); } 
			if(spellTime > 99 && spellTime < 999) { maxDigit = 3; spellTime = min(spellTime,999); }

			let listNum = DigitToArray(spellTime,maxDigit);
			ObjSpriteList2D_ClearVertexCount(obj);
			ascent(i in 0..maxDigit) {
				let num = listNum[i];
				if(maxDigit == 1) { ObjRender_SetX(obj,396+i*11); }
				if(maxDigit == 2) { ObjRender_SetX(obj,384+i*11); }
				if(maxDigit == 3) { ObjRender_SetX(obj,372+i*11); }
				ObjSpriteList2D_SetSourceRect(obj,num*20,321,(num + 1)*20,352);
				ObjSpriteList2D_SetDestRect(obj,0,0,24,38);
				ObjSpriteList2D_AddVertex(obj);
			}	
		}			
		yield;
	}	
}

task hudSpellInfo() { 

	// Capture
	let maxDigit = 1;
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	// captures
	ObjPrim_SetTexture(obj,menuitems);
	ObjRender_SetBlendType(obj,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj,90);
	ObjRender_SetScaleXYZ(obj,1,1,0);
	ObjRender_SetY(obj,53);
	
	// History
	let maxDigit2 = 1;
	let obj2 = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	// history
	ObjPrim_SetTexture(obj2,menuitems);
	ObjRender_SetBlendType(obj2,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj2,90);
	ObjRender_SetScaleXYZ(obj2,1,1,0);
	ObjRender_SetY(obj2,53);	
	
	// Spell bonus
	let maxDigit3 = 1;
	let obj3 = ObjPrim_Create(OBJ_SPRITE_LIST_2D);	// history
	ObjPrim_SetTexture(obj3,menuitems);
	ObjRender_SetBlendType(obj3,BLEND_ALPHA);
	Obj_SetRenderPriorityI(obj3,90);
	ObjRender_SetScaleXYZ(obj3,1,1,0);
	ObjRender_SetY(obj3,53);		
	
	// Texture bg
	let obj4 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj4,89); 
	ObjPrim_SetTexture(obj4,menuitems); 
	ObjRender_SetBlendType(obj4,BLEND_ALPHA);
	ObjRender_SetAlpha(obj4,255);
	ObjSprite2D_SetSourceRect(obj4,0,640,256,704);
	ObjRender_SetScaleXYZ(obj4,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj4);
	ObjRender_SetPosition(obj4,304,48,0);	
		
	// Failed/bonus indicator
	let obj5 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj5,90); 
	ObjPrim_SetTexture(obj5,menuitems); 
	ObjRender_SetBlendType(obj5,BLEND_ALPHA);
	ObjRender_SetAlpha(obj5,255);
	ObjSprite2D_SetSourceRect(obj5,64,304,128,320);			// bonus
	//ObjSprite2D_SetSourceRect(obj5,128,304,192,320);		// failed
	ObjRender_SetScaleXYZ(obj5,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj5);
	ObjRender_SetPosition(obj5,230,61,0);	
	
	// History text 
	let obj6 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj6,90); 
	ObjPrim_SetTexture(obj6,menuitems); 
	ObjRender_SetBlendType(obj6,BLEND_ALPHA);
	ObjRender_SetAlpha(obj6,255);
	ObjSprite2D_SetSourceRect(obj6,0,304,64,320);
	ObjRender_SetScaleXYZ(obj6,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj6);
	ObjRender_SetPosition(obj6,334,61,0);		
	
	// Slash
	let obj7 = ObjPrim_Create(OBJ_SPRITE_2D);
	Obj_SetRenderPriorityI(obj7,90); 
	ObjPrim_SetTexture(obj7,menuitems); 
	ObjRender_SetBlendType(obj7,BLEND_ALPHA);
	ObjRender_SetAlpha(obj7,255);
	ObjSprite2D_SetSourceRect(obj7,100,288,110,304);
	ObjRender_SetColor(obj7,128,255,255);
	ObjRender_SetScaleXYZ(obj7,1.0,1.0,0);
	ObjSprite2D_SetDestCenter(obj7);
	ObjRender_SetPosition(obj7,383,61,0);	
	
	// Spell card name
	let objSpellName = ObjText_Create;
	Obj_SetRenderPriorityI(objSpellName,90); 	
	ObjRender_SetAlpha(objSpellName,255);
	ObjText_SetFontType(objSpellName,"MeiryoKe_PGothic");	
	ObjText_SetFontSize(objSpellName,15);
	ObjText_SetFontColorTop(objSpellName,255,255,255);
	ObjText_SetFontColorBottom(objSpellName,255,255,255);
	ObjText_SetFontBorderWidth(objSpellName,2); 
	ObjText_SetSidePitch(objSpellName,-2);
	ObjText_SetFontBorderType(objSpellName,BORDER_SHADOW);
	ObjText_SetFontBorderColor(objSpellName,0,0,0);	
	ObjText_SetMaxWidth(objSpellName,260);
	ObjText_SetHorizontalAlignment(objSpellName,ALIGNMENT_RIGHT);
	ObjRender_SetPosition(objSpellName,154,32,0);
	ObjText_SetText(objSpellName,"");

	let getSpellCardInfo = 0;
	let capture = 0;
	let history = 0; 
	let spellbonus = 0;
	let objScene = ID_INVALID;
	let txtAlpha = 255;
	let spellInfoArr = [obj, obj2, obj3, obj4, obj5, obj6, obj7, objSpellName];
	
	loop {
		objScene = GetEnemyBossSceneObjectID;
		ObjSpriteList2D_ClearVertexCount(obj);
		ObjSpriteList2D_ClearVertexCount(obj2);
		ObjSpriteList2D_ClearVertexCount(obj3);
		
		if(objScene != ID_INVALID && !GetCommonData("isDialogue",false) && ObjEnemyBossScene_GetInfo(objScene,INFO_IS_SPELL)) {
			drawSpellInfo;	
			if(!infoAnimOnce) { 			
				spellInfoGlitter; 
				infoAnimOnce = true;
			}
		} else {
			ascent(i in 0..length(spellInfoArr)) { 
				ObjRender_SetAlpha(spellInfoArr[i],0);
				txtAlpha = 0;
			}		
		}
		yield;
	}
	
	function drawSpellInfo() {
		let updateHistory = GetAreaCommonData("core",getResultCard,[0,0,0,0,0,0,0]);
		
		if(GetAreaCommonData("game","menuFlow",0) == 0) {
		    capture = updateHistory[1];
		    history = updateHistory[2];
        }
		else if(GetAreaCommonData("game","menuFlow",0) == 4) {
		    capture = updateHistory[3];
		    history = updateHistory[4];
        }
	
		// Draw the spell card name
		ObjText_SetText(objSpellName,GetCommonData("cardName","Missing Name"));
		
		// Reveal all info because this is a spell.
		ascent(i in 0..length(spellInfoArr)) { 
			ObjRender_SetAlpha(spellInfoArr[i],txtAlpha);
			if(txtAlpha < 254) { ObjRender_SetAlpha(objSpellName,txtAlpha); txtAlpha+=0.5; } 
		}	
		// If player is near this info, make it all transparent. 
		if(GetPlayerX > GetClipMaxX-226 && GetPlayerY <= GetClipMinY+64) { 
			ascent(i in 0..length(spellInfoArr)) { 
				ObjRender_SetAlpha(spellInfoArr[i],55);
			}
		}	

		// Check if player went pichuun during spell and handle stuff
		if(isPichuun) {
		    ObjSprite2D_SetSourceRect(obj5,128,304,192,320);
        }
		if(ObjEnemyBossScene_GetInfo(objScene,INFO_PLAYER_SHOOTDOWN_COUNT) > 0 || ObjEnemyBossScene_GetInfo(objScene,INFO_PLAYER_SPELL_COUNT) > 0) {
		    isPichuun = true;
		    spellbonus = 0;
        }
		else { 
			spellbonus = ObjEnemyBossScene_GetInfo(objScene,INFO_SPELL_SCORE); 
			ObjSprite2D_SetSourceRect(obj5,64,304,128,320);	
		}
		
		// digits for captures
		if(capture < 9) { maxDigit = 1; capture = min(capture,9); } 
		if(capture > 9 && capture < 99) { maxDigit = 2; capture = min(capture,99); } 
		if(capture > 99 && capture < 999) { maxDigit = 3; capture = min(capture,999); }
		if(capture > 999 && capture < 9999) { maxDigit = 4; capture = min(capture,9999); }	
		if(capture > 9999 && capture < 99999) { maxDigit = 5; capture = min(capture,99999); }	
		
		// digits for attempts
		if(history < 9) { maxDigit2 = 1; history = min(history,9); } 
		if(history > 9 && history < 99) { maxDigit2 = 2; history = min(history,99); } 
		if(history > 99 && history < 999) { maxDigit2 = 3; history = min(history,999); }
		if(history > 999 && history < 9999) { maxDigit2 = 4; history = min(history,9999); }	
		if(history > 9999 && history < 99999) { maxDigit2 = 5; history = min(history,99999); }				

		// digits for spell bonus
		if(spellbonus < 9) { maxDigit3 = 1; spellbonus = min(spellbonus,9); } 
		if(spellbonus > 9 && spellbonus < 99) { maxDigit3 = 2; spellbonus = min(spellbonus,99); } 
		if(spellbonus > 99 && spellbonus < 999) { maxDigit3 = 3; spellbonus = min(spellbonus,999); }
		if(spellbonus > 999 && spellbonus < 9999) { maxDigit3 = 4; spellbonus = min(spellbonus,9999); }	
		if(spellbonus > 9999 && spellbonus < 99999) { maxDigit3 = 5; spellbonus = min(spellbonus,99999); }				
		if(spellbonus > 99999 && spellbonus < 999999) { maxDigit3 = 6; spellbonus = min(spellbonus,999999); } 
		if(spellbonus > 999999 && spellbonus < 9999999) { maxDigit3 = 7; spellbonus = min(spellbonus,9999999); } 
		if(spellbonus > 9999999 && spellbonus < 99999999) { maxDigit3 = 8; spellbonus = min(spellbonus,99999999); } 
		
		let listNum = DigitToArray(capture,maxDigit);
		let listNum2 = DigitToArray(history,maxDigit2);
		let listNum3 = DigitToArray(spellbonus,maxDigit3);
		ObjSpriteList2D_ClearVertexCount(obj);
		ObjSpriteList2D_ClearVertexCount(obj2);
		ObjSpriteList2D_ClearVertexCount(obj3);
		
		// captures
		ascent(i in 0..maxDigit) {
			let num = listNum[i];
			if(maxDigit == 1) { ObjRender_SetX(obj,370+i*7); }
			if(maxDigit == 2) { ObjRender_SetX(obj,363+i*7); }
			if(maxDigit == 3) { ObjRender_SetX(obj,356+i*7); }
			if(maxDigit == 4) { ObjRender_SetX(obj,349+i*7); }
			ObjSpriteList2D_SetSourceRect(obj,num*10,288,(num + 1)*10,304);
			ObjSpriteList2D_SetDestRect(obj,0,0,10,16);
			ObjSpriteList2D_AddVertex(obj);
		}
		// history
		ascent(i in 0..maxDigit2) {
			let num2 = listNum2[i];
			if(maxDigit2 == 1) { ObjRender_SetX(obj2,405+i*7); }
			if(maxDigit2 == 2) { ObjRender_SetX(obj2,398+i*7); }
			if(maxDigit2 == 3) { ObjRender_SetX(obj2,391+i*7); }
			if(maxDigit2 == 4) { ObjRender_SetX(obj2,384+i*7); }
			ObjSpriteList2D_SetSourceRect(obj2,num2*10,288,(num2 + 1)*10,304);
			ObjSpriteList2D_SetDestRect(obj2,0,0,10,16);
			ObjSpriteList2D_AddVertex(obj2);	
		}
		// spell bonus
		ascent(i in 0..maxDigit3) {	
			let num3 = listNum3[i];
			if(maxDigit3 == 1) { ObjRender_SetX(obj3,298+i*7); }
			if(maxDigit3 == 2) { ObjRender_SetX(obj3,291+i*7); }
			if(maxDigit3 == 3) { ObjRender_SetX(obj3,284+i*7); }
			if(maxDigit3 == 4) { ObjRender_SetX(obj3,277+i*7); }
			if(maxDigit3 == 5) { ObjRender_SetX(obj3,270+i*7); }	
			if(maxDigit3 == 6) { ObjRender_SetX(obj3,263+i*7); }
			if(maxDigit3 == 7) { ObjRender_SetX(obj3,255+i*7); }
			if(maxDigit3 == 8) { ObjRender_SetX(obj3,248+i*7); }		
			ObjSpriteList2D_SetSourceRect(obj3,num3*10,288,(num3 + 1)*10,304);
			ObjSpriteList2D_SetDestRect(obj3,0,0,10,16);
			ObjSpriteList2D_AddVertex(obj3);	
		}	
	}			
}

task spellInfoGlitter() {
	// red, green, blue, cyan, purple, yellow, orange
	let colSet = [[255,16,16], [16,255,16], [16,16,255], [16,255,255], [255,16,255], [255,255,16], [255,128,16]];
	let colKies = 0;	
	let dir = 0;
	
	ascent(i in 0..16) { 
		colKies = rand_int(0, 7);
		hudGlitter(224+16*cos(dir), 48+16*sin(dir), rand(0.1,0.5), rand_int(0,360), rand(0.2,1.5), 255, colSet[colKies][0], colSet[colKies][1], colSet[colKies][2]);
		hudGlitter(224+16*cos(dir+180), 48+16*sin(dir+180), rand(0.1,0.5),rand_int(0,360), rand(0.2,1.5),255, colSet[colKies][0], colSet[colKies][1], colSet[colKies][2]);
		hudGlitter(224+i*12, rand_int(32,64), rand(0.1,0.5), rand_int(0,360), rand(0.2,1.5), 255, colSet[colKies][0], colSet[colKies][1], colSet[colKies][2]);
		dir += 360 / 36;
		yield;
	}
}

task miniCardGlitter(obj) {
	// red, green, blue, cyan, purple, yellow, orange
	let colSet = [[255,16,16], [16,255,16], [16,16,255], [16,255,255], [255,16,255], [255,255,16], [255,128,16]];
	let colKies = 0;	
	let dir = 0;
	
	loop(4) { 
		colKies = rand_int(0,7);
		hudGlitter(ObjRender_GetX(obj)+8*cos(dir), ObjRender_GetY(obj)+8*sin(dir), rand(0.1,0.4), rand_int(0,360), rand(0.1,1.2), 255, colSet[colKies][0], colSet[colKies][1], colSet[colKies][2]);
		hudGlitter(ObjRender_GetX(obj)+8*cos(dir+180), ObjRender_GetY(obj)+8*sin(dir+180), rand(0.1,0.4), rand_int(0,360), rand(0.1,1.2), 255, colSet[colKies][0], colSet[colKies][1], colSet[colKies][2]);
		dir += 360 / 36;
		yield;
	}
}

//------------------------------------------------------------------------------------------------------------------------------------------
// Sounds and aid 

task timerSFX() {
	let objScene = ID_INVALID;
	loop { 
		objScene = GetEnemyBossSceneObjectID;
		if(objScene != ID_INVALID && !GetCommonData("isDialogue", false)) {
			timerCheck;
		} 
		function timerCheck {
			if(GetTimer > 3 && GetTimer <= 10) { PlaySFX(SFX_TIMEOUT); }
			if(GetTimer <= 3) { PlaySFX(SFX_TIMEOUT2); }
			wait(60);	
		}
		yield;
	}
}

task ouchSFX() {
	let objScene = ID_INVALID;
    let hpL = ObjEnemy_GetInfo(bossObj, INFO_LIFE) / 100 * 15;
	
	loop { 
		objScene = GetEnemyBossSceneObjectID;
		if(objScene != ID_INVALID && !GetCommonData("isDialogue", false)) {
			if(ObjEnemy_GetInfo(bossObj, INFO_SHOT_HIT_COUNT) > 0) {
				damageCheck;
			}			
		} 
		yield;
	}
	function damageCheck {
		wait(3.3);
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > hpL) { PlaySFX(SFX_DAMAGE00); }
		if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= hpL) { PlaySFX(SFX_DAMAGE01); }
	}
}

task ouch2SFX() {
	let objScene = ID_INVALID;
    let hpL = ObjEnemy_GetInfo(boss2Obj, INFO_LIFE) / 100 * 15;

	loop { 
		objScene = GetEnemyBossSceneObjectID;
		if(objScene != ID_INVALID && !GetCommonData("isDialogue", false) && isDuetCard) {
			if(ObjEnemy_GetInfo(boss2Obj, INFO_SHOT_HIT_COUNT) > 0) {
				damageCheck;
			}			
		} 
		function damageCheck {
			wait(3.3);
			if(ObjEnemy_GetInfo(boss2Obj, INFO_LIFE) > hpL) { PlaySFX(SFX_DAMAGE00); }
			if(ObjEnemy_GetInfo(boss2Obj, INFO_LIFE) <= hpL) { PlaySFX(SFX_DAMAGE01); }
		}
		yield;
	}
}

function bossFunkyCircle() { 
	let path = "script/thdcs/functions/function_spellcircle.txt";
	let id = LoadScript(path);
	StartScript(id);
} 

//------------------------------------------------------------------------------------------------------------------------------------------
// Core aid

function locateBossID() {
    bossObj = GetEnemyBossObjectID[0];
	if(isDuetCard) { 
		boss2Obj = GetAllEnemyID[1]; 
	} 
	else { 

	}

	if(GetCommonData("bossAttackType", 0) == 2) {
		let bossScene = GetEnemyBossSceneObjectID(); 
		ObjEnemyBossScene_StartSpell(bossScene); 
	}
} 

task bossMagicCircle() {
	let obj = ObjPrim_Create(OBJ_PRIMITIVE_2D);
	let cardtype = 0;
	let objScene = ID_INVALID;
	let circleSize = 112;
	let circleX = 0;
	let circleSpinValue = 0;
	let circleScale = 0.8;
	let circleFrame = 0;
	
	ObjPrim_SetPrimitiveType(obj, PRIMITIVE_TRIANGLEFAN);
	ObjRender_SetBlendType(obj, BLEND_ADD_RGB);
	
	if(cardtype == 0) { 
		ObjPrim_SetTexture(obj,magicCircTex); 
	}
	if(cardtype == 1 || cardtype == 2 || cardtype == 3) { 
		ObjPrim_SetTexture(obj,spellCircTex); 
	}
	
	ObjRender_SetScaleXYZ(obj, circleScale, circleScale, 0);
	Obj_SetRenderPriorityI(obj, 21);
	ObjRender_SetAlpha(obj, 0);
	ObjPrim_SetVertexCount(obj, 37);
	ObjPrim_SetVertexPosition(obj, 0, 0, 0, 0);
	ObjPrim_SetVertexUVT(obj, 0, 64,64);

	loop {
		objScene = GetEnemyBossSceneObjectID;
		if(objScene != ID_INVALID && !GetCommonData("isDialogue", false)) {
			animMagicCircle;
			ascent(i in 0..37) { 
				ObjPrim_SetVertexColor(obj, i, 255, 255, 255);
			} 
			ObjRender_SetPosition(obj, bossX, bossY, 0);
			ObjRender_SetAlpha(obj, 255);
		} 		
		else {
			ascent(i in 0..37) { 
				ObjPrim_SetVertexColor(obj, i, 0, 0, 0);
			} 
			ObjRender_SetAlpha(obj, 0);
		}
		yield;
	}

	function animMagicCircle {
		cardtype = GetCommonData("bossCircleType", 0);
		if(cardtype == 0) { 
			ObjPrim_SetTexture(obj,magicCircTex); 
		}
		if(cardtype == 1 || cardtype == 2 || cardtype == 3) { 
			ObjPrim_SetTexture(obj, spellCircTex);
		}
	
		ascent(circleX in 0..37) {
				ObjPrim_SetVertexPosition(obj,circleX,circleSize*cos(circleX*360/35)+floor(rand(circblur,circblur2)),circleSize*sin(circleX*360/35)+floor(rand(circblur,circblur2)),0);
				if(cardtype == 0) { ObjPrim_SetVertexUVT(obj,circleX,64*cos(circleX*360/35)+64,64*sin(circleX*360/35)+64); }
				if(cardtype == 1) { ObjPrim_SetVertexUVT(obj,circleX,128*cos(circleX*360/35)+128,128*sin(circleX*360/35)+128); }
				if(cardtype == 2) { ObjPrim_SetVertexUVT(obj,circleX,128*cos(circleX*360/35)+384,128*sin(circleX*360/35)+128); }
				if(cardtype == 3) { ObjPrim_SetVertexUVT(obj,circleX,128*cos(circleX*360/35)+640,128*sin(circleX*360/35)+128); }
		}
		
		ObjRender_SetPosition(obj, bossX, bossY, 0);
		ObjRender_SetAngleZ(obj, circleSpinValue);
		ObjRender_SetScaleXYZ(obj, circleScale, circleScale, 0);
		circleSpinValue -= 3;
		circleScale += sin(circleFrame) / 220;
		circleFrame += 2;
	}   
}

task distortCirc(t,m) {
	let timer = 0;
	let magnitute = m;

	while(timer < t) { 
		circblur = 1; circblur2 = m*sin(180/t*timer); 
		timer++;
		yield;
	}
	circblur = 0; circblur2 = 0;
}

//------------------------------------------------------------------------------------------------------------------------------------------
// Background

task renderBG(type) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj2 = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj3 = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj4 = ObjPrim_Create(OBJ_SPRITE_2D);
	let obj5 = ObjPrim_Create(OBJ_SPRITE_2D);
	
	let bgswitch = 0;
	let bgcounter = 0;
	let bgscroll = 0;
	let bgspin = 0;
	let bgframe = 0;
	let fader = 0;
	
	if(type == 1) { 
		// Under bg
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,ballBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,200);
		ObjSprite2D_SetSourceRect(obj,0,0,384,448);
		ObjRender_SetScaleXYZ(obj,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,92,92,92);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		
		
		// Layer 1 (can be animating)
		Obj_SetRenderPriorityI(obj2,20); 
		ObjPrim_SetTexture(obj2,ballLay); 
		ObjRender_SetBlendType(obj2,BLEND_ALPHA);	
		ObjRender_SetAlpha(obj2,fader);
		ObjSprite2D_SetSourceRect(obj2,0,0,256,512);
		ObjRender_SetScaleXYZ(obj2,1.5,1.0,0);
		ObjSprite2D_SetDestCenter(obj2);
		ObjRender_SetColor(obj2,255,155,155);
		ObjRender_SetPosition(obj2,GetCenterX,GetCenterY,0);	
		
		// Layer 2 (can be animating)
		Obj_SetRenderPriorityI(obj3,20); 
		ObjPrim_SetTexture(obj3,ballLay2); 
		ObjRender_SetBlendType(obj3,BLEND_ALPHA);	
		ObjRender_SetAlpha(obj3,0);
		ObjSprite2D_SetSourceRect(obj3,0,0,512,512);
		ObjRender_SetScaleXYZ(obj3,1.2,1.2,0);
		ObjSprite2D_SetDestCenter(obj3);
		ObjRender_SetColor(obj3,72,144,72);
		ObjRender_SetAngleX(obj3,180);
		ObjRender_SetPosition(obj3,GetCenterX,GetCenterY,0);	
		
		// Layer 3 (can be animating)
		Obj_SetRenderPriorityI(obj4,20); 
		ObjPrim_SetTexture(obj4,ballLay2); 
		ObjRender_SetBlendType(obj4,BLEND_ALPHA);	
		ObjRender_SetAlpha(obj4,0);
		ObjSprite2D_SetSourceRect(obj4,0,0,512,512);
		ObjRender_SetScaleXYZ(obj4,1.2,1.2,0);
		ObjSprite2D_SetDestCenter(obj4);
		ObjRender_SetColor(obj4,72,144,72);
		ObjRender_SetPosition(obj4,GetCenterX,GetCenterY,0);
	}
	if(type == 2) { 
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,afroBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,255);
		ObjSprite2D_SetSourceRect(obj,0,0,512,512);
		ObjRender_SetScaleXYZ(obj,0.0,0.0,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,255,255,255);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		

		Obj_SetRenderPriorityI(obj2,20); 
		ObjPrim_SetTexture(obj2,afroBg2); 
		ObjRender_SetBlendType(obj2,BLEND_ALPHA);
		ObjRender_SetAlpha(obj2,255);
		ObjSprite2D_SetSourceRect(obj2,0,0,512,512);
		ObjRender_SetScaleXYZ(obj2,0.0,0.0,0);
		ObjSprite2D_SetDestCenter(obj2);
		ObjRender_SetColor(obj2,255,255,255);
		ObjRender_SetPosition(obj2,GetCenterX,GetCenterY,0);	

		Obj_SetRenderPriorityI(obj3,20); 
		ObjPrim_SetTexture(obj3,afroBg3); 
		ObjRender_SetBlendType(obj3,BLEND_ALPHA);
		ObjRender_SetAlpha(obj3,255);
		ObjSprite2D_SetSourceRect(obj3,0,0,512,512);
		ObjRender_SetScaleXYZ(obj3,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj3);
		ObjRender_SetColor(obj3,255,255,255);
		ObjRender_SetPosition(obj3,GetCenterX,GetCenterY,0);	

		Obj_SetRenderPriorityI(obj4,20); 
		ObjPrim_SetTexture(obj4,afroBg4); 
		ObjRender_SetBlendType(obj4,BLEND_ALPHA);
		ObjRender_SetAlpha(obj4,255);
		ObjSprite2D_SetSourceRect(obj4,0,0,512,512);
		ObjRender_SetScaleXYZ(obj4,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj4);
		ObjRender_SetColor(obj4,255,255,255);
		ObjRender_SetPosition(obj4,GetCenterX,GetCenterY,0);			
		
		Obj_SetRenderPriorityI(obj5,20); 
		ObjPrim_SetTexture(obj5,afroLay); 
		ObjRender_SetBlendType(obj5,BLEND_ALPHA);
		ObjRender_SetAlpha(obj5,35);
		ObjSprite2D_SetSourceRect(obj5,0,0,512,512);
		ObjRender_SetScaleXYZ(obj5,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj5);
		ObjRender_SetColor(obj5,255,255,255);
		ObjRender_SetPosition(obj5,GetCenterX,GetCenterY,0);			
	}
	if(type == 21) { 
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,ufoBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,255);
		ObjSprite2D_SetSourceRect(obj,0,0,512,512);
		ObjRender_SetScaleXYZ(obj4,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,55,55,55);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		

		Obj_SetRenderPriorityI(obj4,20); 
		ObjPrim_SetTexture(obj4,ufoLay); 
		ObjRender_SetBlendType(obj4,BLEND_ALPHA);
		ObjRender_SetAlpha(obj4,35);
		ObjSprite2D_SetSourceRect(obj4,0,0,512,512);
		ObjRender_SetScaleXYZ(obj4,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj4);
		ObjRender_SetColor(obj4,255,255,255);
		ObjRender_SetPosition(obj4,GetCenterX,GetCenterY,0);	
		
		Obj_SetRenderPriorityI(obj5,20); 
		ObjPrim_SetTexture(obj5,ufoLay); 
		ObjRender_SetBlendType(obj5,BLEND_ALPHA);
		ObjRender_SetAlpha(obj5,35);
		ObjSprite2D_SetSourceRect(obj5,0,0,512,512);
		ObjRender_SetScaleXYZ(obj5,1.0,1.0,0);
		ObjRender_SetAngleXYZ(obj5,0,180,0);
		ObjSprite2D_SetDestCenter(obj5);
		ObjRender_SetColor(obj5,255,255,255);
		ObjRender_SetPosition(obj5,GetCenterX,GetCenterY,0);		
	}
	if(type == 3) { 
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,djBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,255);
		ObjSprite2D_SetSourceRect(obj,0,0,512,512);
		ObjRender_SetScaleXYZ(obj,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,192,192,192);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		

		Obj_SetRenderPriorityI(obj2,20); 
		ObjPrim_SetTexture(obj2,djGram); 
		ObjRender_SetBlendType(obj2,BLEND_ALPHA);
		ObjRender_SetAlpha(obj2,128);
		ObjSprite2D_SetSourceRect(obj2,0,0,512,512);
		ObjRender_SetScaleXYZ(obj2,0.7,0.7,0);
		ObjSprite2D_SetDestCenter(obj2);
		ObjRender_SetColor(obj2,64,64,255);
		ObjRender_SetPosition(obj2,GetCenterX,GetClipMaxY,0);	

		Obj_SetRenderPriorityI(obj3,20); 
		ObjPrim_SetTexture(obj3,djGram); 
		ObjRender_SetBlendType(obj3,BLEND_ALPHA);
		ObjRender_SetAlpha(obj3,128);
		ObjSprite2D_SetSourceRect(obj3,0,0,512,512);
		ObjRender_SetScaleXYZ(obj3,1.0,1.0,0);
		ObjSprite2D_SetDestCenter(obj3);
		ObjRender_SetColor(obj3,64,255,64);
		ObjRender_SetPosition(obj3,GetClipMinX,GetClipMinY,0);

		Obj_SetRenderPriorityI(obj4,20); 
		ObjPrim_SetTexture(obj4,djGram); 
		ObjRender_SetBlendType(obj4,BLEND_ALPHA);
		ObjRender_SetAlpha(obj4,128);
		ObjSprite2D_SetSourceRect(obj4,0,0,512,512);
		ObjRender_SetScaleXYZ(obj4,0.5,0.5,0);
		ObjSprite2D_SetDestCenter(obj4);
		ObjRender_SetColor(obj4,255,64,64);
		ObjRender_SetPosition(obj4,GetClipMaxX,GetCenterY,0);
	}
	if(type == 31) { 
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,borderBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,255);
		ObjSprite2D_SetSourceRect(obj,0,0,512,512);
		ObjRender_SetScaleXYZ(obj,0.9,0.9,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,192,192,192);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		
		
		Obj_SetRenderPriorityI(obj2,20); 
		ObjPrim_SetTexture(obj2,borderLay);
		ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);	
		ObjRender_SetAlpha(obj2,55);
		ObjSprite2D_SetSourceRect(obj2,0,0,512,512);
		ObjRender_SetScaleXYZ(obj2,1,1,0);
		ObjSprite2D_SetDestCenter(obj2);
		ObjRender_SetColor(obj2,255,255,255);
		ObjRender_SetPosition(obj2,GetCenterX,GetCenterY,0);
	}	
	if(type == 32) { 
		Obj_SetRenderPriorityI(obj,20); 
		ObjPrim_SetTexture(obj,magicBg); 
		ObjRender_SetBlendType(obj,BLEND_ALPHA);
		ObjRender_SetAlpha(obj,155);
		ObjSprite2D_SetSourceRect(obj,0,0,512,512);
		ObjRender_SetScaleXYZ(obj,0.8,0.9,0);
		ObjSprite2D_SetDestCenter(obj);
		ObjRender_SetColor(obj,192,192,192);
		ObjRender_SetPosition(obj,GetCenterX,GetCenterY,0);		
		
		Obj_SetRenderPriorityI(obj2,20); 
		ObjPrim_SetTexture(obj2,magicLay); 
		ObjRender_SetBlendType(obj2,BLEND_ADD_ARGB);	
		ObjRender_SetAlpha(obj2,55);
		ObjSprite2D_SetSourceRect(obj2,0,0,1024,1024);
		ObjRender_SetScaleXYZ(obj2,0.7,0.7,0);
		ObjSprite2D_SetDestCenter(obj2);
		ObjRender_SetColor(obj2,64,64,255);
		ObjRender_SetPosition(obj2,GetCenterX,GetCenterY,0);		
	}
	// Anim
	while(!Obj_IsDeleted(bossObj)) {
		if(type == 1) { 
			ObjSprite2D_SetSourceRect(obj2,0,0+bgscroll,256,256+bgscroll);
			bgscroll+=0.5;
			bgspin+=0.5;
			ObjRender_SetAlpha(obj2,-fader+125);
			ObjRender_SetAlpha(obj3,fader);
			ObjRender_SetAlpha(obj4,fader);
			ObjRender_SetAngleZ(obj3,bgspin);
			ObjRender_SetAngleZ(obj4,bgspin);
			if(bgswitch == 0) { 
				fader+=0.5; 
				if(fader >= 60) { 
					bgswitch = 1; 
				} 
			}
			if(bgswitch == 1) { 
				fader-=0.5; 
				if(fader <= 10) { 
					bgswitch = 0; 
				} 
			}
		}
		if(type == 2) {
			if(bgcounter < 10) { 
				ObjRender_SetScaleXYZ(obj,1.0,1.0,0); 
				ObjRender_SetScaleXYZ(obj2,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj3,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj4,0.0,0.0,0); 
			}
			if(bgcounter >= 10 && bgcounter < 20) { 
				ObjRender_SetScaleXYZ(obj,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj2,1.0,1.0,0); 
				ObjRender_SetScaleXYZ(obj3,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj4,0.0,0.0,0); 
			}
			if(bgcounter >= 20 && bgcounter < 30) { 
				ObjRender_SetScaleXYZ(obj,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj2,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj3,1.0,1.0,0); 
				ObjRender_SetScaleXYZ(obj4,0.0,0.0,0); 
			}
			if(bgcounter >= 30) { 
				ObjRender_SetScaleXYZ(obj,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj2,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj3,0.0,0.0,0); 
				ObjRender_SetScaleXYZ(obj4,1.0,1.0,0); 
			}
			if(bgcounter == 40) { 
				bgcounter = 0; 
			}
			ObjSprite2D_SetSourceRect(obj5,0-bgframe,0-bgframe,512-bgframe,512-bgframe);
			bgcounter++;
			bgframe++;
		}
		if(type == 21) {
			ObjSprite2D_SetSourceRect(obj4,0,0+bgframe,512,512+bgframe);
			ObjSprite2D_SetSourceRect(obj5,0,0-bgframe,512,512-bgframe);
			bgframe+=4;
		}
		if(type == 3) { 
			ObjRender_SetAngleZ(obj2,bgspin);
			ObjRender_SetAngleZ(obj3,bgspin);
			ObjRender_SetAngleZ(obj4,-bgspin);
			bgspin+=5;
		}
		if(type == 31) {
			ObjSprite2D_SetSourceRect(obj2, 0, 0+bgscroll, 512, 512+bgscroll);
			bgscroll += 2;
		}
		if(type == 32) {
			bgspin+=1;
			ObjRender_SetAngleZ(obj2,bgspin);
		}
		yield;
	}	
	Obj_Delete(obj); Obj_Delete(obj2); Obj_Delete(obj3); Obj_Delete(obj4); Obj_Delete(obj5);
} 

task breakEffectGlitter(x,y,v,dir,parts,alphaValue,red,green,blue) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let partc = 0;

	ObjPrim_SetTexture(obj,circglit);
	ObjRender_SetBlendType(obj,BLEND_ADD_ARGB);
	Obj_SetRenderPriorityI(obj,30);
	ObjRender_SetPosition(obj,x,y,0);
	ObjMove_SetSpeed(obj,v);
	ObjMove_SetAngle(obj,dir);
	ObjRender_SetScaleXYZ(obj,parts,parts,0);
	ObjSprite2D_SetSourceRect(obj,0,0,64,64);
	ObjSprite2D_SetDestCenter(obj);

	ObjMove_Special(obj,x,y,v,dir);
	
	while(! Obj_IsDeleted(obj)) {
		ObjRender_SetColor(obj,red,green,blue); 
		ObjRender_SetAlpha(obj,alphaValue);
		ObjRender_SetScaleXYZ(obj,parts,parts,0);

		parts = rand(1,1.5)*sin(partc*round(rand(10,20)));
		partc++;

		if(partc > round(rand(90,180))) {
			Obj_Delete(obj); 
		}

		yield;
	}
}

task breakEffect(red,green,blue) {
	let dir = 0;
	loop(18) {
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18) {
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18) {
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
	yield;
	loop(18) {
		breakEffectGlitter(bossX+GetCommonData("circFinalSize",false)*cos(dir),bossY+GetCommonData("circFinalSize",false)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		breakEffectGlitter(bossX+(GetCommonData("circFinalSize",false)*cos(dir)-10),bossY+(GetCommonData("circFinalSize",false)-10)*sin(dir),rand(0.5,2),dir,round(rand(2,4)),255,red,green,blue);
		dir+=360/72;
	}
}

task explosionspray(obj) {
	let x = 0;
	let dir = 0;
	let scaler = 0;

	PlaySFX(SFX_ENEP00);
	
	while(x < 72) {
		yield;
		mapleexplo(ObjMove_GetX(obj),ObjMove_GetY(obj),rand_int(2,4),dir,scaler,scaler,rand_int(1,4));
		dir+=13.7;
		x++;
	}
	explosioncustom(obj);
}

task explosioncustom(obj) {
	let x = 0;
	let scaler = 0;

	PlaySFX(SFX_ENEP01);

	while(x < 24) {
		scaler = rand(1,3);
		mapleexplo(ObjMove_GetX(obj),ObjMove_GetY(obj),3,rand(0,359),scaler,scaler,rand_int(1,4));
		mapleexplo(ObjMove_GetX(obj),ObjMove_GetY(obj),2.8,rand(0,359),scaler,scaler,rand_int(1,4));
		mapleexplo(ObjMove_GetX(obj),ObjMove_GetY(obj),2.6,rand(0,359),scaler,scaler,rand_int(1,4));
		x++;
	}
}

task mapleexplo(x,y,v,dir,sx,sy,color) {
	let obj = ObjPrim_Create(OBJ_SPRITE_2D);
	let alphaValue = 0;
	let as = 0;
	let c = 0;
	let scalex = sx;
	let scaley = sy;
	let spinny = rand_int(-4, 4);
	let randomspinny = rand(1, 2);
	
	ObjPrim_SetTexture(obj, boom);
	ObjRender_SetBlendType(obj, BLEND_ADD_RGB);
	Obj_SetRenderPriorityI(obj, 30);
	ObjRender_SetPosition(obj, x, y, 0);
	ObjRender_SetAlpha(obj, 55);
	ObjMove_SetSpeed(obj, v);
	ObjMove_SetAngle(obj,rand(0, 359));
	ObjRender_SetScaleXYZ(obj, scalex, scaley, 0);
	ObjSprite2D_SetSourceRect(obj, 0, 0, 34, 34);
	ObjSprite2D_SetDestCenter(obj);	
	
	if(color==1) {
		ObjRender_SetColor(obj, 255, 64, 64);
	}
	if(color==2) {
		ObjRender_SetColor(obj, 64, 64, 255);
	}
	if(color==3) {
		ObjRender_SetColor(obj, 64, 255, 64);
	}
	if(color==4) {
		ObjRender_SetColor(obj, 255, 64, 255);
	}

	ObjMove_Special(obj,x,y,v,dir);
	
	while(!Obj_IsDeleted(obj)) {
		ObjRender_SetScaleXYZ(obj, scalex, scaley, 0);
		ObjRender_SetAngleZ(obj, spinny);

		if(c < 30) { 
			scalex += 0.1;
			scaley += 0.1;
		}
		if(c >= 30) { 
			if(scaley >= 0) {
				scalex -= 0.1;
				scaley -= 0.1;
			} 
		}
		if(scaley < 0) { 
			Obj_Delete(obj); 
		}

		c++;

		if(randomspinny == 1 && randomspinny <= 1.5) { 
			spinny+=4; 
		}
		if(randomspinny > 1.5 && randomspinny < 2.0) { 
			spinny-=4; 
		}

		yield;
	}
}

// Drake's visible collision script
task showBulletCol() {
	let obj = ObjPrim_Create(OBJ_SPRITE_LIST_2D);
	let colTex = "script/thdcs/system/bcol.png";
	let toggleCol = false;
	
	ObjPrim_SetTexture(obj,colTex);
	ObjSpriteList2D_SetSourceRect(obj, 0, 0, 16, 16);
	Obj_SetRenderPriorityI(obj, 80);
	ObjRender_SetAlpha(obj,255);
	ObjRender_SetPosition(obj, 0, 0, 0);
	ObjRender_SetColor(obj, 255, 255, 255);
	ObjRender_SetBlendType(obj, BLEND_ALPHA);
	 
	let cx = GetStgFrameWidth() / 2;
	let cy = GetStgFrameHeight() / 2;
	 
	loop {
		RenderHitboxes();
		yield;
	}
	 
	function RenderHitboxes() {
		if(GetKeyState(KEY_Y) == KEY_PULL) { 
			if(!toggleCol) {
			    ObjRender_SetAlpha(obj, 255); toggleCol = true;
			}
			else if(toggleCol) {
			    ObjRender_SetAlpha(obj, 0); toggleCol = false;
            }
		}

		ObjSpriteList2D_ClearVertexCount(obj);
		 
		let shots = GetShotIdInCircleA2(cx, cy, cy*2, TARGET_ENEMY);
		 
		ascent(i in 0..length(shots)) {
			let origin = [ObjMove_GetX(shots[i]), ObjMove_GetY(shots[i])];
			let t = ObjMove_GetAngle(shots[i]) - 90; // 90 offset to match with drawing angle
			let id = ObjShot_GetImageID(shots[i]);
			let col = GetShotDataInfoA1(id, TARGET_ENEMY, INFO_COLLISION_LIST);
			
			ascent(j in 0..length(col)) {
				let pos = origin;
				let r = col[j][0];
				 
				if(col[j][1] != 0 || col[j][2] != 0) {
					pos = pos + [col[j][1]*cos(t) - col[j][2]*sin(t), col[j][1]*sin(t) + col[j][2]*cos(t)];
				}
				 
				ObjSpriteList2D_SetDestRect(obj, pos[0]-r, pos[1]-r, pos[0]+r, pos[1]+r);
				ObjSpriteList2D_AddVertex(obj);
			}
		}
	}
}

//------------------------------------------------------------------------------------------------------------------------------------------
// Local functions

function wait(w) { loop(w) { yield; } } 

// Because ObjMove_SetSpeed does not work with Primitive 2D Sprites, I decided to make my own move code.
task ObjMove_Special(obj,x,y,v,dir) {
	let vx = v * cos(dir);
	let vy = v * sin(dir);

	while(!Obj_IsDeleted(obj)) {
		ObjRender_SetPosition(obj, x, y, 0);
		yield;
		x += vx;
		y += vy;
	}
}

// Gets the current time on a spell card or attack.
function GetTimer() {
	let attackTimer = ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID, INFO_TIMER);
	return attackTimer;
}

// Gets the distance beteween two given xy coordinates
function GetDistanceXY(x1,y1,x2,y2) {
	let distance = (((x2-x1)^2+(y2-y1)^2)^(1/2));
	return distance;
}

// Gets the true angle between two points
function GetPointToPointAngle(x1,y1,x2,y2) {
	let dir = atan2(y1-y2, x1-x2);
	return dir;
}

// 0.12m personal transition for rand_int.
function rand_int(min,max) { 
	let rand_int_result;
	rand_int_result = truncate(rand(min,max));
	return rand_int_result;
} 

// Gets the centre X of stage field
function GetCenterX() {
	let calc = GetStgFrameWidth / 2;
	return calc;
}

// Gets the centre of stage field
function GetCenterY() {
	let calc = GetStgFrameHeight / 2; 
	return calc; 
}

// Gets minimum X of stage field ( x = 0 )
function GetClipMinX() { 
	let calc = GetStgFrameWidth - GetStgFrameWidth;
	return calc; 
}

// Gets maximum X of stage field
function GetClipMaxX() { 
	let calc = GetStgFrameWidth;
	return calc; 
}

// Gets minimum Y of stage field
function GetClipMinY() { 
	let calc = GetStgFrameHeight - GetStgFrameHeight;
	return calc; 
} 

// Gets minimum Y of stage field
function GetClipMaxY() { 
	let calc = GetStgFrameHeight;
	return calc; 
} 

// Gets X position of boss
function GetEnemyX() { 
	let ex = ObjMove_GetX(bossObj);
	return ex;
}

// Gets Y position of boss
function GetEnemyY() { 
	let ey = ObjMove_GetY(bossObj);
	return ey;
}

// Quake cam 2D to use for certain boss effects.
task quakeCam2D(m,t) {
	let schudx = Get2DCameraX;
	let schudy = Get2DCameraY;

	loop(t) {
		Set2DCameraFocusX(rand(schudx-m, schudx+m));
		Set2DCameraFocusY(rand(schudy-m, schudy+m));
		yield;
	}

	Reset2DCamera;
}

// Quake cam 3D to use 3D stages
task quakeCam3D(m,t) {
	let oldCamX = GetCameraX;
	let oldCamY = GetCameraY;
	let oldCamZ = GetCameraZ;
	let azuSchud = GetCameraAzimuthAngle;
	let eleSchud = GetCameraElevationAngle;
	
	loop(t) {
		SetCameraFocusXYZ(rand(oldCamX-m, oldCamX+m), rand(oldCamY-m, oldCamX+m), rand(oldCamZ-m, oldCamX+m));
		SetCameraAzimuthAngle(rand(azuSchud-m, azuSchud+m));
		SetCameraElevationAngle(rand(eleSchud-m, eleSchud+m));
		yield;
	}

	SetCameraFocusXYZ(oldCamX, oldCamY, oldCamZ);
}

